crypto: add ECDH.convertKey to convert public keys
ECDH.convertKey is used to convert public keys between different formats. PR-URL: https://github.com/nodejs/node/pull/19080 Fixes: https://github.com/nodejs/node/issues/18977 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
a0adf56855
commit
f2e02883e7
@ -656,6 +656,54 @@ assert.strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex'));
|
|||||||
// OK
|
// OK
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### ECDH.convertKey(key, curve[, inputEncoding[, outputEncoding[, format]]])
|
||||||
|
<!-- YAML
|
||||||
|
added: REPLACEME
|
||||||
|
-->
|
||||||
|
|
||||||
|
- `key` {string | Buffer | TypedArray | DataView}
|
||||||
|
- `curve` {string}
|
||||||
|
- `inputEncoding` {string}
|
||||||
|
- `outputEncoding` {string}
|
||||||
|
- `format` {string} Defaults to `uncompressed`.
|
||||||
|
|
||||||
|
Converts the EC Diffie-Hellman public key specified by `key` and `curve` to the
|
||||||
|
format specified by `format`. The `format` argument specifies point encoding
|
||||||
|
and can be `'compressed'`, `'uncompressed'` or `'hybrid'`. The supplied key is
|
||||||
|
interpreted using the specified `inputEncoding`, and the returned key is encoded
|
||||||
|
using the specified `outputEncoding`. Encodings can be `'latin1'`, `'hex'`,
|
||||||
|
or `'base64'`.
|
||||||
|
|
||||||
|
Use [`crypto.getCurves()`][] to obtain a list of available curve names.
|
||||||
|
On recent OpenSSL releases, `openssl ecparam -list_curves` will also display
|
||||||
|
the name and description of each available elliptic curve.
|
||||||
|
|
||||||
|
If `format` is not specified the point will be returned in `'uncompressed'`
|
||||||
|
format.
|
||||||
|
|
||||||
|
If the `inputEncoding` is not provided, `key` is expected to be a [`Buffer`][],
|
||||||
|
`TypedArray`, or `DataView`.
|
||||||
|
|
||||||
|
Example (uncompressing a key):
|
||||||
|
|
||||||
|
```js
|
||||||
|
const { ECDH } = require('crypto');
|
||||||
|
|
||||||
|
const ecdh = ECDH('secp256k1');
|
||||||
|
ecdh.generateKeys();
|
||||||
|
|
||||||
|
const compressedKey = ecdh.getPublicKey('hex', 'compressed');
|
||||||
|
|
||||||
|
const uncompressedKey = ECDH.convertKey(compressedKey,
|
||||||
|
'secp256k1',
|
||||||
|
'hex',
|
||||||
|
'hex',
|
||||||
|
'uncompressed');
|
||||||
|
|
||||||
|
// the converted key and the uncompressed public key should be the same
|
||||||
|
console.log(uncompressedKey === ecdh.getPublicKey('hex'));
|
||||||
|
```
|
||||||
|
|
||||||
### ecdh.computeSecret(otherPublicKey[, inputEncoding][, outputEncoding])
|
### ecdh.computeSecret(otherPublicKey[, inputEncoding][, outputEncoding])
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
added: v0.11.14
|
added: v0.11.14
|
||||||
|
@ -14,7 +14,8 @@ const {
|
|||||||
const {
|
const {
|
||||||
DiffieHellman: _DiffieHellman,
|
DiffieHellman: _DiffieHellman,
|
||||||
DiffieHellmanGroup: _DiffieHellmanGroup,
|
DiffieHellmanGroup: _DiffieHellmanGroup,
|
||||||
ECDH: _ECDH
|
ECDH: _ECDH,
|
||||||
|
ECDHConvertKey: _ECDHConvertKey
|
||||||
} = process.binding('crypto');
|
} = process.binding('crypto');
|
||||||
const {
|
const {
|
||||||
POINT_CONVERSION_COMPRESSED,
|
POINT_CONVERSION_COMPRESSED,
|
||||||
@ -84,11 +85,9 @@ DiffieHellmanGroup.prototype.generateKeys =
|
|||||||
dhGenerateKeys;
|
dhGenerateKeys;
|
||||||
|
|
||||||
function dhGenerateKeys(encoding) {
|
function dhGenerateKeys(encoding) {
|
||||||
var keys = this._handle.generateKeys();
|
const keys = this._handle.generateKeys();
|
||||||
encoding = encoding || getDefaultEncoding();
|
encoding = encoding || getDefaultEncoding();
|
||||||
if (encoding && encoding !== 'buffer')
|
return encode(keys, encoding);
|
||||||
keys = keys.toString(encoding);
|
|
||||||
return keys;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -100,12 +99,10 @@ function dhComputeSecret(key, inEnc, outEnc) {
|
|||||||
const encoding = getDefaultEncoding();
|
const encoding = getDefaultEncoding();
|
||||||
inEnc = inEnc || encoding;
|
inEnc = inEnc || encoding;
|
||||||
outEnc = outEnc || encoding;
|
outEnc = outEnc || encoding;
|
||||||
var ret = this._handle.computeSecret(toBuf(key, inEnc));
|
const ret = this._handle.computeSecret(toBuf(key, inEnc));
|
||||||
if (typeof ret === 'string')
|
if (typeof ret === 'string')
|
||||||
throw new ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY();
|
throw new ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY();
|
||||||
if (outEnc && outEnc !== 'buffer')
|
return encode(ret, outEnc);
|
||||||
ret = ret.toString(outEnc);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -114,11 +111,9 @@ DiffieHellmanGroup.prototype.getPrime =
|
|||||||
dhGetPrime;
|
dhGetPrime;
|
||||||
|
|
||||||
function dhGetPrime(encoding) {
|
function dhGetPrime(encoding) {
|
||||||
var prime = this._handle.getPrime();
|
const prime = this._handle.getPrime();
|
||||||
encoding = encoding || getDefaultEncoding();
|
encoding = encoding || getDefaultEncoding();
|
||||||
if (encoding && encoding !== 'buffer')
|
return encode(prime, encoding);
|
||||||
prime = prime.toString(encoding);
|
|
||||||
return prime;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -127,11 +122,9 @@ DiffieHellmanGroup.prototype.getGenerator =
|
|||||||
dhGetGenerator;
|
dhGetGenerator;
|
||||||
|
|
||||||
function dhGetGenerator(encoding) {
|
function dhGetGenerator(encoding) {
|
||||||
var generator = this._handle.getGenerator();
|
const generator = this._handle.getGenerator();
|
||||||
encoding = encoding || getDefaultEncoding();
|
encoding = encoding || getDefaultEncoding();
|
||||||
if (encoding && encoding !== 'buffer')
|
return encode(generator, encoding);
|
||||||
generator = generator.toString(encoding);
|
|
||||||
return generator;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -140,11 +133,9 @@ DiffieHellmanGroup.prototype.getPublicKey =
|
|||||||
dhGetPublicKey;
|
dhGetPublicKey;
|
||||||
|
|
||||||
function dhGetPublicKey(encoding) {
|
function dhGetPublicKey(encoding) {
|
||||||
var key = this._handle.getPublicKey();
|
const key = this._handle.getPublicKey();
|
||||||
encoding = encoding || getDefaultEncoding();
|
encoding = encoding || getDefaultEncoding();
|
||||||
if (encoding && encoding !== 'buffer')
|
return encode(key, encoding);
|
||||||
key = key.toString(encoding);
|
|
||||||
return key;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -153,11 +144,9 @@ DiffieHellmanGroup.prototype.getPrivateKey =
|
|||||||
dhGetPrivateKey;
|
dhGetPrivateKey;
|
||||||
|
|
||||||
function dhGetPrivateKey(encoding) {
|
function dhGetPrivateKey(encoding) {
|
||||||
var key = this._handle.getPrivateKey();
|
const key = this._handle.getPrivateKey();
|
||||||
encoding = encoding || getDefaultEncoding();
|
encoding = encoding || getDefaultEncoding();
|
||||||
if (encoding && encoding !== 'buffer')
|
return encode(key, encoding);
|
||||||
key = key.toString(encoding);
|
|
||||||
return key;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -197,7 +186,40 @@ ECDH.prototype.generateKeys = function generateKeys(encoding, format) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ECDH.prototype.getPublicKey = function getPublicKey(encoding, format) {
|
ECDH.prototype.getPublicKey = function getPublicKey(encoding, format) {
|
||||||
var f;
|
const f = getFormat(format);
|
||||||
|
const key = this._handle.getPublicKey(f);
|
||||||
|
encoding = encoding || getDefaultEncoding();
|
||||||
|
return encode(key, encoding);
|
||||||
|
};
|
||||||
|
|
||||||
|
ECDH.convertKey = function convertKey(key, curve, inEnc, outEnc, format) {
|
||||||
|
if (typeof key !== 'string' && !isArrayBufferView(key)) {
|
||||||
|
throw new ERR_INVALID_ARG_TYPE(
|
||||||
|
'key',
|
||||||
|
['string', 'Buffer', 'TypedArray', 'DataView']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof curve !== 'string') {
|
||||||
|
throw new ERR_INVALID_ARG_TYPE('curve', 'string');
|
||||||
|
}
|
||||||
|
|
||||||
|
const encoding = getDefaultEncoding();
|
||||||
|
inEnc = inEnc || encoding;
|
||||||
|
outEnc = outEnc || encoding;
|
||||||
|
const f = getFormat(format);
|
||||||
|
const convertedKey = _ECDHConvertKey(toBuf(key, inEnc), curve, f);
|
||||||
|
return encode(convertedKey, outEnc);
|
||||||
|
};
|
||||||
|
|
||||||
|
function encode(buffer, encoding) {
|
||||||
|
if (encoding && encoding !== 'buffer')
|
||||||
|
buffer = buffer.toString(encoding);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFormat(format) {
|
||||||
|
let f;
|
||||||
if (format) {
|
if (format) {
|
||||||
if (format === 'compressed')
|
if (format === 'compressed')
|
||||||
f = POINT_CONVERSION_COMPRESSED;
|
f = POINT_CONVERSION_COMPRESSED;
|
||||||
@ -211,12 +233,8 @@ ECDH.prototype.getPublicKey = function getPublicKey(encoding, format) {
|
|||||||
} else {
|
} else {
|
||||||
f = POINT_CONVERSION_UNCOMPRESSED;
|
f = POINT_CONVERSION_UNCOMPRESSED;
|
||||||
}
|
}
|
||||||
var key = this._handle.getPublicKey(f);
|
return f;
|
||||||
encoding = encoding || getDefaultEncoding();
|
}
|
||||||
if (encoding && encoding !== 'buffer')
|
|
||||||
key = key.toString(encoding);
|
|
||||||
return key;
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
DiffieHellman,
|
DiffieHellman,
|
||||||
|
@ -4731,31 +4731,31 @@ void ECDH::GenerateKeys(const FunctionCallbackInfo<Value>& args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
EC_POINT* ECDH::BufferToPoint(char* data, size_t len) {
|
EC_POINT* ECDH::BufferToPoint(Environment* env,
|
||||||
|
const EC_GROUP* group,
|
||||||
|
char* data,
|
||||||
|
size_t len) {
|
||||||
EC_POINT* pub;
|
EC_POINT* pub;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
pub = EC_POINT_new(group_);
|
pub = EC_POINT_new(group);
|
||||||
if (pub == nullptr) {
|
if (pub == nullptr) {
|
||||||
env()->ThrowError("Failed to allocate EC_POINT for a public key");
|
env->ThrowError("Failed to allocate EC_POINT for a public key");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = EC_POINT_oct2point(
|
r = EC_POINT_oct2point(
|
||||||
group_,
|
group,
|
||||||
pub,
|
pub,
|
||||||
reinterpret_cast<unsigned char*>(data),
|
reinterpret_cast<unsigned char*>(data),
|
||||||
len,
|
len,
|
||||||
nullptr);
|
nullptr);
|
||||||
if (!r) {
|
if (!r) {
|
||||||
goto fatal;
|
EC_POINT_free(pub);
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pub;
|
return pub;
|
||||||
|
|
||||||
fatal:
|
|
||||||
EC_POINT_free(pub);
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4772,7 +4772,9 @@ void ECDH::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
|
|||||||
if (!ecdh->IsKeyPairValid())
|
if (!ecdh->IsKeyPairValid())
|
||||||
return env->ThrowError("Invalid key pair");
|
return env->ThrowError("Invalid key pair");
|
||||||
|
|
||||||
EC_POINT* pub = ecdh->BufferToPoint(Buffer::Data(args[0]),
|
EC_POINT* pub = ECDH::BufferToPoint(env,
|
||||||
|
ecdh->group_,
|
||||||
|
Buffer::Data(args[0]),
|
||||||
Buffer::Length(args[0]));
|
Buffer::Length(args[0]));
|
||||||
if (pub == nullptr) {
|
if (pub == nullptr) {
|
||||||
args.GetReturnValue().Set(
|
args.GetReturnValue().Set(
|
||||||
@ -4921,7 +4923,9 @@ void ECDH::SetPublicKey(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
MarkPopErrorOnReturn mark_pop_error_on_return;
|
MarkPopErrorOnReturn mark_pop_error_on_return;
|
||||||
|
|
||||||
EC_POINT* pub = ecdh->BufferToPoint(Buffer::Data(args[0].As<Object>()),
|
EC_POINT* pub = ECDH::BufferToPoint(env,
|
||||||
|
ecdh->group_,
|
||||||
|
Buffer::Data(args[0].As<Object>()),
|
||||||
Buffer::Length(args[0].As<Object>()));
|
Buffer::Length(args[0].As<Object>()));
|
||||||
if (pub == nullptr)
|
if (pub == nullptr)
|
||||||
return env->ThrowError("Failed to convert Buffer to EC_POINT");
|
return env->ThrowError("Failed to convert Buffer to EC_POINT");
|
||||||
@ -5597,6 +5601,61 @@ void ExportChallenge(const FunctionCallbackInfo<Value>& args) {
|
|||||||
args.GetReturnValue().Set(outString);
|
args.GetReturnValue().Set(outString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Convert the input public key to compressed, uncompressed, or hybrid formats.
|
||||||
|
void ConvertKey(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
|
||||||
|
CHECK_EQ(args.Length(), 3);
|
||||||
|
|
||||||
|
size_t len = Buffer::Length(args[0]);
|
||||||
|
if (len == 0)
|
||||||
|
return args.GetReturnValue().SetEmptyString();
|
||||||
|
|
||||||
|
node::Utf8Value curve(env->isolate(), args[1]);
|
||||||
|
|
||||||
|
int nid = OBJ_sn2nid(*curve);
|
||||||
|
if (nid == NID_undef)
|
||||||
|
return env->ThrowTypeError("Invalid ECDH curve name");
|
||||||
|
|
||||||
|
EC_GROUP* group = EC_GROUP_new_by_curve_name(nid);
|
||||||
|
if (group == nullptr)
|
||||||
|
return env->ThrowError("Failed to get EC_GROUP");
|
||||||
|
|
||||||
|
EC_POINT* pub = ECDH::BufferToPoint(env,
|
||||||
|
group,
|
||||||
|
Buffer::Data(args[0]),
|
||||||
|
len);
|
||||||
|
|
||||||
|
std::shared_ptr<void> cleanup(nullptr, [group, pub] (...) {
|
||||||
|
EC_GROUP_free(group);
|
||||||
|
EC_POINT_free(pub);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (pub == nullptr)
|
||||||
|
return env->ThrowError("Failed to convert Buffer to EC_POINT");
|
||||||
|
|
||||||
|
point_conversion_form_t form =
|
||||||
|
static_cast<point_conversion_form_t>(args[2]->Uint32Value());
|
||||||
|
|
||||||
|
int size = EC_POINT_point2oct(group, pub, form, nullptr, 0, nullptr);
|
||||||
|
if (size == 0)
|
||||||
|
return env->ThrowError("Failed to get public key length");
|
||||||
|
|
||||||
|
unsigned char* out = node::Malloc<unsigned char>(size);
|
||||||
|
|
||||||
|
int r = EC_POINT_point2oct(group, pub, form, out, size, nullptr);
|
||||||
|
if (r != size) {
|
||||||
|
free(out);
|
||||||
|
return env->ThrowError("Failed to get public key");
|
||||||
|
}
|
||||||
|
|
||||||
|
Local<Object> buf =
|
||||||
|
Buffer::New(env, reinterpret_cast<char*>(out), size).ToLocalChecked();
|
||||||
|
args.GetReturnValue().Set(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void TimingSafeEqual(const FunctionCallbackInfo<Value>& args) {
|
void TimingSafeEqual(const FunctionCallbackInfo<Value>& args) {
|
||||||
CHECK(Buffer::HasInstance(args[0]));
|
CHECK(Buffer::HasInstance(args[0]));
|
||||||
CHECK(Buffer::HasInstance(args[1]));
|
CHECK(Buffer::HasInstance(args[1]));
|
||||||
@ -5739,6 +5798,8 @@ void InitCrypto(Local<Object> target,
|
|||||||
env->SetMethod(target, "certVerifySpkac", VerifySpkac);
|
env->SetMethod(target, "certVerifySpkac", VerifySpkac);
|
||||||
env->SetMethod(target, "certExportPublicKey", ExportPublicKey);
|
env->SetMethod(target, "certExportPublicKey", ExportPublicKey);
|
||||||
env->SetMethod(target, "certExportChallenge", ExportChallenge);
|
env->SetMethod(target, "certExportChallenge", ExportChallenge);
|
||||||
|
|
||||||
|
env->SetMethod(target, "ECDHConvertKey", ConvertKey);
|
||||||
#ifndef OPENSSL_NO_ENGINE
|
#ifndef OPENSSL_NO_ENGINE
|
||||||
env->SetMethod(target, "setEngine", SetEngine);
|
env->SetMethod(target, "setEngine", SetEngine);
|
||||||
#endif // !OPENSSL_NO_ENGINE
|
#endif // !OPENSSL_NO_ENGINE
|
||||||
|
@ -627,6 +627,10 @@ class ECDH : public BaseObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void Initialize(Environment* env, v8::Local<v8::Object> target);
|
static void Initialize(Environment* env, v8::Local<v8::Object> target);
|
||||||
|
static EC_POINT* BufferToPoint(Environment* env,
|
||||||
|
const EC_GROUP* group,
|
||||||
|
char* data,
|
||||||
|
size_t len);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ECDH(Environment* env, v8::Local<v8::Object> wrap, EC_KEY* key)
|
ECDH(Environment* env, v8::Local<v8::Object> wrap, EC_KEY* key)
|
||||||
@ -645,8 +649,6 @@ class ECDH : public BaseObject {
|
|||||||
static void GetPublicKey(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void GetPublicKey(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void SetPublicKey(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void SetPublicKey(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
|
||||||
EC_POINT* BufferToPoint(char* data, size_t len);
|
|
||||||
|
|
||||||
bool IsKeyPairValid();
|
bool IsKeyPairValid();
|
||||||
bool IsKeyValidForCurve(const BIGNUM* private_key);
|
bool IsKeyValidForCurve(const BIGNUM* private_key);
|
||||||
|
|
||||||
|
101
test/parallel/test-crypto-ecdh-convert-key.js
Normal file
101
test/parallel/test-crypto-ecdh-convert-key.js
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
'use strict';
|
||||||
|
const common = require('../common');
|
||||||
|
if (!common.hasCrypto)
|
||||||
|
common.skip('missing crypto');
|
||||||
|
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
|
const { ECDH, 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);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user