UNPKG

react-native-quick-crypto

Version:

A fast implementation of Node's `crypto` module written in C/C++ JSI

246 lines (239 loc) 9.38 kB
"use strict"; import { AsymmetricKeyObject, CryptoKey, KeyObject, SecretKeyObject, PublicKeyObject, PrivateKeyObject } from './classes'; import { generateKeyPair, generateKeyPairSync } from './generateKeyPair'; import { createSign, createVerify, sign, verify, Sign, Verify } from './signVerify'; import { publicEncrypt, publicDecrypt, privateEncrypt, privateDecrypt } from './publicCipher'; import { isCryptoKey, parseKeyEncoding, parsePrivateKeyEncoding, parsePublicKeyEncoding } from './utils'; import { NitroModules } from 'react-native-nitro-modules'; import { binaryLikeToArrayBuffer as toAB, isStringOrBuffer, KFormatType, KeyEncoding, KeyType } from '../utils'; import { randomBytes } from '../random'; function isRawFormat(format) { return format === 'raw-public' || format === 'raw-private' || format === 'raw-seed'; } function createPublicKeyFromRaw(input) { if (input.format !== 'raw-public') { throw new Error('Invalid format for createPublicKey raw import'); } if (typeof input.asymmetricKeyType !== 'string') { throw new Error('options.asymmetricKeyType is required for raw key import'); } if (input.asymmetricKeyType === 'ec' && !input.namedCurve) { throw new Error('options.namedCurve is required for EC raw key import'); } const handle = NitroModules.createHybridObject('KeyObjectHandle'); handle.initRawPublic(input.asymmetricKeyType, toAB(input.key), input.namedCurve); return new PublicKeyObject(handle); } function createPrivateKeyFromRaw(input) { if (input.format !== 'raw-private' && input.format !== 'raw-seed') { throw new Error('Invalid format for createPrivateKey raw import'); } if (typeof input.asymmetricKeyType !== 'string') { throw new Error('options.asymmetricKeyType is required for raw key import'); } if (input.asymmetricKeyType === 'ec' && !input.namedCurve) { throw new Error('options.namedCurve is required for EC raw key import'); } const handle = NitroModules.createHybridObject('KeyObjectHandle'); if (input.format === 'raw-seed') { handle.initRawSeed(input.asymmetricKeyType, toAB(input.key)); } else { handle.initRawPrivate(input.asymmetricKeyType, toAB(input.key), input.namedCurve); } return new PrivateKeyObject(handle); } function createSecretKey(key) { const keyBuffer = toAB(key); return KeyObject.createKeyObject('secret', keyBuffer); } function prepareAsymmetricKey(key, isPublic) { if (key instanceof KeyObject) { if (isPublic) { // createPublicKey can accept either a public key or extract public from private if (key.type === 'secret') { throw new Error('Cannot create public key from secret key'); } // Export as SPKI (public key format) - works for both public and private keys const exported = key.handle.exportKey(KFormatType.DER, KeyEncoding.SPKI); return { data: exported, format: 'der', type: 'spki' }; } else { // createPrivateKey requires a private key if (key.type !== 'private') { throw new Error('Key must be a private key'); } const exported = key.handle.exportKey(KFormatType.DER, KeyEncoding.PKCS8); return { data: exported, format: 'der', type: 'pkcs8' }; } } if (isCryptoKey(key)) { const cryptoKey = key; return prepareAsymmetricKey(cryptoKey.keyObject, isPublic); } if (isStringOrBuffer(key)) { // Detect PEM format from string content const isPem = typeof key === 'string' && key.includes('-----BEGIN'); return { data: toAB(key), format: isPem ? 'pem' : undefined }; } if (typeof key === 'object' && 'key' in key) { const keyObj = key; const { key: data, format, type, passphrase } = keyObj; const passphraseAB = passphrase !== undefined ? toAB(passphrase) : undefined; if (data instanceof KeyObject) { return prepareAsymmetricKey(data, isPublic); } if (isCryptoKey(data)) { return prepareAsymmetricKey(data.keyObject, isPublic); } if (!isStringOrBuffer(data)) { throw new Error('Invalid key data type'); } // For PEM format with string data, convert to ArrayBuffer if ((format === 'pem' || typeof data === 'string' && data.includes('-----BEGIN')) && typeof data === 'string') { return { data: toAB(data), format: 'pem', type, passphrase: passphraseAB }; } // Filter to only 'pem' or 'der' — JWK and raw formats are handled // separately via dedicated paths. const filteredFormat = format === 'pem' || format === 'der' ? format : undefined; return { data: toAB(data), format: filteredFormat, type, passphrase: passphraseAB }; } throw new Error('Invalid key input'); } function createPublicKey(key) { if (typeof key === 'object' && 'key' in key && isRawFormat(key.format)) { if (key.format !== 'raw-public') { throw new Error(`Invalid format ${key.format} for createPublicKey — only 'raw-public' is allowed`); } return createPublicKeyFromRaw(key); } if (typeof key === 'object' && 'key' in key && key.format === 'jwk') { const handle = NitroModules.createHybridObject('KeyObjectHandle'); const keyType = handle.initJwk(key.key); if (keyType === undefined) { throw new Error('Failed to import JWK'); } if (keyType === KeyType.PRIVATE) { // Extract public from private const exported = handle.exportKey(KFormatType.DER, KeyEncoding.SPKI); const pubHandle = NitroModules.createHybridObject('KeyObjectHandle'); pubHandle.init(KeyType.PUBLIC, exported, KFormatType.DER, KeyEncoding.SPKI); return new PublicKeyObject(pubHandle); } return new PublicKeyObject(handle); } const { data, format, type, passphrase } = prepareAsymmetricKey(key, true); // Map format string to KFormatType enum let kFormat; if (format === 'pem') kFormat = KFormatType.PEM;else if (format === 'der') kFormat = KFormatType.DER; // Map type string to KeyEncoding enum let kType; if (type === 'spki') kType = KeyEncoding.SPKI;else if (type === 'pkcs1') kType = KeyEncoding.PKCS1; return KeyObject.createKeyObject('public', data, kFormat, kType, passphrase); } function createPrivateKey(key) { if (typeof key === 'object' && 'key' in key && isRawFormat(key.format)) { if (key.format === 'raw-public') { throw new Error("Invalid format 'raw-public' for createPrivateKey"); } return createPrivateKeyFromRaw(key); } if (typeof key === 'object' && 'key' in key && key.format === 'jwk') { const handle = NitroModules.createHybridObject('KeyObjectHandle'); const keyType = handle.initJwk(key.key); if (keyType === undefined || keyType !== KeyType.PRIVATE) { throw new Error('Failed to import private key from JWK'); } return new PrivateKeyObject(handle); } const { data, format, type, passphrase } = prepareAsymmetricKey(key, false); // Map format string to KFormatType enum let kFormat; if (format === 'pem') kFormat = KFormatType.PEM;else if (format === 'der') kFormat = KFormatType.DER; // Map type string to KeyEncoding enum let kType; if (type === 'pkcs8') kType = KeyEncoding.PKCS8;else if (type === 'pkcs1') kType = KeyEncoding.PKCS1;else if (type === 'sec1') kType = KeyEncoding.SEC1; return KeyObject.createKeyObject('private', data, kFormat, kType, passphrase); } function generateKeySync(type, options) { if (typeof type !== 'string') { throw new TypeError('The "type" argument must be a string'); } if (typeof options !== 'object' || options === null) { throw new TypeError('The "options" argument must be an object'); } const { length } = options; if (typeof length !== 'number' || !Number.isInteger(length)) { throw new TypeError('The "options.length" property must be an integer'); } switch (type) { case 'hmac': if (length < 8 || length > 2 ** 31 - 1) { throw new RangeError('The "options.length" property must be >= 8 and <= 2147483647'); } break; case 'aes': if (length !== 128 && length !== 192 && length !== 256) { throw new RangeError('The "options.length" property must be 128, 192, or 256'); } break; default: throw new TypeError(`The "type" argument must be 'aes' or 'hmac'. Received '${type}'`); } const keyBytes = length / 8; const keyMaterial = randomBytes(keyBytes); return createSecretKey(keyMaterial); } function generateKey(type, options, callback) { if (typeof callback !== 'function') { throw new TypeError('The "callback" argument must be a function'); } try { const key = generateKeySync(type, options); process.nextTick(callback, null, key); } catch (err) { process.nextTick(callback, err); } } export { // Node Public API createSecretKey, createPublicKey, createPrivateKey, CryptoKey, generateKey, generateKeySync, generateKeyPair, generateKeyPairSync, AsymmetricKeyObject, KeyObject, createSign, createVerify, sign, verify, Sign, Verify, publicEncrypt, publicDecrypt, privateEncrypt, privateDecrypt, // Node Internal API parsePublicKeyEncoding, parsePrivateKeyEncoding, parseKeyEncoding, SecretKeyObject, PublicKeyObject, PrivateKeyObject, isCryptoKey }; //# sourceMappingURL=index.js.map