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
JavaScript
;
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