1'use strict'; 2const common = require('../common'); 3if (!common.hasCrypto) 4 common.skip('missing crypto'); 5 6const assert = require('assert'); 7const crypto = require('crypto'); 8 9const constants = crypto.constants; 10 11const fixtures = require('../common/fixtures'); 12 13// Test certificates 14const certPem = fixtures.readKey('rsa_cert.crt'); 15const keyPem = fixtures.readKey('rsa_private.pem'); 16const rsaKeySize = 2048; 17const rsaPubPem = fixtures.readKey('rsa_public.pem', 'ascii'); 18const rsaKeyPem = fixtures.readKey('rsa_private.pem', 'ascii'); 19const rsaKeyPemEncrypted = fixtures.readKey('rsa_private_encrypted.pem', 20 'ascii'); 21const dsaPubPem = fixtures.readKey('dsa_public.pem', 'ascii'); 22const dsaKeyPem = fixtures.readKey('dsa_private.pem', 'ascii'); 23const dsaKeyPemEncrypted = fixtures.readKey('dsa_private_encrypted.pem', 24 'ascii'); 25const rsaPkcs8KeyPem = fixtures.readKey('rsa_private_pkcs8.pem'); 26const dsaPkcs8KeyPem = fixtures.readKey('dsa_private_pkcs8.pem'); 27 28const ec = new TextEncoder(); 29 30const openssl1DecryptError = { 31 message: 'error:06065064:digital envelope routines:EVP_DecryptFinal_ex:' + 32 'bad decrypt', 33 code: 'ERR_OSSL_EVP_BAD_DECRYPT', 34 reason: 'bad decrypt', 35 function: 'EVP_DecryptFinal_ex', 36 library: 'digital envelope routines', 37}; 38 39const decryptError = common.hasOpenSSL3 ? 40 { message: 'error:1C800064:Provider routines::bad decrypt' } : 41 openssl1DecryptError; 42 43const decryptPrivateKeyError = common.hasOpenSSL3 ? { 44 message: 'error:1C800064:Provider routines::bad decrypt', 45} : openssl1DecryptError; 46 47function getBufferCopy(buf) { 48 return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength); 49} 50 51// Test RSA encryption/decryption 52{ 53 const input = 'I AM THE WALRUS'; 54 const bufferToEncrypt = Buffer.from(input); 55 const bufferPassword = Buffer.from('password'); 56 57 let encryptedBuffer = crypto.publicEncrypt(rsaPubPem, bufferToEncrypt); 58 59 // Test other input types 60 let otherEncrypted; 61 { 62 const ab = getBufferCopy(ec.encode(rsaPubPem)); 63 const ab2enc = getBufferCopy(bufferToEncrypt); 64 65 crypto.publicEncrypt(ab, ab2enc); 66 crypto.publicEncrypt(new Uint8Array(ab), new Uint8Array(ab2enc)); 67 crypto.publicEncrypt(new DataView(ab), new DataView(ab2enc)); 68 otherEncrypted = crypto.publicEncrypt({ 69 key: Buffer.from(ab).toString('hex'), 70 encoding: 'hex' 71 }, Buffer.from(ab2enc).toString('hex')); 72 } 73 74 let decryptedBuffer = crypto.privateDecrypt(rsaKeyPem, encryptedBuffer); 75 const otherDecrypted = crypto.privateDecrypt(rsaKeyPem, otherEncrypted); 76 assert.strictEqual(decryptedBuffer.toString(), input); 77 assert.strictEqual(otherDecrypted.toString(), input); 78 79 decryptedBuffer = crypto.privateDecrypt(rsaPkcs8KeyPem, encryptedBuffer); 80 assert.strictEqual(decryptedBuffer.toString(), input); 81 82 let decryptedBufferWithPassword = crypto.privateDecrypt({ 83 key: rsaKeyPemEncrypted, 84 passphrase: 'password' 85 }, encryptedBuffer); 86 87 const otherDecryptedBufferWithPassword = crypto.privateDecrypt({ 88 key: rsaKeyPemEncrypted, 89 passphrase: ec.encode('password') 90 }, encryptedBuffer); 91 92 assert.strictEqual( 93 otherDecryptedBufferWithPassword.toString(), 94 decryptedBufferWithPassword.toString()); 95 96 decryptedBufferWithPassword = crypto.privateDecrypt({ 97 key: rsaKeyPemEncrypted, 98 passphrase: 'password' 99 }, encryptedBuffer); 100 101 assert.strictEqual(decryptedBufferWithPassword.toString(), input); 102 103 encryptedBuffer = crypto.publicEncrypt({ 104 key: rsaKeyPemEncrypted, 105 passphrase: 'password' 106 }, bufferToEncrypt); 107 108 decryptedBufferWithPassword = crypto.privateDecrypt({ 109 key: rsaKeyPemEncrypted, 110 passphrase: 'password' 111 }, encryptedBuffer); 112 assert.strictEqual(decryptedBufferWithPassword.toString(), input); 113 114 encryptedBuffer = crypto.privateEncrypt({ 115 key: rsaKeyPemEncrypted, 116 passphrase: bufferPassword 117 }, bufferToEncrypt); 118 119 decryptedBufferWithPassword = crypto.publicDecrypt({ 120 key: rsaKeyPemEncrypted, 121 passphrase: bufferPassword 122 }, encryptedBuffer); 123 assert.strictEqual(decryptedBufferWithPassword.toString(), input); 124 125 // Now with explicit RSA_PKCS1_PADDING. 126 encryptedBuffer = crypto.privateEncrypt({ 127 padding: crypto.constants.RSA_PKCS1_PADDING, 128 key: rsaKeyPemEncrypted, 129 passphrase: bufferPassword 130 }, bufferToEncrypt); 131 132 decryptedBufferWithPassword = crypto.publicDecrypt({ 133 padding: crypto.constants.RSA_PKCS1_PADDING, 134 key: rsaKeyPemEncrypted, 135 passphrase: bufferPassword 136 }, encryptedBuffer); 137 assert.strictEqual(decryptedBufferWithPassword.toString(), input); 138 139 // Omitting padding should be okay because RSA_PKCS1_PADDING is the default. 140 decryptedBufferWithPassword = crypto.publicDecrypt({ 141 key: rsaKeyPemEncrypted, 142 passphrase: bufferPassword 143 }, encryptedBuffer); 144 assert.strictEqual(decryptedBufferWithPassword.toString(), input); 145 146 // Now with RSA_NO_PADDING. Plaintext needs to match key size. 147 // OpenSSL 3.x has a rsa_check_padding that will cause an error if 148 // RSA_NO_PADDING is used. 149 if (!common.hasOpenSSL3) { 150 { 151 const plaintext = 'x'.repeat(rsaKeySize / 8); 152 encryptedBuffer = crypto.privateEncrypt({ 153 padding: crypto.constants.RSA_NO_PADDING, 154 key: rsaKeyPemEncrypted, 155 passphrase: bufferPassword 156 }, Buffer.from(plaintext)); 157 158 decryptedBufferWithPassword = crypto.publicDecrypt({ 159 padding: crypto.constants.RSA_NO_PADDING, 160 key: rsaKeyPemEncrypted, 161 passphrase: bufferPassword 162 }, encryptedBuffer); 163 assert.strictEqual(decryptedBufferWithPassword.toString(), plaintext); 164 } 165 } 166 167 encryptedBuffer = crypto.publicEncrypt(certPem, bufferToEncrypt); 168 169 decryptedBuffer = crypto.privateDecrypt(keyPem, encryptedBuffer); 170 assert.strictEqual(decryptedBuffer.toString(), input); 171 172 encryptedBuffer = crypto.publicEncrypt(keyPem, bufferToEncrypt); 173 174 decryptedBuffer = crypto.privateDecrypt(keyPem, encryptedBuffer); 175 assert.strictEqual(decryptedBuffer.toString(), input); 176 177 encryptedBuffer = crypto.privateEncrypt(keyPem, bufferToEncrypt); 178 179 decryptedBuffer = crypto.publicDecrypt(keyPem, encryptedBuffer); 180 assert.strictEqual(decryptedBuffer.toString(), input); 181 182 assert.throws(() => { 183 crypto.privateDecrypt({ 184 key: rsaKeyPemEncrypted, 185 passphrase: 'wrong' 186 }, bufferToEncrypt); 187 }, decryptError); 188 189 assert.throws(() => { 190 crypto.publicEncrypt({ 191 key: rsaKeyPemEncrypted, 192 passphrase: 'wrong' 193 }, encryptedBuffer); 194 }, decryptError); 195 196 encryptedBuffer = crypto.privateEncrypt({ 197 key: rsaKeyPemEncrypted, 198 passphrase: Buffer.from('password') 199 }, bufferToEncrypt); 200 201 assert.throws(() => { 202 crypto.publicDecrypt({ 203 key: rsaKeyPemEncrypted, 204 passphrase: Buffer.from('wrong') 205 }, encryptedBuffer); 206 }, decryptError); 207} 208 209function test_rsa(padding, encryptOaepHash, decryptOaepHash) { 210 const size = (padding === 'RSA_NO_PADDING') ? rsaKeySize / 8 : 32; 211 const input = Buffer.allocUnsafe(size); 212 for (let i = 0; i < input.length; i++) 213 input[i] = (i * 7 + 11) & 0xff; 214 const bufferToEncrypt = Buffer.from(input); 215 216 padding = constants[padding]; 217 218 const encryptedBuffer = crypto.publicEncrypt({ 219 key: rsaPubPem, 220 padding: padding, 221 oaepHash: encryptOaepHash 222 }, bufferToEncrypt); 223 224 let decryptedBuffer = crypto.privateDecrypt({ 225 key: rsaKeyPem, 226 padding: padding, 227 oaepHash: decryptOaepHash 228 }, encryptedBuffer); 229 assert.deepStrictEqual(decryptedBuffer, input); 230 231 decryptedBuffer = crypto.privateDecrypt({ 232 key: rsaPkcs8KeyPem, 233 padding: padding, 234 oaepHash: decryptOaepHash 235 }, encryptedBuffer); 236 assert.deepStrictEqual(decryptedBuffer, input); 237} 238 239test_rsa('RSA_NO_PADDING'); 240test_rsa('RSA_PKCS1_PADDING'); 241test_rsa('RSA_PKCS1_OAEP_PADDING'); 242 243// Test OAEP with different hash functions. 244test_rsa('RSA_PKCS1_OAEP_PADDING', undefined, 'sha1'); 245test_rsa('RSA_PKCS1_OAEP_PADDING', 'sha1', undefined); 246test_rsa('RSA_PKCS1_OAEP_PADDING', 'sha256', 'sha256'); 247test_rsa('RSA_PKCS1_OAEP_PADDING', 'sha512', 'sha512'); 248assert.throws(() => { 249 test_rsa('RSA_PKCS1_OAEP_PADDING', 'sha256', 'sha512'); 250}, { 251 code: 'ERR_OSSL_RSA_OAEP_DECODING_ERROR' 252}); 253 254// The following RSA-OAEP test cases were created using the WebCrypto API to 255// ensure compatibility when using non-SHA1 hash functions. 256{ 257 const { decryptionTests } = 258 JSON.parse(fixtures.readSync('rsa-oaep-test-vectors.js', 'utf8')); 259 260 for (const { ct, oaepHash, oaepLabel } of decryptionTests) { 261 const label = oaepLabel ? Buffer.from(oaepLabel, 'hex') : undefined; 262 const copiedLabel = oaepLabel ? getBufferCopy(label) : undefined; 263 264 const decrypted = crypto.privateDecrypt({ 265 key: rsaPkcs8KeyPem, 266 oaepHash, 267 oaepLabel: oaepLabel ? label : undefined 268 }, Buffer.from(ct, 'hex')); 269 270 assert.strictEqual(decrypted.toString('utf8'), 'Hello Node.js'); 271 272 const otherDecrypted = crypto.privateDecrypt({ 273 key: rsaPkcs8KeyPem, 274 oaepHash, 275 oaepLabel: copiedLabel 276 }, Buffer.from(ct, 'hex')); 277 278 assert.strictEqual(otherDecrypted.toString('utf8'), 'Hello Node.js'); 279 } 280} 281 282// Test invalid oaepHash and oaepLabel options. 283for (const fn of [crypto.publicEncrypt, crypto.privateDecrypt]) { 284 assert.throws(() => { 285 fn({ 286 key: rsaPubPem, 287 oaepHash: 'Hello world' 288 }, Buffer.alloc(10)); 289 }, { 290 code: 'ERR_OSSL_EVP_INVALID_DIGEST' 291 }); 292 293 for (const oaepHash of [0, false, null, Symbol(), () => {}]) { 294 assert.throws(() => { 295 fn({ 296 key: rsaPubPem, 297 oaepHash 298 }, Buffer.alloc(10)); 299 }, { 300 code: 'ERR_INVALID_ARG_TYPE' 301 }); 302 } 303 304 for (const oaepLabel of [0, false, null, Symbol(), () => {}, {}]) { 305 assert.throws(() => { 306 fn({ 307 key: rsaPubPem, 308 oaepLabel 309 }, Buffer.alloc(10)); 310 }, { 311 code: 'ERR_INVALID_ARG_TYPE' 312 }); 313 } 314} 315 316// Test RSA key signing/verification 317let rsaSign = crypto.createSign('SHA1'); 318let rsaVerify = crypto.createVerify('SHA1'); 319assert.ok(rsaSign); 320assert.ok(rsaVerify); 321 322const expectedSignature = fixtures.readKey( 323 'rsa_public_sha1_signature_signedby_rsa_private_pkcs8.sha1', 324 'hex' 325); 326 327rsaSign.update(rsaPubPem); 328let rsaSignature = rsaSign.sign(rsaKeyPem, 'hex'); 329assert.strictEqual(rsaSignature, expectedSignature); 330 331rsaVerify.update(rsaPubPem); 332assert.strictEqual(rsaVerify.verify(rsaPubPem, rsaSignature, 'hex'), true); 333 334// Test RSA PKCS#8 key signing/verification 335rsaSign = crypto.createSign('SHA1'); 336rsaSign.update(rsaPubPem); 337rsaSignature = rsaSign.sign(rsaPkcs8KeyPem, 'hex'); 338assert.strictEqual(rsaSignature, expectedSignature); 339 340rsaVerify = crypto.createVerify('SHA1'); 341rsaVerify.update(rsaPubPem); 342assert.strictEqual(rsaVerify.verify(rsaPubPem, rsaSignature, 'hex'), true); 343 344// Test RSA key signing/verification with encrypted key 345rsaSign = crypto.createSign('SHA1'); 346rsaSign.update(rsaPubPem); 347const signOptions = { key: rsaKeyPemEncrypted, passphrase: 'password' }; 348rsaSignature = rsaSign.sign(signOptions, 'hex'); 349assert.strictEqual(rsaSignature, expectedSignature); 350 351rsaVerify = crypto.createVerify('SHA1'); 352rsaVerify.update(rsaPubPem); 353assert.strictEqual(rsaVerify.verify(rsaPubPem, rsaSignature, 'hex'), true); 354 355rsaSign = crypto.createSign('SHA1'); 356rsaSign.update(rsaPubPem); 357assert.throws(() => { 358 const signOptions = { key: rsaKeyPemEncrypted, passphrase: 'wrong' }; 359 rsaSign.sign(signOptions, 'hex'); 360}, decryptPrivateKeyError); 361 362// 363// Test RSA signing and verification 364// 365{ 366 const privateKey = fixtures.readKey('rsa_private_b.pem'); 367 const publicKey = fixtures.readKey('rsa_public_b.pem'); 368 369 const input = 'I AM THE WALRUS'; 370 371 const signature = fixtures.readKey( 372 'I_AM_THE_WALRUS_sha256_signature_signedby_rsa_private_b.sha256', 373 'hex' 374 ); 375 376 const sign = crypto.createSign('SHA256'); 377 sign.update(input); 378 379 const output = sign.sign(privateKey, 'hex'); 380 assert.strictEqual(output, signature); 381 382 const verify = crypto.createVerify('SHA256'); 383 verify.update(input); 384 385 assert.strictEqual(verify.verify(publicKey, signature, 'hex'), true); 386 387 // Test the legacy signature algorithm name. 388 const sign2 = crypto.createSign('RSA-SHA256'); 389 sign2.update(input); 390 391 const output2 = sign2.sign(privateKey, 'hex'); 392 assert.strictEqual(output2, signature); 393 394 const verify2 = crypto.createVerify('SHA256'); 395 verify2.update(input); 396 397 assert.strictEqual(verify2.verify(publicKey, signature, 'hex'), true); 398} 399 400 401// 402// Test DSA signing and verification 403// 404{ 405 const input = 'I AM THE WALRUS'; 406 407 // DSA signatures vary across runs so there is no static string to verify 408 // against. 409 const sign = crypto.createSign('SHA1'); 410 sign.update(input); 411 const signature = sign.sign(dsaKeyPem, 'hex'); 412 413 const verify = crypto.createVerify('SHA1'); 414 verify.update(input); 415 416 assert.strictEqual(verify.verify(dsaPubPem, signature, 'hex'), true); 417 418 // Test the legacy 'DSS1' name. 419 const sign2 = crypto.createSign('DSS1'); 420 sign2.update(input); 421 const signature2 = sign2.sign(dsaKeyPem, 'hex'); 422 423 const verify2 = crypto.createVerify('DSS1'); 424 verify2.update(input); 425 426 assert.strictEqual(verify2.verify(dsaPubPem, signature2, 'hex'), true); 427} 428 429 430// 431// Test DSA signing and verification with PKCS#8 private key 432// 433{ 434 const input = 'I AM THE WALRUS'; 435 436 // DSA signatures vary across runs so there is no static string to verify 437 // against. 438 const sign = crypto.createSign('SHA1'); 439 sign.update(input); 440 const signature = sign.sign(dsaPkcs8KeyPem, 'hex'); 441 442 const verify = crypto.createVerify('SHA1'); 443 verify.update(input); 444 445 assert.strictEqual(verify.verify(dsaPubPem, signature, 'hex'), true); 446} 447 448 449// 450// Test DSA signing and verification with encrypted key 451// 452const input = 'I AM THE WALRUS'; 453 454{ 455 const sign = crypto.createSign('SHA1'); 456 sign.update(input); 457 assert.throws(() => { 458 sign.sign({ key: dsaKeyPemEncrypted, passphrase: 'wrong' }, 'hex'); 459 }, decryptPrivateKeyError); 460} 461 462{ 463 // DSA signatures vary across runs so there is no static string to verify 464 // against. 465 const sign = crypto.createSign('SHA1'); 466 sign.update(input); 467 const signOptions = { key: dsaKeyPemEncrypted, passphrase: 'password' }; 468 const signature = sign.sign(signOptions, 'hex'); 469 470 const verify = crypto.createVerify('SHA1'); 471 verify.update(input); 472 473 assert.strictEqual(verify.verify(dsaPubPem, signature, 'hex'), true); 474} 475