react-native-quick-crypto
Version:
A fast implementation of Node's `crypto` module written in C/C++ JSI
157 lines (156 loc) • 5.32 kB
JavaScript
;
import { NitroModules } from 'react-native-nitro-modules';
import { binaryLikeToArrayBuffer as toAB, isStringOrBuffer, KFormatType, KeyEncoding } from '../utils';
import { isCryptoKey } from './utils';
import { KeyObject } from './classes';
import { constants } from '../constants';
function preparePublicCipherKey(key, isEncrypt) {
let keyObj;
let padding;
let oaepHash;
let oaepLabel;
if (key instanceof KeyObject) {
if (isEncrypt && key.type !== 'public') {
throw new Error('publicEncrypt requires a public key');
}
// publicDecrypt accepts both public and private keys (Node.js behavior)
// A private key contains the public components needed for verify_recover
keyObj = key;
} else if (isCryptoKey(key)) {
const cryptoKey = key;
keyObj = cryptoKey.keyObject;
} else if (isStringOrBuffer(key)) {
const data = toAB(key);
const isPem = typeof key === 'string' && key.includes('-----BEGIN');
const isPrivatePem = typeof key === 'string' && key.includes('-----BEGIN PRIVATE');
// publicDecrypt accepts both public and private keys (Node.js behavior)
if (!isEncrypt && isPrivatePem) {
keyObj = KeyObject.createKeyObject('private', data, KFormatType.PEM, KeyEncoding.PKCS8);
} else {
keyObj = KeyObject.createKeyObject('public', data, isPem ? KFormatType.PEM : KFormatType.DER, KeyEncoding.SPKI);
}
} else if (typeof key === 'object' && 'key' in key) {
const options = key;
const result = preparePublicCipherKey(options.key, isEncrypt);
keyObj = result.keyHandle;
padding = options.padding;
oaepHash = options.oaepHash;
if (options.oaepLabel) {
oaepLabel = toAB(options.oaepLabel);
}
} else {
throw new Error('Invalid key input');
}
return {
keyHandle: keyObj,
padding,
oaepHash,
oaepLabel
};
}
export function publicEncrypt(key, buffer) {
const {
keyHandle,
padding,
oaepHash,
oaepLabel
} = preparePublicCipherKey(key, true);
const rsaCipher = NitroModules.createHybridObject('RsaCipher');
const data = toAB(buffer);
const paddingMode = padding ?? constants.RSA_PKCS1_OAEP_PADDING;
const hashAlgorithm = oaepHash || 'SHA-256';
try {
const encrypted = rsaCipher.encrypt(keyHandle.handle, data, paddingMode, hashAlgorithm, oaepLabel);
return Buffer.from(encrypted);
} catch (error) {
throw new Error(`publicEncrypt failed: ${error.message}`);
}
}
export function publicDecrypt(key, buffer) {
const {
keyHandle,
padding
} = preparePublicCipherKey(key, false);
const rsaCipher = NitroModules.createHybridObject('RsaCipher');
const data = toAB(buffer);
const paddingMode = padding ?? constants.RSA_PKCS1_PADDING;
try {
const decrypted = rsaCipher.publicDecrypt(keyHandle.handle, data, paddingMode);
return Buffer.from(decrypted);
} catch (error) {
throw new Error(`publicDecrypt failed: ${error.message}`);
}
}
function preparePrivateCipherKey(key, isEncrypt) {
let keyObj;
let padding;
let oaepHash;
let oaepLabel;
if (key instanceof KeyObject) {
if (isEncrypt && key.type !== 'private') {
throw new Error('privateEncrypt requires a private key');
}
if (!isEncrypt && key.type !== 'private') {
throw new Error('privateDecrypt requires a private key');
}
keyObj = key;
} else if (isCryptoKey(key)) {
const cryptoKey = key;
keyObj = cryptoKey.keyObject;
} else if (isStringOrBuffer(key)) {
const data = toAB(key);
const isPem = typeof key === 'string' && key.includes('-----BEGIN');
keyObj = KeyObject.createKeyObject('private', data, isPem ? KFormatType.PEM : KFormatType.DER, KeyEncoding.PKCS8);
} else if (typeof key === 'object' && 'key' in key) {
const options = key;
const result = preparePrivateCipherKey(options.key, isEncrypt);
keyObj = result.keyHandle;
padding = options.padding;
oaepHash = options.oaepHash;
if (options.oaepLabel) {
oaepLabel = toAB(options.oaepLabel);
}
} else {
throw new Error('Invalid key input');
}
return {
keyHandle: keyObj,
padding,
oaepHash,
oaepLabel
};
}
export function privateEncrypt(key, buffer) {
const {
keyHandle,
padding
} = preparePrivateCipherKey(key, true);
const rsaCipher = NitroModules.createHybridObject('RsaCipher');
const data = toAB(buffer);
const paddingMode = padding ?? constants.RSA_PKCS1_PADDING;
try {
const encrypted = rsaCipher.privateEncrypt(keyHandle.handle, data, paddingMode);
return Buffer.from(encrypted);
} catch (error) {
throw new Error(`privateEncrypt failed: ${error.message}`);
}
}
export function privateDecrypt(key, buffer) {
const {
keyHandle,
padding,
oaepHash,
oaepLabel
} = preparePrivateCipherKey(key, false);
const rsaCipher = NitroModules.createHybridObject('RsaCipher');
const data = toAB(buffer);
const paddingMode = padding ?? constants.RSA_PKCS1_OAEP_PADDING;
const hashAlgorithm = oaepHash || 'SHA-256';
try {
const decrypted = rsaCipher.privateDecrypt(keyHandle.handle, data, paddingMode, hashAlgorithm, oaepLabel);
return Buffer.from(decrypted);
} catch (error) {
throw new Error(`privateDecrypt failed: ${error.message}`);
}
}
//# sourceMappingURL=publicCipher.js.map