react-native-quick-crypto
Version:
A fast implementation of Node's `crypto` module written in C/C++ JSI
168 lines (161 loc) • 5.91 kB
JavaScript
;
import { AsymmetricKeyObject, CryptoKey, KeyObject, SecretKeyObject, PublicKeyObject, PrivateKeyObject } from './classes';
import { generateKeyPair, generateKeyPairSync } from './generateKeyPair';
import { createSign, createVerify, Sign, Verify } from './signVerify';
import { publicEncrypt, publicDecrypt, privateEncrypt, privateDecrypt } from './publicCipher';
import { isCryptoKey, parseKeyEncoding, parsePrivateKeyEncoding, parsePublicKeyEncoding } from './utils';
import { binaryLikeToArrayBuffer as toAB, isStringOrBuffer, KFormatType, KeyEncoding } from '../utils';
import { randomBytes } from '../random';
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
} = keyObj;
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
};
}
// Filter out 'jwk' format - only 'pem' and 'der' are supported here
const filteredFormat = format === 'jwk' ? undefined : format;
return {
data: toAB(data),
format: filteredFormat,
type
};
}
throw new Error('Invalid key input');
}
function createPublicKey(key) {
const {
data,
format,
type
} = 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);
}
function createPrivateKey(key) {
const {
data,
format,
type
} = 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);
}
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, publicEncrypt, publicDecrypt, privateEncrypt, privateDecrypt,
// Node Internal API
parsePublicKeyEncoding, parsePrivateKeyEncoding, parseKeyEncoding, SecretKeyObject, PublicKeyObject, PrivateKeyObject, isCryptoKey };
//# sourceMappingURL=index.js.map