UNPKG

crypto-key-composer

Version:

A library to decompose and compose crypto keys of different types and formats

210 lines (174 loc) 5.82 kB
import { decomposeRsaPrivateKey, composeRsaPrivateKey } from '../raw/keys'; import { decodeAsn1, encodeAsn1 } from '../../util/asn1-encoder'; import { EcParameters, EcPrivateKey, CurvePrivateKey } from '../../util/asn1-entities'; import { decodeEcPoint, encodeEcPoint, validateEcD } from '../../util/ec'; import { hexStringToUint8Array } from '../../util/binary'; import { UnsupportedAlgorithmError } from '../../util/errors'; import { OIDS, FLIPPED_OIDS } from '../../util/oids'; import { KEY_TYPES } from '../../util/key-types'; const decomposeRsaPrivateKeyInfo = privateKeyInfo => { const { privateKeyAlgorithm, privateKey: privateKeyAsn1 } = privateKeyInfo; const keyAlgorithm = { id: OIDS[privateKeyAlgorithm.id] }; switch (keyAlgorithm.id) { case 'rsa-encryption': case 'md2-with-rsa-encryption': case 'md4-with-rsa-encryption': case 'md5-with-rsa-encryption': case 'sha1-with-rsa-encryption': case 'sha224-with-rsa-encryption': case 'sha256-with-rsa-encryption': case 'sha384-with-rsa-encryption': case 'sha512-with-rsa-encryption': case 'sha512-224-with-rsa-encryption': case 'sha512-256-with-rsa-encryption': break; /* istanbul ignore next */ case 'rsaes-oaep': throw new UnsupportedAlgorithmError('RSA-OAEP keys are not yet supported'); /* istanbul ignore next */ case 'rsassa-pss': throw new UnsupportedAlgorithmError('RSA-PSS keys are not yet supported'); /* istanbul ignore next */ default: throw new UnsupportedAlgorithmError(`Unsupported key algorithm OID '${privateKeyAlgorithm.id}'`); } const { keyData } = decomposeRsaPrivateKey(privateKeyAsn1); return { keyAlgorithm: { id: OIDS[privateKeyAlgorithm.id] }, keyData }; }; const composeRsaPrivateKeyInfo = (keyAlgorithm, keyData) => { const rsaPrivateKeyAsn1 = composeRsaPrivateKey(keyAlgorithm, keyData); return { version: 0, privateKeyAlgorithm: { id: FLIPPED_OIDS[keyAlgorithm.id], parameters: hexStringToUint8Array('0500') }, privateKey: rsaPrivateKeyAsn1 }; }; const decomposeEcPrivateKeyInfo = privateKeyInfo => { const { privateKeyAlgorithm, privateKey: privateKeyAsn1 } = privateKeyInfo; const ecParameters = decodeAsn1(privateKeyAlgorithm.parameters, EcParameters); const ecPrivateKey = decodeAsn1(privateKeyAsn1, EcPrivateKey); // Validate parameters & publicKey /* istanbul ignore if */ if (ecParameters.type !== 'namedCurve') { throw new UnsupportedAlgorithmError('Only EC named curves are supported'); } /* istanbul ignore if */ if (!ecPrivateKey.publicKey) { throw new UnsupportedAlgorithmError('Missing publicKey from ECPrivateKey'); } // Ensure that the named curve is supported const namedCurve = OIDS[ecParameters.value]; if (!namedCurve) { throw new UnsupportedAlgorithmError(`Unsupported named curve OID '${ecParameters.value}'`); } // Validate & get encoded point const { x, y } = decodeEcPoint(namedCurve, ecPrivateKey.publicKey.data); return { keyAlgorithm: { id: 'ec-public-key', namedCurve }, keyData: { d: ecPrivateKey.privateKey, x, y } }; }; const composeEcPrivateKeyInfo = (keyAlgorithm, keyData) => { // Validate named curve const namedCurveOid = FLIPPED_OIDS[keyAlgorithm.namedCurve]; if (!namedCurveOid) { throw new UnsupportedAlgorithmError(`Unsupported named curve '${keyAlgorithm.namedCurve}'`); } // Validate D value (private key) const privateKey = validateEcD(keyAlgorithm.namedCurve, keyData.d); // Validate & encode point (public key) const publicKey = encodeEcPoint(keyAlgorithm.namedCurve, keyData.x, keyData.y); const ecPrivateKey = { version: 1, privateKey, publicKey: { unused: 0, data: publicKey } }; const ecPrivateKeyAsn1 = encodeAsn1(ecPrivateKey, EcPrivateKey); const ecParametersAsn1 = encodeAsn1({ type: 'namedCurve', value: namedCurveOid }, EcParameters); return { version: 0, privateKeyAlgorithm: { id: FLIPPED_OIDS[keyAlgorithm.id], parameters: ecParametersAsn1 }, privateKey: ecPrivateKeyAsn1 }; }; const decomposeEd25519PrivateKeyInfo = privateKeyInfo => { // See: https://tools.ietf.org/html/rfc8032#section-5.1.5 const { privateKeyAlgorithm, privateKey } = privateKeyInfo; const seed = decodeAsn1(privateKey, CurvePrivateKey); return { keyAlgorithm: { id: OIDS[privateKeyAlgorithm.id] }, keyData: { seed } }; }; const composeEd25519PrivateKeyInfo = (keyAlgorithm, keyData) => ({ version: 0, privateKeyAlgorithm: { id: FLIPPED_OIDS[keyAlgorithm.id] }, privateKey: encodeAsn1(keyData.seed, CurvePrivateKey) }); export const decomposePrivateKeyInfo = privateKeyInfo => { const keyType = KEY_TYPES[OIDS[privateKeyInfo.privateKeyAlgorithm.id]]; switch (keyType) { case 'rsa': return decomposeRsaPrivateKeyInfo(privateKeyInfo); case 'ec': return decomposeEcPrivateKeyInfo(privateKeyInfo); case 'ed25519': return decomposeEd25519PrivateKeyInfo(privateKeyInfo); default: throw new UnsupportedAlgorithmError(`Unsupported key algorithm OID '${privateKeyInfo.privateKeyAlgorithm.id}'`); } }; export const composePrivateKeyInfo = (keyAlgorithm, keyData) => { const keyType = KEY_TYPES[keyAlgorithm.id]; switch (keyType) { case 'rsa': return composeRsaPrivateKeyInfo(keyAlgorithm, keyData); case 'ec': return composeEcPrivateKeyInfo(keyAlgorithm, keyData); case 'ed25519': return composeEd25519PrivateKeyInfo(keyAlgorithm, keyData); default: throw new UnsupportedAlgorithmError(`Unsupported key algorithm id '${keyAlgorithm.id}'`); } };