UNPKG

react-native-quick-crypto

Version:

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

171 lines (170 loc) 6.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.privateDecrypt = privateDecrypt; exports.privateEncrypt = privateEncrypt; exports.publicDecrypt = publicDecrypt; exports.publicEncrypt = publicEncrypt; var _reactNativeNitroModules = require("react-native-nitro-modules"); var _reactNativeBuffer = require("@craftzdog/react-native-buffer"); var _utils = require("../utils"); var _utils2 = require("./utils"); var _classes = require("./classes"); var _constants = require("../constants"); function preparePublicCipherKey(key, isEncrypt) { let keyObj; let padding; let oaepHash; let oaepLabel; if (key instanceof _classes.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 ((0, _utils2.isCryptoKey)(key)) { const cryptoKey = key; keyObj = cryptoKey.keyObject; } else if ((0, _utils.isStringOrBuffer)(key)) { const data = (0, _utils.binaryLikeToArrayBuffer)(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 = _classes.KeyObject.createKeyObject('private', data, _utils.KFormatType.PEM, _utils.KeyEncoding.PKCS8); } else { keyObj = _classes.KeyObject.createKeyObject('public', data, isPem ? _utils.KFormatType.PEM : _utils.KFormatType.DER, _utils.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 = (0, _utils.binaryLikeToArrayBuffer)(options.oaepLabel); } } else { throw new Error('Invalid key input'); } return { keyHandle: keyObj, padding, oaepHash, oaepLabel }; } function publicEncrypt(key, buffer) { const { keyHandle, padding, oaepHash, oaepLabel } = preparePublicCipherKey(key, true); const rsaCipher = _reactNativeNitroModules.NitroModules.createHybridObject('RsaCipher'); const data = (0, _utils.binaryLikeToArrayBuffer)(buffer); const paddingMode = padding ?? _constants.constants.RSA_PKCS1_OAEP_PADDING; const hashAlgorithm = oaepHash || 'sha1'; try { const encrypted = rsaCipher.encrypt(keyHandle.handle, data, paddingMode, hashAlgorithm, oaepLabel); return _reactNativeBuffer.Buffer.from(encrypted); } catch (error) { throw new Error(`publicEncrypt failed: ${error.message}`); } } function publicDecrypt(key, buffer) { const { keyHandle, padding } = preparePublicCipherKey(key, false); const rsaCipher = _reactNativeNitroModules.NitroModules.createHybridObject('RsaCipher'); const data = (0, _utils.binaryLikeToArrayBuffer)(buffer); const paddingMode = padding ?? _constants.constants.RSA_PKCS1_PADDING; try { const decrypted = rsaCipher.publicDecrypt(keyHandle.handle, data, paddingMode); return _reactNativeBuffer.Buffer.from(decrypted); } catch { // Bleichenbacher mitigation: surface a single, content-independent error // for every decrypt failure so an attacker cannot use error-message // differences as a padding oracle. The native side already collapses its // OpenSSL error codes to the same opaque message; we drop it here too // rather than re-leaking it via string interpolation. throw new Error('publicDecrypt failed'); } } function preparePrivateCipherKey(key, isEncrypt) { let keyObj; let padding; let oaepHash; let oaepLabel; if (key instanceof _classes.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 ((0, _utils2.isCryptoKey)(key)) { const cryptoKey = key; keyObj = cryptoKey.keyObject; } else if ((0, _utils.isStringOrBuffer)(key)) { const data = (0, _utils.binaryLikeToArrayBuffer)(key); const isPem = typeof key === 'string' && key.includes('-----BEGIN'); keyObj = _classes.KeyObject.createKeyObject('private', data, isPem ? _utils.KFormatType.PEM : _utils.KFormatType.DER, _utils.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 = (0, _utils.binaryLikeToArrayBuffer)(options.oaepLabel); } } else { throw new Error('Invalid key input'); } return { keyHandle: keyObj, padding, oaepHash, oaepLabel }; } function privateEncrypt(key, buffer) { const { keyHandle, padding } = preparePrivateCipherKey(key, true); const rsaCipher = _reactNativeNitroModules.NitroModules.createHybridObject('RsaCipher'); const data = (0, _utils.binaryLikeToArrayBuffer)(buffer); const paddingMode = padding ?? _constants.constants.RSA_PKCS1_PADDING; try { const encrypted = rsaCipher.privateEncrypt(keyHandle.handle, data, paddingMode); return _reactNativeBuffer.Buffer.from(encrypted); } catch (error) { throw new Error(`privateEncrypt failed: ${error.message}`); } } function privateDecrypt(key, buffer) { const { keyHandle, padding, oaepHash, oaepLabel } = preparePrivateCipherKey(key, false); const rsaCipher = _reactNativeNitroModules.NitroModules.createHybridObject('RsaCipher'); const data = (0, _utils.binaryLikeToArrayBuffer)(buffer); const paddingMode = padding ?? _constants.constants.RSA_PKCS1_OAEP_PADDING; const hashAlgorithm = oaepHash || 'sha1'; try { const decrypted = rsaCipher.privateDecrypt(keyHandle.handle, data, paddingMode, hashAlgorithm, oaepLabel); return _reactNativeBuffer.Buffer.from(decrypted); } catch { // Bleichenbacher mitigation — see publicDecrypt above. throw new Error('privateDecrypt failed'); } } //# sourceMappingURL=publicCipher.js.map