🐛 Decryption error - privateDecrypt
What's happening?
I'm trying to decrypt a string encrypted with RSA-PKCS1, and i'm running into this same nondescript error.
[Error: Failed Cipher Operation - privateDecrypt]
I've narrowed it down to two possibilities: Incorrect keypair data formatted incorrectly
My current process being halted is:
- generate RSA keypair via OpenSSL library on rust server ✅
- encrypt data with public key and base58 encode bytes ✅
- decode data on client ✅
- decrypt data on client with cached private key from server ❌
is there any reason to assume the server is generating an improper keypair? I have verified the key itself is correct.
Reproducible Code
// handler.rs
for member in members {
let mut user = users::get_user(&member)?;
let pemkey = match base58_public_key_to_pem(&user.id) {
Ok(pemkey) => {
println!("{}", pemkey);
pemkey
},
Err(e) => {
println!("Key conversion error: {:?}", e);
return Err(warp::reject::custom(InternalError::Unknown));
}
};
let key = match encrypt_symetric_key(&pemkey, &key) {
Ok(key) => key,
Err(e) => {
println!("Encryption error: {:?}", e);
return Err(warp::reject::custom(InternalError::Unknown));
}
};
let _ = chats::add_member(
&ctx,
user.clone(),
key
)?;
user.chats.push(
bs58::encode(encrypt_data(
&base58_public_key_to_pem(&user.id).expect("Failed to convert key"),
ctx.id.as_bytes()
).expect("Failed to encrypt chat id")).into_string()
);
let _ = users::update_user(user)?;
}
// rsa.ts
export function decryptMessageWithPrivateKey(encryptedMessage: Buffer, privateKeyPem: string): string {
const decryptedMessage = QuickCrypto.privateDecrypt(
{
key: privateKeyPem,
padding: QuickCrypto.constants.RSA_PKCS1_PADDING,
},
encryptedMessage
);
return decryptedMessage.toString('utf8');
}
// webserver.ts
this.retrieveData({ctx: decryptMessageWithPrivateKey(Buffer.from(base58.decode(chat)), cache.user.private_key)}).then((r: ChatResponse) => {
this.cache.chats = [...this.cache.chats, {
id: chat,
...r,
messages: [],
key: deriveChatSymKeyFromEncryptedKeys(r.symetric_keys, cache.user.private_key)
}]
})
Relevant log output
ERROR [Error: Failed Cipher Operation - privateDecrypt]
Device
iPhone 16 Pro iOS 18
QuickCrypto Version
0.7.5
Can you reproduce this issue in the QuickCrypto Example app?
1.0.0-beta3 does not implement privateDecrypt
Additional information
- [X] I am using Expo
- [X] I have read the Troubleshooting Guide
- [X] I agree to follow this project's Code of Conduct
- [X] I searched for similar issues in this repository and found none.
- 😦 It looks to me like
privateDecrypt()is not implemented in the implementation guide. - 😄 The code looks to be in place here and here for this to work. Looks promising, but
- 😦 The code only "says"
getPublicCipherFieldDefinition - 😦 The tests for
privateDecrypt()fail
Someone needs to take a dive into the C++ implementation, which is a few years old, and fix things up. Also, more tests need to be ported from the node.js codebase.
Thanks @boorad, do you have any recommendations of what to do in the mean time? All other react-native libraries for RSA are immature and/or poorly documented. Many of which haven't been touched in years.
@Morgandri1 can you take the dive into C++ (using XCode) to see what's going on? Use this PR & branch, and the example app. Set some breakpoints in XCode in the C++ files. I've commented out all but the first test in PublicCipherTests.ts. Weird thing is that it passes sometimes :eyes:
To be perfectly honest, I have no idea where to start on that. not sure how to open the lib code in xcode before it compiles
@boorad I tried diving into the c++ and couldn't find the privateDecrypt or publicEncrypt functions. do you know where i should start?
I would like to add on this:
We would love to migrate to the new architecture, however we need to decrypt an RSA string that we receive from our API. e Currently we use the privateDecrypt of the 0.7 branch, but I want to humbly request if this could be added to the new 1.X rewrite. As @Morgandri1 said, all other libraries look unmaintained and badly documented, this library stands on top.
@Morgandri1
What is in encrypt_symetric_key()?
I think we need keys and data from the Rust side to test on the RN side, because this test passes:
it('#494 decryption error', () => {
const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 512,
publicKeyEncoding: {
type: 'pkcs1',
format: 'pem',
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
},
});
const encryptedMessage = crypto.publicEncrypt(
{
key: publicKey,
padding: crypto.constants.RSA_PKCS1_PADDING,
},
Buffer.from(message, 'utf8')
);
const decryptedMessage = crypto.privateDecrypt(
{
key: privateKey,
padding: crypto.constants.RSA_PKCS1_PADDING,
},
encryptedMessage
);
expect(decryptedMessage.toString('utf8')).to.equal(message);
})
To be honest, I have no idea. I believe, though, that it's the AES encrypt function.