react-native-quick-crypto
Version:
A fast implementation of Node's `crypto` module written in C/C++ JSI
280 lines (272 loc) • 9.07 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.SecretKeyObject = exports.PublicKeyObject = exports.PrivateKeyObject = exports.KeyObject = exports.CryptoKey = exports.AsymmetricKeyObject = void 0;
var _reactNativeBuffer = require("@craftzdog/react-native-buffer");
var _reactNativeNitroModules = require("react-native-nitro-modules");
var _utils = require("../utils");
var _utils2 = require("./utils");
class CryptoKey {
get [Symbol.toStringTag]() {
return 'CryptoKey';
}
constructor(keyObject, keyAlgorithm, keyUsages, keyExtractable) {
this.keyObject = keyObject;
this.keyAlgorithm = keyAlgorithm;
// Frozen so external code can't mutate `key.usages` (per WebCrypto spec).
this.keyUsages = Object.freeze((0, _utils.getSortedUsages)(keyUsages));
this.keyExtractable = keyExtractable;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
inspect(_depth, _options) {
throw new Error('CryptoKey.inspect is not implemented');
// if (depth < 0) return this;
// const opts = {
// ...options,
// depth: options.depth == null ? null : options.depth - 1,
// };
// return `CryptoKey ${inspect(
// {
// type: this.type,
// extractable: this.extractable,
// algorithm: this.algorithm,
// usages: this.usages,
// },
// opts
// )}`;
}
get type() {
// if (!(this instanceof CryptoKey)) throw new Error('Invalid CryptoKey');
return this.keyObject.type;
}
get extractable() {
return this.keyExtractable;
}
get algorithm() {
return this.keyAlgorithm;
}
get usages() {
return this.keyUsages;
}
}
exports.CryptoKey = CryptoKey;
class KeyObject {
get [Symbol.toStringTag]() {
return 'KeyObject';
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export(_options) {
// This is a placeholder and should be overridden by subclasses.
throw new Error('export() must be implemented by subclasses');
}
equals(otherKeyObject) {
if (!(otherKeyObject instanceof KeyObject)) {
throw new TypeError('otherKeyObject must be a KeyObject');
}
return this.handle.keyEquals(otherKeyObject.handle);
}
constructor(type, handleOrKey) {
if (type !== 'secret' && type !== 'public' && type !== 'private') throw new Error(`invalid KeyObject type: ${type}`);
if (handleOrKey instanceof ArrayBuffer) {
this.handle = _reactNativeNitroModules.NitroModules.createHybridObject('KeyObjectHandle');
let keyType;
switch (type) {
case 'public':
keyType = _utils.KeyType.PUBLIC;
break;
case 'private':
keyType = _utils.KeyType.PRIVATE;
break;
case 'secret':
keyType = _utils.KeyType.SECRET;
break;
default:
// Should not happen
throw new Error('invalid key type');
}
this.handle.init(keyType, handleOrKey);
} else {
this.handle = handleOrKey;
}
this.type = type;
}
static from(key) {
if (!(key instanceof CryptoKey)) {
throw new TypeError(`The "key" argument must be an instance of CryptoKey. Received ${typeof key}`);
}
return key.keyObject;
}
toCryptoKey(algorithm, extractable, keyUsages) {
return new CryptoKey(this, algorithm, keyUsages, extractable);
}
static createKeyObject(type, key, format, encoding, passphrase) {
if (type !== 'secret' && type !== 'public' && type !== 'private') throw new Error(`invalid KeyObject type: ${type}`);
const handle = _reactNativeNitroModules.NitroModules.createHybridObject('KeyObjectHandle');
let keyType;
switch (type) {
case 'public':
keyType = _utils.KeyType.PUBLIC;
break;
case 'private':
keyType = _utils.KeyType.PRIVATE;
break;
case 'secret':
keyType = _utils.KeyType.SECRET;
break;
default:
throw new Error('invalid key type');
}
handle.init(keyType, key, format, encoding, passphrase);
// For asymmetric keys, return the appropriate subclass
if (type === 'public' || type === 'private') {
try {
handle.getAsymmetricKeyType();
// If we get here, it's an asymmetric key - return the appropriate subclass
if (type === 'public') {
return new PublicKeyObject(handle);
} else {
return new PrivateKeyObject(handle);
}
} catch {
// Not an asymmetric key, fall through to regular KeyObject
}
}
// For secret keys, return SecretKeyObject
if (type === 'secret') {
return new SecretKeyObject(handle);
}
// Return regular KeyObject for symmetric keys or if asymmetric detection failed
return new KeyObject(type, handle);
}
getAsymmetricKeyType() {
return undefined;
}
getAsymmetricKeyDetails() {
return undefined;
}
}
exports.KeyObject = KeyObject;
class SecretKeyObject extends KeyObject {
constructor(handle) {
super('secret', handle);
}
get symmetricKeySize() {
return this.handle.getSymmetricKeySize();
}
export(options) {
if (options?.format === 'pem' || options?.format === 'jwk') {
throw new Error(`SecretKey export for ${options.format} is not supported`);
}
const key = this.handle.exportKey();
return _reactNativeBuffer.Buffer.from(key);
}
}
// const kAsymmetricKeyType = Symbol('kAsymmetricKeyType');
// const kAsymmetricKeyDetails = Symbol('kAsymmetricKeyDetails');
// function normalizeKeyDetails(details = {}) {
// if (details.publicExponent !== undefined) {
// return {
// ...details,
// publicExponent: bigIntArrayToUnsignedBigInt(
// new Uint8Array(details.publicExponent)
// ),
// };
// }
// return details;
// }
exports.SecretKeyObject = SecretKeyObject;
class AsymmetricKeyObject extends KeyObject {
constructor(type, handle) {
super(type, handle);
}
get asymmetricKeyType() {
if (!this._asymmetricKeyType) {
this._asymmetricKeyType = this.handle.getAsymmetricKeyType();
}
return this._asymmetricKeyType;
}
get asymmetricKeyDetails() {
if (!this._asymmetricKeyDetails) {
this._asymmetricKeyDetails = this.handle.keyDetail();
}
return this._asymmetricKeyDetails;
}
get namedCurve() {
return this.asymmetricKeyDetails?.namedCurve;
}
}
exports.AsymmetricKeyObject = AsymmetricKeyObject;
class PublicKeyObject extends AsymmetricKeyObject {
constructor(handle) {
super('public', handle);
}
export(options) {
if (options?.format === 'jwk') {
return this.handle.exportJwk({}, false);
}
if (options?.format === 'raw-public') {
if (this.asymmetricKeyType === 'ec') {
const pointType = options.type ?? 'uncompressed';
if (pointType !== 'compressed' && pointType !== 'uncompressed') {
throw new Error(`Invalid options.type for raw-public EC export: ${pointType}`);
}
return _reactNativeBuffer.Buffer.from(this.handle.exportECPublicRaw(pointType === 'compressed'));
}
return _reactNativeBuffer.Buffer.from(this.handle.exportRawPublic());
}
const {
format,
type
} = (0, _utils2.parsePublicKeyEncoding)(options, this.asymmetricKeyType);
if (typeof format !== 'number') {
throw new Error(`Unexpected format ${format} after raw-format dispatch`);
}
const key = this.handle.exportKey(format, typeof type === 'string' ? undefined : type);
const buffer = _reactNativeBuffer.Buffer.from(key);
if (options?.format === 'pem') {
return buffer.toString('utf-8');
}
return buffer;
}
}
exports.PublicKeyObject = PublicKeyObject;
class PrivateKeyObject extends AsymmetricKeyObject {
constructor(handle) {
super('private', handle);
}
export(options) {
if (options?.format === 'jwk') {
if (options.passphrase !== undefined) {
throw new Error('jwk does not support encryption');
}
return this.handle.exportJwk({}, false);
}
if (options?.format === 'raw-private') {
if (this.asymmetricKeyType === 'ec') {
return _reactNativeBuffer.Buffer.from(this.handle.exportECPrivateRaw());
}
return _reactNativeBuffer.Buffer.from(this.handle.exportRawPrivate());
}
if (options?.format === 'raw-seed') {
return _reactNativeBuffer.Buffer.from(this.handle.exportRawSeed());
}
const {
format,
type,
cipher,
passphrase
} = (0, _utils2.parsePrivateKeyEncoding)(options, this.asymmetricKeyType);
if (typeof format !== 'number') {
throw new Error(`Unexpected format ${format} after raw-format dispatch`);
}
const key = this.handle.exportKey(format, typeof type === 'string' ? undefined : type, cipher, passphrase);
const buffer = _reactNativeBuffer.Buffer.from(key);
if (options?.format === 'pem') {
return buffer.toString('utf-8');
}
return buffer;
}
}
exports.PrivateKeyObject = PrivateKeyObject;
//# sourceMappingURL=classes.js.map