UNPKG

@libp2p/crypto

Version:
165 lines • 6.4 kB
import { InvalidParametersError } from '@libp2p/interface'; import { Uint8ArrayList } from 'uint8arraylist'; import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'; import { toString as uint8ArrayToString } from 'uint8arrays/to-string'; import { decodeDer, encodeBitString, encodeInteger, encodeOctetString, encodeSequence } from '../rsa/der.js'; import { ECDSAPrivateKey as ECDSAPrivateKeyClass, ECDSAPublicKey as ECDSAPublicKeyClass } from './ecdsa.js'; import { generateECDSAKey } from './index.js'; // 1.2.840.10045.3.1.7 prime256v1 (ANSI X9.62 named elliptic curve) const OID_256 = Uint8Array.from([0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07]); // 1.3.132.0.34 secp384r1 (SECG (Certicom) named elliptic curve) const OID_384 = Uint8Array.from([0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22]); // 1.3.132.0.35 secp521r1 (SECG (Certicom) named elliptic curve) const OID_521 = Uint8Array.from([0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23]); const P_256_KEY_JWK = { ext: true, kty: 'EC', crv: 'P-256' }; const P_384_KEY_JWK = { ext: true, kty: 'EC', crv: 'P-384' }; const P_521_KEY_JWK = { ext: true, kty: 'EC', crv: 'P-521' }; const P_256_KEY_LENGTH = 32; const P_384_KEY_LENGTH = 48; const P_521_KEY_LENGTH = 66; export function unmarshalECDSAPrivateKey(bytes) { const message = decodeDer(bytes); return pkiMessageToECDSAPrivateKey(message); } export function pkiMessageToECDSAPrivateKey(message) { const privateKey = message[1]; const d = uint8ArrayToString(privateKey, 'base64url'); const coordinates = message[2][1][0]; const offset = 1; let x; let y; if (privateKey.byteLength === P_256_KEY_LENGTH) { x = uint8ArrayToString(coordinates.subarray(offset, offset + P_256_KEY_LENGTH), 'base64url'); y = uint8ArrayToString(coordinates.subarray(offset + P_256_KEY_LENGTH), 'base64url'); return new ECDSAPrivateKeyClass({ ...P_256_KEY_JWK, key_ops: ['sign'], d, x, y }); } if (privateKey.byteLength === P_384_KEY_LENGTH) { x = uint8ArrayToString(coordinates.subarray(offset, offset + P_384_KEY_LENGTH), 'base64url'); y = uint8ArrayToString(coordinates.subarray(offset + P_384_KEY_LENGTH), 'base64url'); return new ECDSAPrivateKeyClass({ ...P_384_KEY_JWK, key_ops: ['sign'], d, x, y }); } if (privateKey.byteLength === P_521_KEY_LENGTH) { x = uint8ArrayToString(coordinates.subarray(offset, offset + P_521_KEY_LENGTH), 'base64url'); y = uint8ArrayToString(coordinates.subarray(offset + P_521_KEY_LENGTH), 'base64url'); return new ECDSAPrivateKeyClass({ ...P_521_KEY_JWK, key_ops: ['sign'], d, x, y }); } throw new InvalidParametersError(`Private key length was wrong length, got ${privateKey.byteLength}, expected 32, 48 or 66`); } export function unmarshalECDSAPublicKey(bytes) { const message = decodeDer(bytes); return pkiMessageToECDSAPublicKey(message); } export function pkiMessageToECDSAPublicKey(message) { const coordinates = message[1][1][0]; const offset = 1; let x; let y; if (coordinates.byteLength === ((P_256_KEY_LENGTH * 2) + 1)) { x = uint8ArrayToString(coordinates.subarray(offset, offset + P_256_KEY_LENGTH), 'base64url'); y = uint8ArrayToString(coordinates.subarray(offset + P_256_KEY_LENGTH), 'base64url'); return new ECDSAPublicKeyClass({ ...P_256_KEY_JWK, key_ops: ['verify'], x, y }); } if (coordinates.byteLength === ((P_384_KEY_LENGTH * 2) + 1)) { x = uint8ArrayToString(coordinates.subarray(offset, offset + P_384_KEY_LENGTH), 'base64url'); y = uint8ArrayToString(coordinates.subarray(offset + P_384_KEY_LENGTH), 'base64url'); return new ECDSAPublicKeyClass({ ...P_384_KEY_JWK, key_ops: ['verify'], x, y }); } if (coordinates.byteLength === ((P_521_KEY_LENGTH * 2) + 1)) { x = uint8ArrayToString(coordinates.subarray(offset, offset + P_521_KEY_LENGTH), 'base64url'); y = uint8ArrayToString(coordinates.subarray(offset + P_521_KEY_LENGTH), 'base64url'); return new ECDSAPublicKeyClass({ ...P_521_KEY_JWK, key_ops: ['verify'], x, y }); } throw new InvalidParametersError(`coordinates were wrong length, got ${coordinates.byteLength}, expected 65, 97 or 133`); } export function privateKeyToPKIMessage(privateKey) { return encodeSequence([ encodeInteger(Uint8Array.from([1])), // header encodeOctetString(uint8ArrayFromString(privateKey.d ?? '', 'base64url')), // body encodeSequence([ getOID(privateKey.crv) ], 0xA0), encodeSequence([ encodeBitString(new Uint8ArrayList(Uint8Array.from([0x04]), uint8ArrayFromString(privateKey.x ?? '', 'base64url'), uint8ArrayFromString(privateKey.y ?? '', 'base64url'))) ], 0xA1) ]).subarray(); } export function publicKeyToPKIMessage(publicKey) { return encodeSequence([ encodeInteger(Uint8Array.from([1])), // header encodeSequence([ getOID(publicKey.crv) ], 0xA0), encodeSequence([ encodeBitString(new Uint8ArrayList(Uint8Array.from([0x04]), uint8ArrayFromString(publicKey.x ?? '', 'base64url'), uint8ArrayFromString(publicKey.y ?? '', 'base64url'))) ], 0xA1) ]).subarray(); } function getOID(curve) { if (curve === 'P-256') { return OID_256; } if (curve === 'P-384') { return OID_384; } if (curve === 'P-521') { return OID_521; } throw new InvalidParametersError(`Invalid curve ${curve}`); } export async function generateECDSAKeyPair(curve = 'P-256') { const key = await generateECDSAKey(curve); return new ECDSAPrivateKeyClass(key.privateKey); } export function ensureECDSAKey(key, length) { key = Uint8Array.from(key ?? []); if (key.length !== length) { throw new InvalidParametersError(`Key must be a Uint8Array of length ${length}, got ${key.length}`); } return key; } //# sourceMappingURL=utils.js.map