UNPKG

react-native-quick-crypto

Version:

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

191 lines (169 loc) 5.18 kB
import { binaryLikeToArrayBuffer, isStringOrBuffer, KeyEncoding, KFormatType, } from '../utils'; import type { CryptoKeyPair, EncodingOptions } from '../utils'; import type { CryptoKey } from './classes'; // eslint-disable-next-line @typescript-eslint/no-explicit-any export const isCryptoKey = (obj: any): boolean => { return obj !== null && obj?.keyObject !== undefined; }; export function getCryptoKeyPair( key: CryptoKey | CryptoKeyPair, ): CryptoKeyPair { if ('publicKey' in key && 'privateKey' in key) return key; throw new Error('Invalid CryptoKeyPair'); } /** * Parses the public key encoding based on an object. keyType must be undefined * when this is used to parse an input encoding and must be a valid key type if * used to parse an output encoding. */ export function parsePublicKeyEncoding( enc: EncodingOptions, keyType: string | undefined, objName?: string, ) { return parseKeyEncoding(enc, keyType, keyType ? true : undefined, objName); } /** * Parses the private key encoding based on an object. keyType must be undefined * when this is used to parse an input encoding and must be a valid key type if * used to parse an output encoding. */ export function parsePrivateKeyEncoding( enc: EncodingOptions, keyType: string | undefined, objName?: string, ) { return parseKeyEncoding(enc, keyType, false, objName); } export function parseKeyEncoding( enc: EncodingOptions, keyType?: string, isPublic?: boolean, objName?: string, ) { // validateObject(enc, 'options'); const isInput = keyType === undefined; const { format, type } = parseKeyFormatAndType( enc, keyType, isPublic, objName, ); let cipher, passphrase, encoding; if (isPublic !== true) { ({ cipher, passphrase, encoding } = enc); if (!isInput) { if (cipher != null) { if (typeof cipher !== 'string') throw new Error( `Invalid argument ${option('cipher', objName)}: ${cipher}`, ); if ( format === KFormatType.DER && (type === KeyEncoding.PKCS1 || type === KeyEncoding.SEC1) ) { throw new Error( `Incompatible key options ${encodingNames[type]} does not support encryption`, ); } } else if (passphrase !== undefined) { throw new Error( `invalid argument ${option('cipher', objName)}: ${cipher}`, ); } } if ( (isInput && passphrase !== undefined && !isStringOrBuffer(passphrase)) || (!isInput && cipher != null && !isStringOrBuffer(passphrase)) ) { throw new Error( `Invalid argument value ${option('passphrase', objName)}: ${passphrase}`, ); } } if (passphrase !== undefined) passphrase = binaryLikeToArrayBuffer(passphrase, encoding); return { format, type, cipher, passphrase }; } const encodingNames = { [KeyEncoding.PKCS1]: 'pkcs1', [KeyEncoding.PKCS8]: 'pkcs8', [KeyEncoding.SPKI]: 'spki', [KeyEncoding.SEC1]: 'sec1', }; function option(name: string, objName?: string) { return objName === undefined ? `options.${name}` : `options.${objName}.${name}`; } function parseKeyFormat( formatStr?: string, defaultFormat?: KFormatType, optionName?: string, ) { if (formatStr === undefined && defaultFormat !== undefined) return defaultFormat; else if (formatStr === 'pem') return KFormatType.PEM; else if (formatStr === 'der') return KFormatType.DER; else if (formatStr === 'jwk') return KFormatType.JWK; throw new Error(`Invalid key format str: ${optionName}`); } function parseKeyType( typeStr: string | undefined, required: boolean, keyType: string | undefined, isPublic: boolean | undefined, optionName: string, ): KeyEncoding | undefined { if (typeStr === undefined && !required) { return undefined; } else if (typeStr === 'pkcs1') { if (keyType !== undefined && keyType !== 'rsa') { throw new Error( `Crypto incompatible key options: ${typeStr} can only be used for RSA keys`, ); } return KeyEncoding.PKCS1; } else if (typeStr === 'spki' && isPublic !== false) { return KeyEncoding.SPKI; } else if (typeStr === 'pkcs8' && isPublic !== true) { return KeyEncoding.PKCS8; } else if (typeStr === 'sec1' && isPublic !== true) { if (keyType !== undefined && keyType !== 'ec') { throw new Error( `Incompatible key options ${typeStr} can only be used for EC keys`, ); } return KeyEncoding.SEC1; } throw new Error(`Invalid option ${optionName} - ${typeStr}`); } function parseKeyFormatAndType( enc: EncodingOptions, keyType?: string, isPublic?: boolean, objName?: string, ) { const { format: formatStr, type: typeStr } = enc; const isInput = keyType === undefined; const format = parseKeyFormat( formatStr, isInput ? KFormatType.PEM : undefined, option('format', objName), ); const isRequired = (!isInput || format === KFormatType.DER) && format !== KFormatType.JWK; const type = parseKeyType( typeStr, isRequired, keyType, isPublic, option('type', objName), ); return { format, type }; }