I tried to decrypt a private AES encrypted RSA key and re-encrypt it with the same AES algorithm, but a different password. I used this method to create an RSA keypair:
crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
publicKeyEncoding: {
type: 'pkcs1',
format: 'pem',
},
privateKeyEncoding: {
type: 'pkcs1',
format: 'pem',
cipher: 'aes-256-cbc',
passphrase: secret
}
});
This is an example private key generated by this method:
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,B25B895829F89685570676A6C53B4E9F
xb/IOI6S1rXqxo N1Aba1M4xCqDG8u5OGBiF/zvDnKzZ/rV7/TTVIhQouZKdq 26
XMQDWGlRx1YQqWajJUZzbvixdWR3pacRpR1Mli1WPIU3rtWwOlYVgL3TqtN19IK
NEMMrGpbnUQmXM1M5ZExRrKYw9qPI3VJwmCuE0j19 FoYZJT/5v861RcNs18v8hz
[...]
-----END RSA PRIVATE KEY-----
I want to decrypt the private key that was encrypted using aes-256-cbc
and a password and re-encrypt it using another password and the same AES algorithm.
I have already tried the following method but I did not manage to get it working:
const decryptRsaPrivateKey = (privateKey, oldPassword, newPassword) => {
const keyLines = privateKey.split('\n');
// Extract the DEK-Info line
var dekInfoLine = keyLines[2]
// Extract the encryption algorithm and IV from the DEK-Info line
const [, algorithm, ivHex] = dekInfoLine.match(/DEK-Info: (. ),(. )/);
const iv = Buffer.from(ivHex, 'hex');
// Remove the DEK-Info line and the header/footer lines
keyLines.splice(2, 1);
keyLines.splice(0, 1);
keyLines.splice(-1, 1);
// Join the remaining lines and base64-decode the key
const encodedKey = keyLines.join('');
const decipher = crypto.createDecipheriv(algorithm, Buffer.from(oldPassword), iv);
let decryptedKey = decipher.update(encodedKey, 'base64', 'binary');
decryptedKey = decipher.final('binary');
// Encrypt the key with the new password
const cipher = crypto.createCipheriv(algorithm, Buffer.from(newPassword), iv);
let encryptedKey = cipher.update(decryptedKey, 'binary', 'base64');
encryptedKey = cipher.final('base64');
// Add the DEK-Info line and the header/footer lines
const dekInfo = `DEK-Info: ${algorithm},${iv.toString('hex')}`;
return `-----BEGIN RSA PRIVATE KEY-----\n${dekInfo}\n\n${encryptedKey}\n-----END RSA PRIVATE KEY-----`;
}
This was the error I got from this method:
node:internal/crypto/cipher:116
this[kHandle].initiv(cipher, credential, iv, authTagLength);
^
RangeError: Invalid key length
at Decipheriv.createCipherBase (node:internal/crypto/cipher:116:19)
at Decipheriv.createCipherWithIV (node:internal/crypto/cipher:135:3)
at new Decipheriv (node:internal/crypto/cipher:289:3)
at Object.createDecipheriv (node:crypto:149:10)
at Module._compile (node:internal/modules/cjs/loader:1159:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1213:10)
at Module.load (node:internal/modules/cjs/loader:1037:32)
at Module._load (node:internal/modules/cjs/loader:878:12) {
code: 'ERR_CRYPTO_INVALID_KEYLEN'
}
I also read the documentation from node, but I found nothing that could help me.
Thank you in advance.
CodePudding user response:
A key is usually imported with crypto.createPrivateKey()
. This is also true for an encrypted key, for which the password must be specified.
The export is possible with keyObject.export()
. If the key is to be encrypted, the password and algorithm must be specified.
If a password of an existing encrypted key is to be changed, the procedure is analogous: Import with the old password, export with the new password.
Example:
var crypto = require('crypto');
// Generate keypair
var secret ='secret';
var keyPair = crypto.generateKeyPairSync(
'rsa',
{
modulusLength: 2048,
publicKeyEncoding: {type: 'pkcs1', format: 'pem'},
privateKeyEncoding: {type: 'pkcs1', format: 'pem', cipher: 'aes-256-cbc', passphrase: secret}
}
);
var encPkcs1Pem = keyPair.privateKey;
console.log(encPkcs1Pem);
// Import
var privateKey = crypto.createPrivateKey({key: encPkcs1Pem, type: 'pkcs1', format: 'pem', passphrase: secret});
//var privateKey = crypto.createPrivateKey({key: encPkcs1Pem, passphrase: secret}); // works also
// Export with new passphrase
var secret_2 ='another secret';
var encPkcs1Pem_2 = privateKey.export({type: 'pkcs1', format: 'pem', cipher: 'aes-256-cbc', passphrase: secret_2});
console.log(encPkcs1Pem_2);