crypto-key-composer
Version:
A library to decompose and compose crypto keys of different types and formats
195 lines (162 loc) • 5.14 kB
JavaScript
import { decomposeRsaPublicKey, composeRsaPublicKey } from '../raw/keys';
import { decodeAsn1, encodeAsn1 } from '../../util/asn1-encoder';
import { EcParameters } from '../../util/asn1-entities';
import { decodeEcPoint, encodeEcPoint } 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 decomposeRsaSubjectPublicKeyInfo = subjectPublicKeyInfo => {
const {
algorithm,
publicKey: publicKeyAsn1
} = subjectPublicKeyInfo;
const keyAlgorithm = {
id: OIDS[algorithm.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 '${algorithm.id}'`);
}
const {
keyData
} = decomposeRsaPublicKey(publicKeyAsn1.data);
return {
keyAlgorithm: {
id: OIDS[algorithm.id]
},
keyData
};
};
const composeRsaSubjectPublicKeyInfo = (keyAlgorithm, keyData) => {
const rsaPublicKeyAsn1 = composeRsaPublicKey(keyAlgorithm, keyData);
return {
algorithm: {
id: FLIPPED_OIDS[keyAlgorithm.id],
parameters: hexStringToUint8Array('0500')
},
publicKey: {
unused: 0,
data: rsaPublicKeyAsn1
}
};
};
const decomposeEcSubjectPublicKeyInfo = subjectPublicKeyInfo => {
const {
algorithm,
publicKey
} = subjectPublicKeyInfo;
const ecParameters = decodeAsn1(algorithm.parameters, EcParameters); // Validate parameters
/* istanbul ignore if */
if (ecParameters.type !== 'namedCurve') {
throw new UnsupportedAlgorithmError('Only EC named curves are supported');
} // 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 (public key)
const {
x,
y
} = decodeEcPoint(namedCurve, publicKey.data);
return {
keyAlgorithm: {
id: 'ec-public-key',
namedCurve
},
keyData: {
x,
y
}
};
};
const composeEcSubjectPublicKeyInfo = (keyAlgorithm, keyData) => {
// Validate named curve
const namedCurveOid = FLIPPED_OIDS[keyAlgorithm.namedCurve];
if (!namedCurveOid) {
throw new UnsupportedAlgorithmError(`Unsupported named curve '${keyAlgorithm.namedCurve}'`);
} // Encode point (public key)
const encodedPoint = encodeEcPoint(keyAlgorithm.namedCurve, keyData.x, keyData.y);
const ecParametersAsn1 = encodeAsn1({
type: 'namedCurve',
value: namedCurveOid
}, EcParameters);
return {
algorithm: {
id: FLIPPED_OIDS[keyAlgorithm.id],
parameters: ecParametersAsn1
},
publicKey: {
unused: 0,
data: encodedPoint
}
};
};
const decomposeEd25519SubjectPublicKeyInfo = subjectPublicKeyInfo => {
const {
algorithm,
publicKey
} = subjectPublicKeyInfo;
return {
keyAlgorithm: {
id: OIDS[algorithm.id]
},
keyData: {
bytes: publicKey.data
}
};
};
const composeEd25519SubjectPublicKeyInfo = (keyAlgorithm, keyData) => ({
algorithm: {
id: FLIPPED_OIDS[keyAlgorithm.id]
},
publicKey: {
unused: 0,
data: keyData.bytes
}
});
export const decomposeSubjectPublicKeyInfo = subjectPublicKeyInfo => {
const keyType = KEY_TYPES[OIDS[subjectPublicKeyInfo.algorithm.id]];
switch (keyType) {
case 'rsa':
return decomposeRsaSubjectPublicKeyInfo(subjectPublicKeyInfo);
case 'ec':
return decomposeEcSubjectPublicKeyInfo(subjectPublicKeyInfo);
case 'ed25519':
return decomposeEd25519SubjectPublicKeyInfo(subjectPublicKeyInfo);
default:
throw new UnsupportedAlgorithmError(`Unsupported key algorithm OID '${subjectPublicKeyInfo.algorithm.id}'`);
}
};
export const composeSubjectPublicKeyInfo = (keyAlgorithm, keyData) => {
const keyType = KEY_TYPES[keyAlgorithm.id];
switch (keyType) {
case 'rsa':
return composeRsaSubjectPublicKeyInfo(keyAlgorithm, keyData);
case 'ec':
return composeEcSubjectPublicKeyInfo(keyAlgorithm, keyData);
case 'ed25519':
return composeEd25519SubjectPublicKeyInfo(keyAlgorithm, keyData);
default:
throw new UnsupportedAlgorithmError(`Unsupported key algorithm id '${keyAlgorithm.id}'`);
}
};