I have an asymmetric RSA key pair stored in two separate files. I want to generate a new symmetric key and encrypt it with public RSA key in my postbuild.js
GULP script, so the user cannot access it. Then I want to send it to the C# server, where it would be decrypted and used.
I use the following JavaScript code in Node.js for encryption:
const generateAndEncryptKey = () => {
const symmetricKey = crypto.randomBytes(32);
const publicKey = fs.readFileSync("pubkey.pem", "utf8");
const encryptedSymmetricKey = crypto.publicEncrypt({
key: publicKey,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
oaepHash: "sha256",
}, Buffer.from(symmetricKey)).toString("base64");
return encryptedSymmetricKey;
}
The above code somehow works and generates a base64 string that I later send to the server. I'm not sure if this is the correct way to do this.
But I'm unable to find a way to decrypt this string in C#. I tried to use the BouncyCastle library and the following code:
public string DecryptKey(string encryptedKey) {
var privateKey = @"-----BEGIN RSA PRIVATE KEY-----
...shortened...
-----END RSA PRIVATE KEY-----";
var bytesToDecrypt = Convert.FromBase64String(encryptedKey);
var decryptEngine = new Pkcs1Encoding(new RsaEngine());
using (var txtreader = new StringReader(privateKey)) {
AsymmetricCipherKeyPair keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject();
decryptEngine.Init(false, keyPair.Private);
}
var decrypted = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length));
return decrypted;
}
But the ProcessBlock
method always throws an InvalidCipherTextException "unknown block type".
Can someone help me to find out what am I doing wrong or point me to another better way of achieving this?
Decryption with the C# code fails because in the NodeJS code OAEP/SHA256 is used as padding and in the C# code PKCS#1 v1.5 padding. For decryption to work, both paddings must be identical. The padding in the C# code can be adapted to that of the NodeJS code as follows:
var decryptEngine = new OaepEncoding(new RsaEngine(), new Sha256Digest());
Also, the decrypted key must not be UTF-8 decoded as this corrupts the data. Either it is returned as byte[]
, or if conversion to a string is desired, a suitable binary-to-text encoding such as Base64 or hex must be used.
With these changes decryption works in the C# code.