react-native-quick-crypto
Version:
A fast implementation of Node's `crypto` module written in C/C++ JSI
248 lines (241 loc) • 9.31 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.rsaKeyGenerate = exports.rsaImportKey = exports.rsaExportKey = exports.rsaCipher = exports.RSAKeyVariant = void 0;
var _Cipher = require("./NativeQuickCrypto/Cipher");
var _Cipher2 = require("./Cipher");
var _NativeQuickCrypto = require("./NativeQuickCrypto/NativeQuickCrypto");
var _Utils = require("./Utils");
var _keys = require("./keys");
// TODO: keep in in sync with C++ side (cpp/Cipher/MGLRsa.h)
let RSAKeyVariant = exports.RSAKeyVariant = /*#__PURE__*/function (RSAKeyVariant) {
RSAKeyVariant[RSAKeyVariant["RSA_SSA_PKCS1_v1_5"] = 0] = "RSA_SSA_PKCS1_v1_5";
RSAKeyVariant[RSAKeyVariant["RSA_PSS"] = 1] = "RSA_PSS";
RSAKeyVariant[RSAKeyVariant["RSA_OAEP"] = 2] = "RSA_OAEP";
return RSAKeyVariant;
}({});
function verifyAcceptableRsaKeyUse(name, isPublic, usages) {
let checkSet;
switch (name) {
case 'RSA-OAEP':
checkSet = isPublic ? ['encrypt', 'wrapKey'] : ['decrypt', 'unwrapKey'];
break;
case 'RSA-PSS':
// Fall through
case 'RSASSA-PKCS1-v1_5':
checkSet = isPublic ? ['verify'] : ['sign'];
break;
default:
throw (0, _Utils.lazyDOMException)('The algorithm is not supported', 'NotSupportedError');
}
if ((0, _Utils.hasAnyNotIn)(usages, checkSet)) {
throw (0, _Utils.lazyDOMException)(`Unsupported key usage for an ${name} key`, 'SyntaxError');
}
}
const rsaOaepCipher = (mode, key, data, {
label
}) => {
const type = mode === _keys.CipherOrWrapMode.kWebCryptoCipherEncrypt ? 'public' : 'private';
if (key.type !== type) {
throw (0, _Utils.lazyDOMException)('The requested operation is not valid for the provided key', 'InvalidAccessError');
}
if (label !== undefined) {
(0, _Utils.validateMaxBufferLength)(label, 'algorithm.label');
}
return _NativeQuickCrypto.NativeQuickCrypto.webcrypto.rsaCipher(mode, key.keyObject.handle, data, RSAKeyVariant.RSA_OAEP, (0, _Utils.normalizeHashName)(key.algorithm.hash), label !== undefined ? (0, _Utils.bufferLikeToArrayBuffer)(label) : undefined);
};
const rsaCipher = exports.rsaCipher = rsaOaepCipher;
const rsaKeyGenerate = async (algorithm, extractable, keyUsages) => {
const {
name,
modulusLength,
publicExponent,
hash: rawHash
} = algorithm;
const hash = (0, _Utils.normalizeHashName)(rawHash);
// const usageSet = new SafeSet(keyUsages);
const publicExponentConverted = (0, _Utils.bigIntArrayToUnsignedInt)(publicExponent);
if (publicExponentConverted === undefined) {
throw (0, _Utils.lazyDOMException)('The publicExponent must be equivalent to an unsigned 32-bit value', 'OperationError');
}
switch (name) {
case 'RSA-OAEP':
if ((0, _Utils.hasAnyNotIn)(keyUsages, ['encrypt', 'decrypt', 'wrapKey', 'unwrapKey'])) {
throw (0, _Utils.lazyDOMException)('Unsupported key usage for a RSA key', 'SyntaxError');
}
break;
default:
if ((0, _Utils.hasAnyNotIn)(keyUsages, ['sign', 'verify'])) {
throw (0, _Utils.lazyDOMException)('Unsupported key usage for a RSA key', 'SyntaxError');
}
}
const [err, keypair] = await (0, _Cipher2.generateKeyPairPromise)('rsa', {
modulusLength,
publicExponent: publicExponentConverted
});
if (err) {
throw (0, _Utils.lazyDOMException)('The operation failed for an operation-specific reason', {
name: 'OperationError',
cause: err
});
}
const keyAlgorithm = {
name,
modulusLength,
publicExponent: publicExponentConverted,
hash
};
let publicUsages = [];
let privateUsages = [];
switch (name) {
case 'RSA-OAEP':
{
publicUsages = (0, _Utils.getUsagesUnion)(keyUsages, 'encrypt', 'wrapKey');
privateUsages = (0, _Utils.getUsagesUnion)(keyUsages, 'decrypt', 'unwrapKey');
break;
}
default:
{
publicUsages = (0, _Utils.getUsagesUnion)(keyUsages, 'verify');
privateUsages = (0, _Utils.getUsagesUnion)(keyUsages, 'sign');
break;
}
}
const pub = new _keys.PublicKeyObject(keypair?.publicKey);
const publicKey = new _keys.CryptoKey(pub, keyAlgorithm, publicUsages, true);
const priv = new _keys.PrivateKeyObject(keypair?.privateKey);
const privateKey = new _keys.CryptoKey(priv, keyAlgorithm, privateUsages, extractable);
return {
publicKey,
privateKey
};
};
exports.rsaKeyGenerate = rsaKeyGenerate;
const rsaExportKey = (key, format) => {
const variant = _Cipher.KeyVariantLookup[key.algorithm.name];
if (variant === undefined) {
throw (0, _Utils.lazyDOMException)(`Unrecognized algorithm name '${key.algorithm.name}'`, 'NotSupportedError');
}
return _NativeQuickCrypto.NativeQuickCrypto.webcrypto.rsaExportKey(format, key.keyObject.handle, variant);
};
exports.rsaExportKey = rsaExportKey;
const rsaImportKey = (format, keyData, algorithm, extractable, keyUsages) => {
// const usagesSet = new SafeSet(keyUsages);
let keyObject;
switch (format) {
case 'spki':
{
verifyAcceptableRsaKeyUse(algorithm.name, true, keyUsages);
try {
keyObject = (0, _keys.createPublicKey)({
key: keyData,
format: 'der',
type: 'spki'
});
} catch (err) {
throw (0, _Utils.lazyDOMException)('Invalid keyData', {
name: 'DataError',
cause: err
});
}
break;
}
// case 'pkcs8': {
// verifyAcceptableRsaKeyUse(algorithm.name, false, keyUsages);
// try {
// keyObject = createPrivateKey({
// key: keyData,
// format: 'der',
// type: 'pkcs8',
// });
// } catch (err) {
// throw lazyDOMException('Invalid keyData', {
// name: 'DataError',
// cause: err,
// });
// }
// break;
// }
case 'jwk':
{
const data = keyData;
if (!data.kty) {
throw (0, _Utils.lazyDOMException)('Invalid keyData', 'DataError');
}
if (data.kty !== 'RSA') throw (0, _Utils.lazyDOMException)('Invalid JWK "kty" Parameter', 'DataError');
verifyAcceptableRsaKeyUse(algorithm.name, data.d === undefined, keyUsages);
if (keyUsages.length > 0 && data.use !== undefined) {
const checkUse = algorithm.name === 'RSA-OAEP' ? 'enc' : 'sig';
if (data.use !== checkUse) throw (0, _Utils.lazyDOMException)('Invalid JWK "use" Parameter', 'DataError');
}
(0, _Utils.validateKeyOps)(data.key_ops, keyUsages);
if (data.ext !== undefined && data.ext === false && extractable === true) {
throw (0, _Utils.lazyDOMException)('JWK "ext" Parameter and extractable mismatch', 'DataError');
}
if (data.alg !== undefined) {
const hash = (0, _Utils.normalizeHashName)(data.alg, _Utils.HashContext.WebCrypto);
if (hash !== algorithm.hash) throw (0, _Utils.lazyDOMException)('JWK "alg" does not match the requested algorithm', 'DataError');
}
const handle = _NativeQuickCrypto.NativeQuickCrypto.webcrypto.createKeyObjectHandle();
const type = handle.initJwk(data);
if (type === undefined) throw (0, _Utils.lazyDOMException)('Invalid JWK', 'DataError');
keyObject = type === _keys.KeyType.Private ? new _keys.PrivateKeyObject(handle) : new _keys.PublicKeyObject(handle);
break;
}
default:
throw (0, _Utils.lazyDOMException)(`Unable to import RSA key with format ${format}`, 'NotSupportedError');
}
if (keyObject.asymmetricKeyType !== 'rsa') {
throw (0, _Utils.lazyDOMException)('Invalid key type', 'DataError');
}
const {
modulusLength,
publicExponent
} = keyObject.handle.keyDetail();
if (publicExponent === undefined) {
throw (0, _Utils.lazyDOMException)('publicExponent is undefined', 'DataError');
}
return new _keys.CryptoKey(keyObject, {
name: algorithm.name,
modulusLength,
publicExponent: new Uint8Array(publicExponent),
hash: algorithm.hash
}, keyUsages, extractable);
};
// function rsaSignVerify(key, data, { saltLength }, signature) {
// let padding;
// if (key.algorithm.name === 'RSA-PSS') {
// padding = RSA_PKCS1_PSS_PADDING;
// // TODO(@jasnell): Validate maximum size of saltLength
// // based on the key size:
// // Math.ceil((keySizeInBits - 1)/8) - digestSizeInBytes - 2
// validateInt32(saltLength, 'algorithm.saltLength', -2);
// }
// const mode = signature === undefined ? kSignJobModeSign : kSignJobModeVerify;
// const type = mode === kSignJobModeSign ? 'private' : 'public';
// if (key.type !== type)
// throw lazyDOMException(`Key must be a ${type} key`, 'InvalidAccessError');
// return jobPromise(() => new SignJob(
// kCryptoJobAsync,
// signature === undefined ? kSignJobModeSign : kSignJobModeVerify,
// key[kKeyObject][kHandle],
// undefined,
// undefined,
// undefined,
// data,
// normalizeHashName(key.algorithm.hash.name),
// saltLength,
// padding,
// undefined,
// signature));
// }
// module.exports = {
// rsaCipher: rsaOaepCipher,
// rsaExportKey,
// rsaImportKey,
// rsaKeyGenerate,
// rsaSignVerify,
// };
exports.rsaImportKey = rsaImportKey;
//# sourceMappingURL=rsa.js.map
;