|
1 | 1 | 'use strict';
|
2 |
| -var common = require('../common'); |
3 |
| -var assert = require('assert'); |
4 |
| -var constants = require('constants'); |
| 2 | +const common = require('../common'); |
| 3 | +const assert = require('assert'); |
| 4 | +const constants = require('constants'); |
5 | 5 |
|
6 | 6 | if (!common.hasCrypto) {
|
7 | 7 | console.log('1..0 # Skipped: missing crypto');
|
8 | 8 | return;
|
9 | 9 | }
|
10 |
| -var crypto = require('crypto'); |
| 10 | +const crypto = require('crypto'); |
11 | 11 |
|
12 | 12 | // Test Diffie-Hellman with two parties sharing a secret,
|
13 | 13 | // using various encodings as we go along
|
@@ -150,36 +150,110 @@ assert.equal(bad_dh.verifyError, constants.DH_NOT_SUITABLE_GENERATOR);
|
150 | 150 |
|
151 | 151 |
|
152 | 152 | // Test ECDH
|
153 |
| -var ecdh1 = crypto.createECDH('prime256v1'); |
154 |
| -var ecdh2 = crypto.createECDH('prime256v1'); |
155 |
| -var key1 = ecdh1.generateKeys(); |
156 |
| -var key2 = ecdh2.generateKeys('hex'); |
157 |
| -var secret1 = ecdh1.computeSecret(key2, 'hex', 'base64'); |
158 |
| -var secret2 = ecdh2.computeSecret(key1, 'binary', 'buffer'); |
| 153 | +const ecdh1 = crypto.createECDH('prime256v1'); |
| 154 | +const ecdh2 = crypto.createECDH('prime256v1'); |
| 155 | +key1 = ecdh1.generateKeys(); |
| 156 | +key2 = ecdh2.generateKeys('hex'); |
| 157 | +secret1 = ecdh1.computeSecret(key2, 'hex', 'base64'); |
| 158 | +secret2 = ecdh2.computeSecret(key1, 'binary', 'buffer'); |
159 | 159 |
|
160 | 160 | assert.equal(secret1, secret2.toString('base64'));
|
161 | 161 |
|
162 | 162 | // Point formats
|
163 | 163 | assert.equal(ecdh1.getPublicKey('buffer', 'uncompressed')[0], 4);
|
164 |
| -var firstByte = ecdh1.getPublicKey('buffer', 'compressed')[0]; |
| 164 | +let firstByte = ecdh1.getPublicKey('buffer', 'compressed')[0]; |
165 | 165 | assert(firstByte === 2 || firstByte === 3);
|
166 |
| -var firstByte = ecdh1.getPublicKey('buffer', 'hybrid')[0]; |
| 166 | +firstByte = ecdh1.getPublicKey('buffer', 'hybrid')[0]; |
167 | 167 | assert(firstByte === 6 || firstByte === 7);
|
168 | 168 |
|
169 | 169 | // ECDH should check that point is on curve
|
170 |
| -var ecdh3 = crypto.createECDH('secp256k1'); |
171 |
| -var key3 = ecdh3.generateKeys(); |
| 170 | +const ecdh3 = crypto.createECDH('secp256k1'); |
| 171 | +const key3 = ecdh3.generateKeys(); |
172 | 172 |
|
173 | 173 | assert.throws(function() {
|
174 |
| - var secret3 = ecdh2.computeSecret(key3, 'binary', 'buffer'); |
| 174 | + ecdh2.computeSecret(key3, 'binary', 'buffer'); |
175 | 175 | });
|
176 | 176 |
|
177 | 177 | // ECDH should allow .setPrivateKey()/.setPublicKey()
|
178 |
| -var ecdh4 = crypto.createECDH('prime256v1'); |
| 178 | +const ecdh4 = crypto.createECDH('prime256v1'); |
179 | 179 |
|
180 | 180 | ecdh4.setPrivateKey(ecdh1.getPrivateKey());
|
181 | 181 | ecdh4.setPublicKey(ecdh1.getPublicKey());
|
182 | 182 |
|
183 | 183 | assert.throws(function() {
|
184 | 184 | ecdh4.setPublicKey(ecdh3.getPublicKey());
|
| 185 | +}, /Failed to convert Buffer to EC_POINT/); |
| 186 | + |
| 187 | +// Verify that we can use ECDH without having to use newly generated keys. |
| 188 | +const ecdh5 = crypto.createECDH('secp256k1'); |
| 189 | + |
| 190 | +// Verify errors are thrown when retrieving keys from an uninitialized object. |
| 191 | +assert.throws(function() { |
| 192 | + ecdh5.getPublicKey(); |
| 193 | +}, /Failed to get ECDH public key/); |
| 194 | +assert.throws(function() { |
| 195 | + ecdh5.getPrivateKey(); |
| 196 | +}, /Failed to get ECDH private key/); |
| 197 | + |
| 198 | +// A valid private key for the secp256k1 curve. |
| 199 | +const cafebabeKey = 'cafebabe'.repeat(8); |
| 200 | +// Associated compressed and uncompressed public keys (points). |
| 201 | +const cafebabePubPtComp = |
| 202 | +'03672a31bfc59d3f04548ec9b7daeeba2f61814e8ccc40448045007f5479f693a3'; |
| 203 | +const cafebabePubPtUnComp = |
| 204 | +'04672a31bfc59d3f04548ec9b7daeeba2f61814e8ccc40448045007f5479f693a3' + |
| 205 | +'2e02c7f93d13dc2732b760ca377a5897b9dd41a1c1b29dc0442fdce6d0a04d1d'; |
| 206 | +ecdh5.setPrivateKey(cafebabeKey, 'hex'); |
| 207 | +assert.equal(ecdh5.getPrivateKey('hex'), cafebabeKey); |
| 208 | +// Show that the public point (key) is generated while setting the private key. |
| 209 | +assert.equal(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp); |
| 210 | + |
| 211 | +// Compressed and uncompressed public points/keys for other party's private key |
| 212 | +// 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF |
| 213 | +const peerPubPtComp = |
| 214 | +'02c6b754b20826eb925e052ee2c25285b162b51fdca732bcf67e39d647fb6830ae'; |
| 215 | +const peerPubPtUnComp = |
| 216 | +'04c6b754b20826eb925e052ee2c25285b162b51fdca732bcf67e39d647fb6830ae' + |
| 217 | +'b651944a574a362082a77e3f2b5d9223eb54d7f2f76846522bf75f3bedb8178e'; |
| 218 | + |
| 219 | +const sharedSecret = |
| 220 | +'1da220b5329bbe8bfd19ceef5a5898593f411a6f12ea40f2a8eead9a5cf59970'; |
| 221 | + |
| 222 | +assert.equal(ecdh5.computeSecret(peerPubPtComp, 'hex', 'hex'), sharedSecret); |
| 223 | +assert.equal(ecdh5.computeSecret(peerPubPtUnComp, 'hex', 'hex'), sharedSecret); |
| 224 | + |
| 225 | +// Verify that we still have the same key pair as before the computation. |
| 226 | +assert.equal(ecdh5.getPrivateKey('hex'), cafebabeKey); |
| 227 | +assert.equal(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp); |
| 228 | + |
| 229 | +// Verify setting and getting compressed and non-compressed serializations. |
| 230 | +ecdh5.setPublicKey(cafebabePubPtComp, 'hex'); |
| 231 | +assert.equal(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp); |
| 232 | +assert.equal(ecdh5.getPublicKey('hex', 'compressed'), cafebabePubPtComp); |
| 233 | +ecdh5.setPublicKey(cafebabePubPtUnComp, 'hex'); |
| 234 | +assert.equal(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp); |
| 235 | +assert.equal(ecdh5.getPublicKey('hex', 'compressed'), cafebabePubPtComp); |
| 236 | + |
| 237 | +// Show why allowing the public key to be set on this type does not make sense. |
| 238 | +ecdh5.setPublicKey(peerPubPtComp, 'hex'); |
| 239 | +assert.equal(ecdh5.getPublicKey('hex'), peerPubPtUnComp); |
| 240 | +assert.throws(function() { |
| 241 | + // Error because the public key does not match the private key anymore. |
| 242 | + ecdh5.computeSecret(peerPubPtComp, 'hex', 'hex'); |
| 243 | +}, /Invalid key pair/); |
| 244 | + |
| 245 | +// Set to a valid key to show that later attempts to set an invalid key are |
| 246 | +// rejected. |
| 247 | +ecdh5.setPrivateKey(cafebabeKey, 'hex'); |
| 248 | + |
| 249 | +[ // Some invalid private keys for the secp256k1 curve. |
| 250 | + '0000000000000000000000000000000000000000000000000000000000000000', |
| 251 | + 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141', |
| 252 | + 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', |
| 253 | +].forEach(function(element, index, object) { |
| 254 | + assert.throws(function() { |
| 255 | + ecdh5.setPrivateKey(element, 'hex'); |
| 256 | + }, /Private key is not valid for specified curve/); |
| 257 | + // Verify object state did not change. |
| 258 | + assert.equal(ecdh5.getPrivateKey('hex'), cafebabeKey); |
185 | 259 | });
|
0 commit comments