最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to convert raw representations of ECDH key pair into a JSON Web Key? - Stack Overflow

programmeradmin0浏览0评论

Currently, I am trying to pass a public/private pair of keys generated via ECDH, represented as hex strings, into the importKey function of the Web Crypto API.

I am receiving these keys from an external source, but I have generated similar keys via node.js for testing. The curve is prime256v1. For reference, the public key I am using to test that I obtained is 04b71388fced2daee34793f74a7dfa982e37ce539a728233bcadaec298fc4ee422165b8db13e657f9c7b27b35364f523ad11fab29d717606140cc6312ec2c685cc, and the private key is 4bd22700ec3450b5f27e47ba70c233a680c981ab02c1432a859ae23111bef377.

const crypto = require('crypto');
const ecdh = crypto.createECDH('prime256v1');
ecdh.generateKeys();
console.log('ecdh p256 pubkey', ecdh.getPublicKey('hex'));
console.log('ecdh p256 prvkey', ecdh.getPrivateKey('hex'));

Importing the public key is successfully done via the raw option of importKey.

const hexToUintArray = hex => {
  const a = [];
  for (let i = 0, len = hex.length; i < len; i += 2) {
    a.push(parseInt(hex.substr(i, 2), 16));
  }
  return new Uint8Array(a);
}
const importedKey = await crypto.subtle.importKey(
  'raw',
 hexToUintArray('04b71388fced2daee34793f74a7dfa982e37ce539a728233bcadaec298fc4ee422165b8db13e657f9c7b27b35364f523ad11fab29d717606140cc6312ec2c685cc'),
  {
    name: 'ECDH',
    namedCurve: 'P-256'
  },
  true,
  []
);

However, the private key cannot be imported via the same method, as it fails with the error DataError: Data provided to an operation does not meet requirements, since the "raw" option only accepts EC public keys.

const importedPrvKey = await crypto.subtle.importKey(
  'raw',
  hexToUintArray('4bd22700ec3450b5f27e47ba70c233a680c981ab02c1432a859ae23111bef377'),
  {
    name: 'ECDH',
    namedCurve: 'P-256'
  },
  true,
  []
);

I am aware that I am able to import keys easily if it is in JSON Web Key format, but I am not aware of a method to convert it from the raw format to JWK format, or any other importable format that the Web Crypto API accepts.

Currently, I am trying to pass a public/private pair of keys generated via ECDH, represented as hex strings, into the importKey function of the Web Crypto API.

I am receiving these keys from an external source, but I have generated similar keys via node.js for testing. The curve is prime256v1. For reference, the public key I am using to test that I obtained is 04b71388fced2daee34793f74a7dfa982e37ce539a728233bcadaec298fc4ee422165b8db13e657f9c7b27b35364f523ad11fab29d717606140cc6312ec2c685cc, and the private key is 4bd22700ec3450b5f27e47ba70c233a680c981ab02c1432a859ae23111bef377.

const crypto = require('crypto');
const ecdh = crypto.createECDH('prime256v1');
ecdh.generateKeys();
console.log('ecdh p256 pubkey', ecdh.getPublicKey('hex'));
console.log('ecdh p256 prvkey', ecdh.getPrivateKey('hex'));

Importing the public key is successfully done via the raw option of importKey.

const hexToUintArray = hex => {
  const a = [];
  for (let i = 0, len = hex.length; i < len; i += 2) {
    a.push(parseInt(hex.substr(i, 2), 16));
  }
  return new Uint8Array(a);
}
const importedKey = await crypto.subtle.importKey(
  'raw',
 hexToUintArray('04b71388fced2daee34793f74a7dfa982e37ce539a728233bcadaec298fc4ee422165b8db13e657f9c7b27b35364f523ad11fab29d717606140cc6312ec2c685cc'),
  {
    name: 'ECDH',
    namedCurve: 'P-256'
  },
  true,
  []
);

However, the private key cannot be imported via the same method, as it fails with the error DataError: Data provided to an operation does not meet requirements, since the "raw" option only accepts EC public keys.

const importedPrvKey = await crypto.subtle.importKey(
  'raw',
  hexToUintArray('4bd22700ec3450b5f27e47ba70c233a680c981ab02c1432a859ae23111bef377'),
  {
    name: 'ECDH',
    namedCurve: 'P-256'
  },
  true,
  []
);

I am aware that I am able to import keys easily if it is in JSON Web Key format, but I am not aware of a method to convert it from the raw format to JWK format, or any other importable format that the Web Crypto API accepts.

Share Improve this question asked Jul 2, 2019 at 6:56 FreliaFrelia 1311 silver badge10 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 10

Managed to solve this myself, by looking at the source code to the the pem-to-jwk library source code. The library itself provides conversion from PEM to JWK.

The "d" parameter is the private key's ArrayBuffer, url-encoded in Base64. The "x" parameter is the first half of the unpressed public key in an ArrayBuffer, url-encoded as a Base64 string. The "y" parameter is the second half of the unpressed public key in an ArrayBuffer, url-encoded as a Base64 string.

const publicKeyHex = '04b71388fced2daee34793f74a7dfa982e37ce539a728233bcadaec298fc4ee422165b8db13e657f9c7b27b35364f523ad11fab29d717606140cc6312ec2c685cc';
const privateKeyHex = '4bd22700ec3450b5f27e47ba70c233a680c981ab02c1432a859ae23111bef377';

const hexToUintArray = hex => {
  const a = [];
  for (let i = 0, len = hex.length; i < len; i += 2) {
    a.push(parseInt(hex.substr(i, 2), 16));
  }
  return new Uint8Array(a);
}

const hexToArrayBuf = hex => {
  return hexToUintArray(hex).buffer;
}

const arrayBufToBase64UrlEncode = buf => {
  let binary = '';
  const bytes = new Uint8Array(buf);
  for (var i = 0; i < bytes.byteLength; i++) {
      binary += String.fromCharCode(bytes[i]);
  }
  return window.btoa(binary)
    .replace(/\//g, '_')
    .replace(/=/g, '')
    .replace(/\+/g, '-');
}

const jwkConv = (prvHex, pubHex) => ({
  kty: "EC",
  crv: "P-256",
  d: arrayBufToBase64UrlEncode(hexToArrayBuf(prvHex)),
  x: arrayBufToBase64UrlEncode(hexToArrayBuf(pubHex).slice(1, 33)),
  y: arrayBufToBase64UrlEncode(hexToArrayBuf(pubHex).slice(33, 66))
});

const importedPrivateKey = await crypto.subtle.importKey(
  'jwk',
  jwkConv(privateKeyHex, publicKeyHex),
  {
    name: 'ECDH',
    namedCurve: 'P-256'
  },
  true,
  []
);
发布评论

评论列表(0)

  1. 暂无评论