UNPKG

@digitalcredentials/ed25519-verification-key-2020

Version:

Javascript library for generating and working with Ed25519VerificationKey2020 key pairs, for use with crypto-ld.

157 lines 5.45 kB
/*! * Copyright (c) 2020-2022 Digital Bazaar, Inc. All rights reserved. */ import { sign, verify, createHash, createPrivateKey, createPublicKey } from 'crypto'; import { assertKeyBytes } from './validators.js'; const crypto = globalThis.crypto; if (typeof crypto.getRandomValues === 'undefined') { throw new Error('Environment does not provide "crypto.getRandomValues".'); } // used to export node's public keys to buffers const publicKeyEncoding = { format: 'der', type: 'spki' }; // used to turn private key bytes into a buffer in DER format const DER_PRIVATE_KEY_PREFIX = Buffer.from('302e020100300506032b657004220420', 'hex'); // used to turn public key bytes into a buffer in DER format const DER_PUBLIC_KEY_PREFIX = Buffer.from('302a300506032b6570032100', 'hex'); /** * Generates a key using a 32 byte Uint8Array. * * @param {Uint8Array} seedBytes - The bytes for the private key. * * @returns {object} The object with the public and private key material. */ async function generateKeyPairFromSeed(seedBytes) { const privateKey = await createPrivateKey({ // node is more than happy to create a new private key using a DER key: privateKeyDerEncode({ seedBytes: seedBytes }), format: 'der', type: 'pkcs8' }); // this expects either a PEM encoded key or a node privateKeyObject const publicKey = await createPublicKey(privateKey); const publicKeyBuffer = publicKey.export(publicKeyEncoding); const publicKeyBytes = getKeyMaterial(publicKeyBuffer); return { publicKey: publicKeyBytes, secretKey: Buffer.concat([seedBytes, publicKeyBytes]) }; } // generates an ed25519 key using a random seed async function generateKeyPair() { const seed = new Uint8Array(32); crypto.getRandomValues(seed); const keyPair = await generateKeyPairFromSeed(seed); seed.fill(0); return keyPair; } async function signData(privateKeyBytes, data) { const privateKey = await createPrivateKey({ key: privateKeyDerEncode({ privateKeyBytes: privateKeyBytes }), format: 'der', type: 'pkcs8' }); return sign(null, data, privateKey); } async function verifyData(publicKeyBytes, data, signature) { const publicKey = await createPublicKey({ key: publicKeyDerEncode(publicKeyBytes), format: 'der', type: 'spki' }); return verify(null, data, publicKey, signature); } async function sha256digest(data) { return createHash('sha256').update(data).digest(); } export default { generateKeyPairFromSeed, generateKeyPair, sign: signData, verify: verifyData, sha256digest }; /** * The key material is the part of the buffer after the DER Prefix. * * @param {Buffer} buffer - A DER encoded key buffer. * * @throws {Error} If the buffer does not contain a valid DER Prefix. * * @returns {Buffer} The key material part of the Buffer. */ function getKeyMaterial(buffer) { if (buffer.indexOf(DER_PUBLIC_KEY_PREFIX) === 0) { return buffer.slice(DER_PUBLIC_KEY_PREFIX.length, buffer.length); } if (buffer.indexOf(DER_PRIVATE_KEY_PREFIX) === 0) { return buffer.slice(DER_PRIVATE_KEY_PREFIX.length, buffer.length); } throw new Error('Expected Buffer to match Ed25519 Public or Private Prefix'); } /** * Takes a Buffer or Uint8Array with the raw private key and encodes it * in DER-encoded PKCS#8 format. * Allows Uint8Arrays to be interoperable with node's crypto functions. * * @param {Buffer} [privateKeyBytes] - Required if no seedBytes. * @param {Buffer} [seedBytes] - Required if no privateKeyBytes. * * @throws {TypeError} Throws if the supplied buffer is not of the right size * or not a Uint8Array or Buffer. * * @returns {Buffer} DER private key prefix + key bytes. */ function privateKeyDerEncode({ privateKeyBytes, seedBytes }) { if (!(privateKeyBytes != null || seedBytes != null)) { throw new TypeError('`privateKeyBytes` or `seedBytes` is required.'); } if (seedBytes && !privateKeyBytes) { assertKeyBytes({ bytes: seedBytes, expectedLength: 32 }); } if (privateKeyBytes && !seedBytes) { assertKeyBytes({ bytes: privateKeyBytes, expectedLength: 64 }); } if (seedBytes == null && !(privateKeyBytes instanceof Uint8Array && privateKeyBytes.length === 64)) { throw new TypeError('`privateKeyBytes` must be a 64 byte Buffer.'); } let p; if (seedBytes != null) { p = seedBytes; } else { // extract the first 32 bytes of the 64 byte private key representation // @ts-ignore p = privateKeyBytes.slice(0, 32); } return Buffer.concat([DER_PRIVATE_KEY_PREFIX, p]); } /** * Takes a Uint8Array of public key bytes and encodes it in DER-encoded * SubjectPublicKeyInfo (SPKI) format. * Allows Uint8Arrays to be interoperable with node's crypto functions. * * @param {Uint8Array} publicKeyBytes - The keyBytes. * * @throws {TypeError} Throws if the bytes are not Uint8Array or of length 32. * * @returns {Buffer} DER Public key Prefix + key bytes. */ function publicKeyDerEncode(publicKeyBytes) { assertKeyBytes({ bytes: publicKeyBytes, expectedLength: 32, code: 'invalidPublicKeyLength' }); return Buffer.concat([DER_PUBLIC_KEY_PREFIX, publicKeyBytes]); } //# sourceMappingURL=ed25519.js.map