UNPKG

react-native-quick-crypto

Version:

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

172 lines (163 loc) 5.12 kB
"use strict"; import { Buffer } from '@craftzdog/react-native-buffer'; import { NitroModules } from 'react-native-nitro-modules'; import { KeyObject } from './classes'; import { isCryptoKey } from './utils'; import { binaryLikeToArrayBuffer as toAB, isStringOrBuffer, KFormatType, KeyEncoding } from '../utils'; function prepareKey(key, isPublic) { // Already a KeyObject if (key instanceof KeyObject) { if (isPublic) { if (key.type === 'secret') { throw new Error('Cannot use secret key for signature verification'); } } else { if (key.type !== 'private') { throw new Error('Key must be a private key for signing'); } } return { keyObject: key }; } // CryptoKey - extract KeyObject if (isCryptoKey(key)) { const cryptoKey = key; return prepareKey(cryptoKey.keyObject, isPublic); } // Raw string or buffer - create KeyObject if (isStringOrBuffer(key)) { const isPem = typeof key === 'string' && key.includes('-----BEGIN'); const format = isPem ? KFormatType.PEM : undefined; const type = isPublic ? 'public' : 'private'; const keyData = toAB(key); const keyObject = KeyObject.createKeyObject(type, keyData, format); return { keyObject }; } // KeyInputObject with options if (typeof key === 'object' && 'key' in key) { const keyObj = key; const { key: data, format, type, padding, saltLength, dsaEncoding } = keyObj; // Nested KeyObject if (data instanceof KeyObject) { return { keyObject: data, options: { padding, saltLength, dsaEncoding } }; } // Nested CryptoKey if (isCryptoKey(data)) { return { keyObject: data.keyObject, options: { padding, saltLength, dsaEncoding } }; } if (!isStringOrBuffer(data)) { throw new Error('Invalid key data type'); } // Determine format const isPem = format === 'pem' || typeof data === 'string' && data.includes('-----BEGIN'); const kFormat = isPem ? KFormatType.PEM : format === 'der' ? KFormatType.DER : undefined; // Determine encoding type let kType; if (type === 'pkcs8') kType = KeyEncoding.PKCS8;else if (type === 'pkcs1') kType = KeyEncoding.PKCS1;else if (type === 'sec1') kType = KeyEncoding.SEC1;else if (type === 'spki') kType = KeyEncoding.SPKI; const keyType = isPublic ? 'public' : 'private'; // Always convert to ArrayBuffer to avoid Nitro bridge string truncation bug const originalLength = typeof data === 'string' ? data.length : data.byteLength; const keyData = toAB(data); console.log(`[prepareKey KeyInputObject] ${keyType} key, original length: ${originalLength}, ArrayBuffer size: ${keyData.byteLength}`); const keyObject = KeyObject.createKeyObject(keyType, keyData, kFormat, kType); return { keyObject, options: { padding, saltLength, dsaEncoding } }; } throw new Error('Invalid key input'); } function dsaEncodingToNumber(dsaEncoding) { if (dsaEncoding === 'der') return 0; if (dsaEncoding === 'ieee-p1363') return 1; return undefined; } export class Sign { constructor(algorithm) { this.handle = NitroModules.createHybridObject('SignHandle'); this.handle.init(algorithm); } update(data) { const dataBuffer = toAB(data); this.handle.update(dataBuffer); return this; } sign(privateKey, outputEncoding) { if (privateKey === null || privateKey === undefined) { throw new Error('Private key is required'); } const { keyObject, options } = prepareKey(privateKey, false); const signature = this.handle.sign(keyObject.handle, options?.padding, options?.saltLength, dsaEncodingToNumber(options?.dsaEncoding)); const buf = Buffer.from(signature); if (outputEncoding) { return buf.toString(outputEncoding); } return buf; } } export class Verify { constructor(algorithm) { this.handle = NitroModules.createHybridObject('VerifyHandle'); this.handle.init(algorithm); } update(data) { const dataBuffer = toAB(data); this.handle.update(dataBuffer); return this; } verify(publicKey, signature, signatureEncoding) { if (publicKey === null || publicKey === undefined) { throw new Error('Public key is required'); } const { keyObject, options } = prepareKey(publicKey, true); // Convert signature to ArrayBuffer let sigBuffer; if (signatureEncoding && typeof signature === 'string') { sigBuffer = toAB(Buffer.from(signature, signatureEncoding)); } else { sigBuffer = toAB(signature); } return this.handle.verify(keyObject.handle, sigBuffer, options?.padding, options?.saltLength, dsaEncodingToNumber(options?.dsaEncoding)); } } export function createSign(algorithm) { return new Sign(algorithm); } export function createVerify(algorithm) { return new Verify(algorithm); } //# sourceMappingURL=signVerify.js.map