diff --git a/Cargo.lock b/Cargo.lock index 4889bca67..03bfa95c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -191,6 +191,15 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -727,6 +736,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", + "sha1", "url", ] @@ -1316,6 +1326,7 @@ dependencies = [ "pkcs1", "pkcs8", "rand_core", + "sha2", "signature", "spki", "subtle", @@ -1579,6 +1590,28 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "signature" version = "2.2.0" diff --git a/Cargo.toml b/Cargo.toml index 0711159f3..dfe77d575 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,8 @@ atom_syndication = "0.12" ruma = { version = "0.9", features = ["events", "html"] } reqwest = "0.11" rand = "0.8.5" -rsa = "0.9.6" +rsa = { version = "0.9.6", features = ["sha2"] } base64ct = { version = "1.6.0", features = ["alloc"] } +sha1 = "0.10.6" [build-dependencies] napi-build = "2" diff --git a/src/tokens/mod.rs b/src/tokens/mod.rs index 60e42941f..533cf8665 100644 --- a/src/tokens/mod.rs +++ b/src/tokens/mod.rs @@ -5,7 +5,8 @@ use napi::bindgen_prelude::Buffer; use napi::Error; use rsa::pkcs1::DecodeRsaPrivateKey; use rsa::pkcs8::DecodePrivateKey; -use rsa::{Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey}; +use rsa::{Oaep, RsaPrivateKey, RsaPublicKey}; +use sha1::Sha1; static MAX_TOKEN_PART_SIZE: usize = 128; @@ -91,11 +92,12 @@ impl JsTokenEncryption { } fn decrypt_value(&self, value: String) -> Result { + let padding = Oaep::new::(); let raw_value = Base64::decode_vec(&value).map_err(DecryptError::Base64)?; let decrypted_value = self .inner .private_key - .decrypt(Pkcs1v15Encrypt, &raw_value) + .decrypt(padding, &raw_value) .map_err(DecryptError::Decryption)?; let utf8_value = String::from_utf8(decrypted_value).map_err(DecryptError::FromUtf8)?; Ok(utf8_value) @@ -106,11 +108,8 @@ impl JsTokenEncryption { let mut rng = rand::thread_rng(); let mut parts: Vec = Vec::new(); for part in input.into_bytes().chunks(MAX_TOKEN_PART_SIZE) { - match self - .inner - .public_key - .encrypt(&mut rng, Pkcs1v15Encrypt, part) - { + let padding = Oaep::new::(); + match self.inner.public_key.encrypt(&mut rng, padding, part) { Ok(encrypted) => { let b64 = Base64::encode_string(encrypted.as_slice()); parts.push(b64); diff --git a/tests/tokens/tokenencryption.spec.ts b/tests/tokens/tokenencryption.spec.ts index d57aec9cd..bf68e2d89 100644 --- a/tests/tokens/tokenencryption.spec.ts +++ b/tests/tokens/tokenencryption.spec.ts @@ -1,5 +1,5 @@ import { TokenEncryption } from "../../src/libRs"; -import { RSAKeyPairOptions, generateKeyPair } from "node:crypto"; +import { RSAKeyPairOptions, generateKeyPair, publicEncrypt } from "node:crypto"; import { expect } from "chai"; describe("TokenEncryption", () => { @@ -8,6 +8,18 @@ describe("TokenEncryption", () => { async function createTokenEncryption() { return new TokenEncryption(await keyPromise); } + + async function legacyEncryptFunction(token: string) { + const MAX_TOKEN_PART_SIZE = 128; + const tokenParts: string[] = []; + let tokenSource = token; + while (tokenSource && tokenSource.length > 0) { + const part = tokenSource.slice(0, MAX_TOKEN_PART_SIZE); + tokenSource = tokenSource.substring(MAX_TOKEN_PART_SIZE); + tokenParts.push(publicEncrypt(await keyPromise, Buffer.from(part)).toString("base64")); + } + return tokenParts; + } before('generate RSA key', () => { // Generate this once since it will take an age. @@ -66,4 +78,9 @@ describe("TokenEncryption", () => { const result = tokenEncryption.encrypt('hello world'); expect(result).to.have.lengthOf(1); }); + it('should be to decrypt a string from the old crypto implementation', async() => { + const legacyString = await legacyEncryptFunction('hello world'); + const tokenEncryption = await createTokenEncryption(); + expect(tokenEncryption.decrypt(legacyString)).to.equal('hello world'); + }); });