react-native-quick-crypto
Version:
A fast implementation of Node's `crypto` module written in C/C++ JSI
202 lines (193 loc) • 7.08 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Rsa = void 0;
exports.rsa_generateKeyPair = rsa_generateKeyPair;
exports.rsa_generateKeyPairNode = rsa_generateKeyPairNode;
exports.rsa_generateKeyPairNodeSync = rsa_generateKeyPairNodeSync;
var _reactNativeNitroModules = require("react-native-nitro-modules");
var _keys = require("./keys");
var _utils = require("./utils");
class Rsa {
constructor(modulusLength, publicExponent, hashAlgorithm) {
this.native = _reactNativeNitroModules.NitroModules.createHybridObject('RsaKeyPair');
this.native.setModulusLength(modulusLength);
this.native.setPublicExponent(publicExponent.buffer.slice(publicExponent.byteOffset, publicExponent.byteOffset + publicExponent.byteLength));
this.native.setHashAlgorithm(hashAlgorithm);
}
async generateKeyPair() {
await this.native.generateKeyPair();
return {
publicKey: this.native.getPublicKey(),
privateKey: this.native.getPrivateKey()
};
}
generateKeyPairSync() {
this.native.generateKeyPairSync();
return {
publicKey: this.native.getPublicKey(),
privateKey: this.native.getPrivateKey()
};
}
}
// Node API
exports.Rsa = Rsa;
async function rsa_generateKeyPair(algorithm, extractable, keyUsages) {
const {
name,
modulusLength,
publicExponent,
hash
} = algorithm;
// Validate parameters first
if (!modulusLength || modulusLength < 256) {
throw (0, _utils.lazyDOMException)('Invalid key length', 'OperationError');
}
if (!publicExponent || publicExponent.length === 0) {
throw (0, _utils.lazyDOMException)('Invalid public exponent', 'OperationError');
}
// Validate hash algorithm using existing validation function
let hashName;
try {
const normalizedHash = (0, _utils.normalizeHashName)(hash);
hashName = typeof hash === 'string' ? hash : hash?.name || normalizedHash;
} catch {
throw (0, _utils.lazyDOMException)('Invalid Hash Algorithm', 'NotSupportedError');
}
// Validate usages are not empty
if (keyUsages.length === 0) {
throw (0, _utils.lazyDOMException)('Usages cannot be empty', 'SyntaxError');
}
// Usage validation based on algorithm type
switch (name) {
case 'RSASSA-PKCS1-v1_5':
if ((0, _utils.hasAnyNotIn)(keyUsages, ['sign', 'verify'])) {
throw (0, _utils.lazyDOMException)(`Unsupported key usage for a ${name} key`, 'SyntaxError');
}
break;
case 'RSA-PSS':
if ((0, _utils.hasAnyNotIn)(keyUsages, ['sign', 'verify'])) {
throw (0, _utils.lazyDOMException)(`Unsupported key usage for a ${name} key`, 'SyntaxError');
}
break;
case 'RSA-OAEP':
if ((0, _utils.hasAnyNotIn)(keyUsages, ['encrypt', 'decrypt', 'wrapKey', 'unwrapKey'])) {
throw (0, _utils.lazyDOMException)(`Unsupported key usage for a ${name} key`, 'SyntaxError');
}
break;
default:
throw (0, _utils.lazyDOMException)('The algorithm is not supported', 'NotSupportedError');
}
// Split usages between public and private keys
let publicUsages = [];
let privateUsages = [];
switch (name) {
case 'RSASSA-PKCS1-v1_5':
case 'RSA-PSS':
publicUsages = (0, _utils.getUsagesUnion)(keyUsages, 'verify');
privateUsages = (0, _utils.getUsagesUnion)(keyUsages, 'sign');
break;
case 'RSA-OAEP':
publicUsages = (0, _utils.getUsagesUnion)(keyUsages, 'encrypt', 'wrapKey');
privateUsages = (0, _utils.getUsagesUnion)(keyUsages, 'decrypt', 'unwrapKey');
break;
}
// Validate that private key has usages for CryptoKeyPair
if (privateUsages.length === 0) {
throw (0, _utils.lazyDOMException)('Usages cannot be empty', 'SyntaxError');
}
const rsa = new Rsa(modulusLength, publicExponent, hashName);
await rsa.generateKeyPair();
const keyAlgorithm = {
name,
modulusLength,
publicExponent,
hash: {
name: hashName
}
};
// Create KeyObject instances using the standard createKeyObject method
const publicKeyData = rsa.native.getPublicKey();
const pub = _keys.KeyObject.createKeyObject('public', publicKeyData);
const publicKey = new _keys.CryptoKey(pub, keyAlgorithm, publicUsages, true);
const privateKeyData = rsa.native.getPrivateKey();
const priv = _keys.KeyObject.createKeyObject('private', privateKeyData);
const privateKey = new _keys.CryptoKey(priv, keyAlgorithm, privateUsages, extractable);
return {
publicKey,
privateKey
};
}
function rsa_prepareKeyGenParams(_type, options) {
if (!options) {
throw new Error('Options are required for RSA key generation');
}
const {
modulusLength,
publicExponent,
hash = 'sha256'
} = options;
if (!modulusLength || modulusLength < 256) {
throw new Error('Invalid modulus length');
}
const pubExp = publicExponent || 65537;
const pubExpBytes = new Uint8Array([pubExp >> 16 & 0xff, pubExp >> 8 & 0xff, pubExp & 0xff]);
const hashName = typeof hash === 'string' ? hash : hash;
return new Rsa(modulusLength, pubExpBytes, hashName);
}
function rsa_formatKeyPairOutput(rsa, encoding) {
const {
publicFormat,
publicType,
privateFormat,
privateType,
cipher,
passphrase
} = encoding;
const publicKeyData = rsa.native.getPublicKey();
const privateKeyData = rsa.native.getPrivateKey();
const pub = _keys.KeyObject.createKeyObject('public', publicKeyData);
const priv = _keys.KeyObject.createKeyObject('private', privateKeyData);
let publicKey;
let privateKey;
if (publicFormat === -1) {
publicKey = pub;
} else {
const format = publicFormat === _utils.KFormatType.PEM ? _utils.KFormatType.PEM : _utils.KFormatType.DER;
const keyEncoding = publicType === _utils.KeyEncoding.SPKI ? _utils.KeyEncoding.SPKI : _utils.KeyEncoding.PKCS1;
const exported = pub.handle.exportKey(format, keyEncoding);
if (format === _utils.KFormatType.PEM) {
publicKey = Buffer.from(new Uint8Array(exported)).toString('utf-8');
} else {
publicKey = exported;
}
}
if (privateFormat === -1) {
privateKey = priv;
} else {
const format = privateFormat === _utils.KFormatType.PEM ? _utils.KFormatType.PEM : _utils.KFormatType.DER;
const keyEncoding = privateType === _utils.KeyEncoding.PKCS8 ? _utils.KeyEncoding.PKCS8 : _utils.KeyEncoding.PKCS1;
const exported = priv.handle.exportKey(format, keyEncoding, cipher, passphrase);
if (format === _utils.KFormatType.PEM) {
privateKey = Buffer.from(new Uint8Array(exported)).toString('utf-8');
} else {
privateKey = exported;
}
}
return {
publicKey,
privateKey
};
}
async function rsa_generateKeyPairNode(type, options, encoding) {
const rsa = rsa_prepareKeyGenParams(type, options);
await rsa.generateKeyPair();
return rsa_formatKeyPairOutput(rsa, encoding);
}
function rsa_generateKeyPairNodeSync(type, options, encoding) {
const rsa = rsa_prepareKeyGenParams(type, options);
rsa.generateKeyPairSync();
return rsa_formatKeyPairOutput(rsa, encoding);
}
//# sourceMappingURL=rsa.js.map