/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
lib/internal/crypto/cipher.js
302 строки
9 KB
Adam Mcgrath
crypto: add mgf1Hash for RSA-OAEP
10 авг 2026, 02:06
10 авг 2026, 02:06
11423b1
Код
Авторство
О чём код?
'use strict'; const { FunctionPrototypeCall, NumberIsInteger, ObjectSetPrototypeOf, } = primordials; const { CipherBase, privateDecrypt: _privateDecrypt, privateEncrypt: _privateEncrypt, publicDecrypt: _publicDecrypt, publicEncrypt: _publicEncrypt, getCipherInfo: _getCipherInfo, } = internalBinding('crypto'); const { crypto: { RSA_PKCS1_OAEP_PADDING, RSA_PKCS1_PADDING, }, } = internalBinding('constants'); const { codes: { ERR_CRYPTO_INVALID_STATE, ERR_INVALID_ARG_TYPE, ERR_INVALID_ARG_VALUE, ERR_UNKNOWN_ENCODING, }, } = require('internal/errors'); const { validateEncoding, validateUint32, validateObject, validateString, } = require('internal/validators'); const { preparePrivateKey, preparePublicOrPrivateKey, prepareSecretKey, } = require('internal/crypto/keys'); const { getArrayBufferOrView, getStringOption, kHandle, } = require('internal/crypto/util'); const { isArrayBufferView, } = require('internal/util/types'); const LazyTransform = require('internal/streams/lazy_transform'); const { normalizeEncoding, kEmptyObject } = require('internal/util'); const { StringDecoder } = require('string_decoder'); function rsaFunctionFor(method, defaultPadding, keyType) { const keyName = keyType === 'private' ? 'privateKey' : undefined; return (key, buffer) => { const { format, type, data, passphrase, namedCurve } = keyType === 'private' ? preparePrivateKey(key, keyName) : preparePublicOrPrivateKey(key, keyName); const padding = key.padding || defaultPadding; const { oaepHash, mgf1Hash, encoding } = key; let { oaepLabel } = key; if (oaepHash !== undefined) validateString(oaepHash, 'key.oaepHash'); if (mgf1Hash !== undefined) validateString(mgf1Hash, 'key.mgf1Hash'); if (oaepLabel !== undefined) oaepLabel = getArrayBufferOrView(oaepLabel, 'key.oaepLabel', encoding); buffer = getArrayBufferOrView(buffer, 'buffer', encoding); return method(data, format, type, passphrase, namedCurve, buffer, padding, oaepHash, oaepLabel, mgf1Hash); }; } const publicEncrypt = rsaFunctionFor(_publicEncrypt, RSA_PKCS1_OAEP_PADDING, 'public'); const publicDecrypt = rsaFunctionFor(_publicDecrypt, RSA_PKCS1_PADDING, 'public'); const privateEncrypt = rsaFunctionFor(_privateEncrypt, RSA_PKCS1_PADDING, 'private'); const privateDecrypt = rsaFunctionFor(_privateDecrypt, RSA_PKCS1_OAEP_PADDING, 'private'); function getDecoder(decoder, encoding) { const normalizedEncoding = normalizeEncoding(encoding); decoder ||= new StringDecoder(encoding); if (decoder.encoding !== normalizedEncoding) { if (normalizedEncoding === undefined) { throw new ERR_UNKNOWN_ENCODING(encoding); } throw new ERR_INVALID_ARG_VALUE( 'outputEncoding', encoding, `cannot be changed from '${decoder.encoding}'`, ); } return decoder; } function getUIntOption(options, key) { let value; if (options && (value = options[key]) != null) { if (value >>> 0 !== value) throw new ERR_INVALID_ARG_VALUE(`options.${key}`, value); // Coerce -0 to +0. return value + 0; } return -1; } function createCipherBase(cipher, credential, options, isEncrypt, iv) { const authTagLength = getUIntOption(options, 'authTagLength'); this[kHandle] = new CipherBase(isEncrypt, cipher, credential, iv, authTagLength); this._decoder = null; FunctionPrototypeCall(LazyTransform, this, options); } function createCipherWithIV(cipher, key, options, isEncrypt, iv) { validateString(cipher, 'cipher'); const encoding = getStringOption(options, 'encoding'); key = prepareSecretKey(key, encoding); iv = iv === null ? null : getArrayBufferOrView(iv, 'iv'); FunctionPrototypeCall(createCipherBase, this, cipher, key, options, isEncrypt, iv); } // The Cipher class is part of the legacy Node.js crypto API. It exposes // a stream-based encryption/decryption model. For backwards compatibility // the Cipher class is defined using the legacy function syntax rather than // ES6 classes. function _transform(chunk, encoding, callback) { this.push(this[kHandle].update(chunk, encoding)); callback(); }; function _flush(callback) { try { this.push(this[kHandle].final()); } catch (e) { callback(e); return; } callback(); }; function update(data, inputEncoding, outputEncoding) { if (typeof data === 'string') { validateEncoding(data, inputEncoding); } else if (!isArrayBufferView(data)) { throw new ERR_INVALID_ARG_TYPE( 'data', ['string', 'Buffer', 'TypedArray', 'DataView'], data); } const ret = this[kHandle].update(data, inputEncoding); if (outputEncoding && outputEncoding !== 'buffer') { this._decoder = getDecoder(this._decoder, outputEncoding); return this._decoder.write(ret); } return ret; }; function final(outputEncoding) { const ret = this[kHandle].final(); if (outputEncoding && outputEncoding !== 'buffer') { this._decoder = getDecoder(this._decoder, outputEncoding); return this._decoder.end(ret); } return ret; }; function setAutoPadding(ap) { if (!this[kHandle].setAutoPadding(!!ap)) throw new ERR_CRYPTO_INVALID_STATE('setAutoPadding'); return this; }; function getAuthTag() { const ret = this[kHandle].getAuthTag(); if (ret === undefined) throw new ERR_CRYPTO_INVALID_STATE('getAuthTag'); return ret; }; function setAuthTag(tagbuf, encoding) { tagbuf = getArrayBufferOrView(tagbuf, 'buffer', encoding); if (!this[kHandle].setAuthTag(tagbuf)) throw new ERR_CRYPTO_INVALID_STATE('setAuthTag'); return this; } function setAAD(aadbuf, options) { const encoding = getStringOption(options, 'encoding'); const plaintextLength = getUIntOption(options, 'plaintextLength'); aadbuf = getArrayBufferOrView(aadbuf, 'aadbuf', encoding); if (!this[kHandle].setAAD(aadbuf, plaintextLength)) throw new ERR_CRYPTO_INVALID_STATE('setAAD'); return this; }; // The Cipheriv class is part of the legacy Node.js crypto API. It exposes // a stream-based encryption/decryption model. For backwards compatibility // the Cipheriv class is defined using the legacy function syntax rather than // ES6 classes. function Cipheriv(cipher, key, iv, options) { if (!(this instanceof Cipheriv)) return new Cipheriv(cipher, key, iv, options); FunctionPrototypeCall(createCipherWithIV, this, cipher, key, options, true, iv); } function addCipherPrototypeFunctions(constructor) { constructor.prototype._transform = _transform; constructor.prototype._flush = _flush; constructor.prototype.update = update; constructor.prototype.final = final; constructor.prototype.setAutoPadding = setAutoPadding; if (constructor === Cipheriv) { constructor.prototype.getAuthTag = getAuthTag; } else { constructor.prototype.setAuthTag = setAuthTag; } constructor.prototype.setAAD = setAAD; } ObjectSetPrototypeOf(Cipheriv.prototype, LazyTransform.prototype); ObjectSetPrototypeOf(Cipheriv, LazyTransform); addCipherPrototypeFunctions(Cipheriv); // The Decipheriv class is part of the legacy Node.js crypto API. It exposes // a stream-based encryption/decryption model. For backwards compatibility // the Decipheriv class is defined using the legacy function syntax rather than // ES6 classes. function Decipheriv(cipher, key, iv, options) { if (!(this instanceof Decipheriv)) return new Decipheriv(cipher, key, iv, options); FunctionPrototypeCall(createCipherWithIV, this, cipher, key, options, false, iv); } ObjectSetPrototypeOf(Decipheriv.prototype, LazyTransform.prototype); ObjectSetPrototypeOf(Decipheriv, LazyTransform); addCipherPrototypeFunctions(Decipheriv); const kMinNid = 1; const kMaxNid = 2_147_483_647; function getCipherInfo(nameOrNid, options = kEmptyObject) { validateObject(options, 'options'); let { keyLength, ivLength } = options; if (keyLength !== undefined) { validateUint32(keyLength, 'options.keyLength'); // Coerce -0 to +0. keyLength += 0; } if (ivLength !== undefined) { validateUint32(ivLength, 'options.ivLength'); // Coerce -0 to +0. ivLength += 0; } const type = typeof nameOrNid; if (type === 'string') { if (nameOrNid.length === 0) return undefined; return _getCipherInfo(nameOrNid, keyLength, ivLength); } else if (type === 'number') { if (!NumberIsInteger(nameOrNid) || nameOrNid < kMinNid || nameOrNid > kMaxNid) { return undefined; } return _getCipherInfo(nameOrNid, keyLength, ivLength); } throw new ERR_INVALID_ARG_TYPE( 'nameOrNid', ['string', 'number'], nameOrNid); } module.exports = { Cipheriv, Decipheriv, privateDecrypt, privateEncrypt, publicDecrypt, publicEncrypt, getCipherInfo, };