'use strict'; const common = require('../common'); if (!common.hasCrypto) common.skip('missing crypto'); const assert = require('assert'); const { ECDH, createSign, getCurves } = require('crypto'); // A valid private key for the secp256k1 curve. const cafebabeKey = 'cafebabe'.repeat(8); // Associated compressed and uncompressed public keys (points). const cafebabePubPtComp = '03672a31bfc59d3f04548ec9b7daeeba2f61814e8ccc40448045007f5479f693a3'; const cafebabePubPtUnComp = '04672a31bfc59d3f04548ec9b7daeeba2f61814e8ccc40448045007f5479f693a3' + '2e02c7f93d13dc2732b760ca377a5897b9dd41a1c1b29dc0442fdce6d0a04d1d'; // Invalid test: key argument is undefined. common.expectsError( () => ECDH.convertKey(), { code: 'ERR_INVALID_ARG_TYPE', type: TypeError, }); // Invalid test: curve argument is undefined. common.expectsError( () => ECDH.convertKey(cafebabePubPtComp), { code: 'ERR_INVALID_ARG_TYPE', type: TypeError, }); // Invalid test: curve argument is invalid. common.expectsError( () => ECDH.convertKey(cafebabePubPtComp, 'badcurve'), { type: TypeError, message: 'Invalid ECDH curve name' }); if (getCurves().includes('secp256k1')) { // Invalid test: format argument is undefined. common.expectsError( () => ECDH.convertKey(cafebabePubPtComp, 'secp256k1', 'hex', 'hex', 10), { code: 'ERR_CRYPTO_ECDH_INVALID_FORMAT', type: TypeError, message: 'Invalid ECDH format: 10' }); // Point formats. let uncompressed = ECDH.convertKey(cafebabePubPtComp, 'secp256k1', 'hex', 'buffer', 'uncompressed'); let compressed = ECDH.convertKey(cafebabePubPtComp, 'secp256k1', 'hex', 'buffer', 'compressed'); let hybrid = ECDH.convertKey(cafebabePubPtComp, 'secp256k1', 'hex', 'buffer', 'hybrid'); assert.strictEqual(uncompressed[0], 4); let firstByte = compressed[0]; assert(firstByte === 2 || firstByte === 3); firstByte = hybrid[0]; assert(firstByte === 6 || firstByte === 7); // Format conversion from hex to hex uncompressed = ECDH.convertKey(cafebabePubPtComp, 'secp256k1', 'hex', 'hex', 'uncompressed'); compressed = ECDH.convertKey(cafebabePubPtComp, 'secp256k1', 'hex', 'hex', 'compressed'); hybrid = ECDH.convertKey(cafebabePubPtComp, 'secp256k1', 'hex', 'hex', 'hybrid'); assert.strictEqual(uncompressed, cafebabePubPtUnComp); assert.strictEqual(compressed, cafebabePubPtComp); // Compare to getPublicKey. const ecdh1 = ECDH('secp256k1'); ecdh1.generateKeys(); ecdh1.setPrivateKey(cafebabeKey, 'hex'); assert.strictEqual(ecdh1.getPublicKey('hex', 'uncompressed'), uncompressed); assert.strictEqual(ecdh1.getPublicKey('hex', 'compressed'), compressed); assert.strictEqual(ecdh1.getPublicKey('hex', 'hybrid'), hybrid); } // See https://github.com/nodejs/node/issues/26133, failed ConvertKey // operations should not leave errors on OpenSSL's error stack because // that's observable by subsequent operations. { const privateKey = '-----BEGIN EC PRIVATE KEY-----\n' + 'MHcCAQEEIF+jnWY1D5kbVYDNvxxo/Y+ku2uJPDwS0r/VuPZQrjjVoAoGCCqGSM49\n' + 'AwEHoUQDQgAEurOxfSxmqIRYzJVagdZfMMSjRNNhB8i3mXyIMq704m2m52FdfKZ2\n' + 'pQhByd5eyj3lgZ7m7jbchtdgyOF8Io/1ng==\n' + '-----END EC PRIVATE KEY-----'; const sign = createSign('sha256').update('plaintext'); // TODO(bnoordhuis) This should really bubble up the specific OpenSSL error // rather than Node's generic error message. const badKey = 'f'.repeat(128); assert.throws( () => ECDH.convertKey(badKey, 'secp256k1', 'hex', 'hex', 'compressed'), /Failed to convert Buffer to EC_POINT/); // Next statement should not throw an exception. sign.sign(privateKey); }