UNPKG

react-native-quick-crypto

Version:

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

219 lines (218 loc) 7.64 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MlKem = void 0; exports.decapsulate = decapsulate; exports.encapsulate = encapsulate; exports.mlkem_generateKeyPairWebCrypto = mlkem_generateKeyPairWebCrypto; var _reactNativeNitroModules = require("react-native-nitro-modules"); var _keys = require("./keys"); var _utils = require("./utils"); const ML_KEM_VARIANTS = { 'ml-kem-512': 'ML-KEM-512', 'ml-kem-768': 'ML-KEM-768', 'ml-kem-1024': 'ML-KEM-1024' }; function isMlKemKeyType(type) { return type in ML_KEM_VARIANTS; } function unpackEncapsulateResult(packed) { const view = new DataView(packed); const ciphertextLen = view.getUint32(0, true); const sharedKeyLen = view.getUint32(4, true); const headerSize = 8; const ciphertext = packed.slice(headerSize, headerSize + ciphertextLen); const sharedKey = packed.slice(headerSize + ciphertextLen, headerSize + ciphertextLen + sharedKeyLen); return { ciphertext, sharedKey }; } class MlKem { constructor(variant) { this.variant = variant; this.native = _reactNativeNitroModules.NitroModules.createHybridObject('MlKemKeyPair'); this.native.setVariant(variant); } async generateKeyPair() { await this.native.generateKeyPair(_utils.KFormatType.DER, _utils.KeyEncoding.SPKI, _utils.KFormatType.DER, _utils.KeyEncoding.PKCS8); } generateKeyPairSync() { this.native.generateKeyPairSync(_utils.KFormatType.DER, _utils.KeyEncoding.SPKI, _utils.KFormatType.DER, _utils.KeyEncoding.PKCS8); } getPublicKey() { return this.native.getPublicKey(); } getPrivateKey() { return this.native.getPrivateKey(); } setPublicKey(keyData, format, type) { this.native.setPublicKey(keyData, format, type); } setPrivateKey(keyData, format, type) { this.native.setPrivateKey(keyData, format, type); } async encapsulate() { const packed = await this.native.encapsulate(); return unpackEncapsulateResult(packed); } encapsulateSync() { const packed = this.native.encapsulateSync(); return unpackEncapsulateResult(packed); } async decapsulate(ciphertext) { return this.native.decapsulate(ciphertext); } decapsulateSync(ciphertext) { return this.native.decapsulateSync(ciphertext); } } exports.MlKem = MlKem; function prepareKey(key, isPublic) { if (key instanceof _keys.KeyObject) { if (isPublic) { if (key.type === 'secret') { throw new Error('Cannot use secret key for encapsulation'); } } else { if (key.type !== 'private') { throw new Error('Key must be a private key for decapsulation'); } } return { keyObject: key }; } if ((0, _keys.isCryptoKey)(key)) { const cryptoKey = key; return prepareKey(cryptoKey.keyObject, isPublic); } if ((0, _utils.isStringOrBuffer)(key)) { const isPem = typeof key === 'string' && key.includes('-----BEGIN'); const format = isPem ? _utils.KFormatType.PEM : undefined; const keyType = isPublic ? 'public' : 'private'; const keyData = (0, _utils.binaryLikeToArrayBuffer)(key); const keyObject = _keys.KeyObject.createKeyObject(keyType, keyData, format); return { keyObject }; } if (typeof key === 'object' && 'key' in key) { const keyObj = key; const { key: data, format, type } = keyObj; if (data instanceof _keys.KeyObject) { return { keyObject: data }; } if ((0, _keys.isCryptoKey)(data)) { return { keyObject: data.keyObject }; } if (!(0, _utils.isStringOrBuffer)(data)) { throw new Error('Invalid key data type'); } const isPem = format === 'pem' || typeof data === 'string' && data.includes('-----BEGIN'); const kFormat = isPem ? _utils.KFormatType.PEM : format === 'der' ? _utils.KFormatType.DER : undefined; let kType; if (type === 'pkcs8') kType = _utils.KeyEncoding.PKCS8;else if (type === 'pkcs1') kType = _utils.KeyEncoding.PKCS1;else if (type === 'sec1') kType = _utils.KeyEncoding.SEC1;else if (type === 'spki') kType = _utils.KeyEncoding.SPKI; const keyType = isPublic ? 'public' : 'private'; const keyData = (0, _utils.binaryLikeToArrayBuffer)(data); const keyObject = _keys.KeyObject.createKeyObject(keyType, keyData, kFormat, kType); return { keyObject }; } throw new Error('Invalid key input'); } function getVariantFromKey(keyObject) { const keyType = keyObject.handle.getAsymmetricKeyType(); if (!isMlKemKeyType(keyType)) { throw new Error(`Key is not an ML-KEM key. Got asymmetricKeyType: ${keyType}`); } return ML_KEM_VARIANTS[keyType]; } function encapsulate(key, callback) { const doEncapsulate = () => { if (key === null || key === undefined) { throw new Error('Public key is required for encapsulation'); } const { keyObject } = prepareKey(key, true); const variant = getVariantFromKey(keyObject); const mlkem = new MlKem(variant); const keyData = keyObject.handle.exportKey(_utils.KFormatType.DER, _utils.KeyEncoding.SPKI); mlkem.setPublicKey(keyData, _utils.KFormatType.DER, _utils.KeyEncoding.SPKI); return mlkem.encapsulateSync(); }; if (callback) { try { const result = doEncapsulate(); process.nextTick(callback, null, result); } catch (err) { process.nextTick(callback, err); } return; } return doEncapsulate(); } function decapsulate(key, ciphertext, callback) { const doDecapsulate = () => { if (key === null || key === undefined) { throw new Error('Private key is required for decapsulation'); } const { keyObject } = prepareKey(key, false); const variant = getVariantFromKey(keyObject); const mlkem = new MlKem(variant); const keyData = keyObject.handle.exportKey(_utils.KFormatType.DER, _utils.KeyEncoding.PKCS8); mlkem.setPrivateKey(keyData, _utils.KFormatType.DER, _utils.KeyEncoding.PKCS8); const ciphertextBuffer = (0, _utils.binaryLikeToArrayBuffer)(ciphertext); return mlkem.decapsulateSync(ciphertextBuffer); }; if (callback) { try { const result = doDecapsulate(); process.nextTick(callback, null, result); } catch (err) { process.nextTick(callback, err); } return; } return doDecapsulate(); } async function mlkem_generateKeyPairWebCrypto(variant, extractable, keyUsages) { if ((0, _utils.hasAnyNotIn)(keyUsages, ['encapsulateBits', 'encapsulateKey', 'decapsulateBits', 'decapsulateKey'])) { throw (0, _utils.lazyDOMException)(`Unsupported key usage for ${variant}`, 'SyntaxError'); } const publicUsages = (0, _utils.getUsagesUnion)(keyUsages, 'encapsulateBits', 'encapsulateKey'); const privateUsages = (0, _utils.getUsagesUnion)(keyUsages, 'decapsulateBits', 'decapsulateKey'); if (privateUsages.length === 0) { throw (0, _utils.lazyDOMException)('Usages cannot be empty', 'SyntaxError'); } const mlkem = new MlKem(variant); await mlkem.generateKeyPair(); const publicKeyData = mlkem.getPublicKey(); const privateKeyData = mlkem.getPrivateKey(); const pub = _keys.KeyObject.createKeyObject('public', publicKeyData, _utils.KFormatType.DER, _utils.KeyEncoding.SPKI); const publicKey = new _keys.CryptoKey(pub, { name: variant }, publicUsages, true); const priv = _keys.KeyObject.createKeyObject('private', privateKeyData, _utils.KFormatType.DER, _utils.KeyEncoding.PKCS8); const privateKey = new _keys.CryptoKey(priv, { name: variant }, privateUsages, extractable); return { publicKey, privateKey }; } //# sourceMappingURL=mlkem.js.map