crypto: remove CipherBase::Init

As far as I can tell, the `iv` parameter can never be `undefined` (but
it can be `null`!), so this code appears to have been dead since
Node.js 22.

This change removes dead code and adds a tiny test case for passing
`undefined` as the IV.

Refs: https://github.com/nodejs/node/pull/50973
PR-URL: https://github.com/nodejs/node/pull/57787
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
This commit is contained in:
Tobias Nießen 2025-04-10 00:13:44 +02:00 committed by GitHub
parent 038d82980a
commit 9bbbe60f6b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 9 additions and 74 deletions

View File

@ -115,11 +115,7 @@ function getUIntOption(options, key) {
function createCipherBase(cipher, credential, options, decipher, iv) {
const authTagLength = getUIntOption(options, 'authTagLength');
this[kHandle] = new CipherBase(decipher);
if (iv === undefined) {
this[kHandle].init(cipher, credential, authTagLength);
} else {
this[kHandle].initiv(cipher, credential, iv, authTagLength);
}
this[kHandle].initiv(cipher, credential, iv, authTagLength);
this._decoder = null;
ReflectApply(LazyTransform, this, [options]);

View File

@ -231,7 +231,6 @@ void CipherBase::Initialize(Environment* env, Local<Object> target) {
t->InstanceTemplate()->SetInternalFieldCount(CipherBase::kInternalFieldCount);
SetProtoMethod(isolate, t, "init", Init);
SetProtoMethod(isolate, t, "initiv", InitIv);
SetProtoMethod(isolate, t, "update", Update);
SetProtoMethod(isolate, t, "final", Final);
@ -275,7 +274,6 @@ void CipherBase::RegisterExternalReferences(
ExternalReferenceRegistry* registry) {
registry->Register(New);
registry->Register(Init);
registry->Register(InitIv);
registry->Register(Update);
registry->Register(Final);
@ -347,69 +345,6 @@ void CipherBase::CommonInit(std::string_view cipher_type,
}
}
void CipherBase::Init(std::string_view cipher_type,
const ArrayBufferOrViewContents<unsigned char>& key_buf,
unsigned int auth_tag_len) {
HandleScope scope(env()->isolate());
MarkPopErrorOnReturn mark_pop_error_on_return;
const auto cipher = Cipher::FromName(cipher_type);
if (!cipher) {
return THROW_ERR_CRYPTO_UNKNOWN_CIPHER(env());
}
unsigned char key[Cipher::MAX_KEY_LENGTH];
unsigned char iv[Cipher::MAX_IV_LENGTH];
ncrypto::Buffer<const unsigned char> keyBuf{
.data = key_buf.data(),
.len = key_buf.size(),
};
int key_len = cipher.bytesToKey(Digest::MD5, keyBuf, key, iv);
CHECK_NE(key_len, 0);
if (kind_ == kCipher &&
(cipher.isCtrMode() || cipher.isGcmMode() || cipher.isCcmMode())) {
// Ignore the return value (i.e. possible exception) because we are
// not calling back into JS anyway.
ProcessEmitWarning(env(),
"Use Cipheriv for counter mode of %s",
cipher_type);
}
CommonInit(cipher_type,
cipher,
key,
key_len,
iv,
cipher.getIvLength(),
auth_tag_len);
}
void CipherBase::Init(const FunctionCallbackInfo<Value>& args) {
CipherBase* cipher;
ASSIGN_OR_RETURN_UNWRAP(&cipher, args.This());
Environment* env = Environment::GetCurrent(args);
CHECK_GE(args.Length(), 3);
const Utf8Value cipher_type(args.GetIsolate(), args[0]);
ArrayBufferOrViewContents<unsigned char> key_buf(args[1]);
if (!key_buf.CheckSizeInt32())
return THROW_ERR_OUT_OF_RANGE(env, "password is too large");
// Don't assign to cipher->auth_tag_len_ directly; the value might not
// represent a valid length at this point.
unsigned int auth_tag_len;
if (args[2]->IsUint32()) {
auth_tag_len = args[2].As<Uint32>()->Value();
} else {
CHECK(args[2]->IsInt32() && args[2].As<Int32>()->Value() == -1);
auth_tag_len = kNoAuthTagLength;
}
cipher->Init(cipher_type.ToStringView(), key_buf, auth_tag_len);
}
void CipherBase::InitIv(std::string_view cipher_type,
const ByteSource& key_buf,
const ArrayBufferOrViewContents<unsigned char>& iv_buf,

View File

@ -50,9 +50,6 @@ class CipherBase : public BaseObject {
const unsigned char* iv,
int iv_len,
unsigned int auth_tag_len);
void Init(std::string_view cipher_type,
const ArrayBufferOrViewContents<unsigned char>& key_buf,
unsigned int auth_tag_len);
void InitIv(std::string_view cipher_type,
const ByteSource& key_buf,
const ArrayBufferOrViewContents<unsigned char>& iv_buf,
@ -73,7 +70,6 @@ class CipherBase : public BaseObject {
bool MaybePassAuthTagToOpenSSL();
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Init(const v8::FunctionCallbackInfo<v8::Value>& args);
static void InitIv(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Update(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Final(const v8::FunctionCallbackInfo<v8::Value>& args);

View File

@ -171,6 +171,14 @@ for (let n = 1; n < 256; n += 1) {
errMessage);
}
// And so should undefined be (regardless of mode).
assert.throws(
() => crypto.createCipheriv('aes-128-ecb', Buffer.alloc(16)),
{ code: 'ERR_INVALID_ARG_TYPE' });
assert.throws(
() => crypto.createCipheriv('aes-128-ecb', Buffer.alloc(16), undefined),
{ code: 'ERR_INVALID_ARG_TYPE' });
// Correctly sized IV should be accepted in CBC mode.
crypto.createCipheriv('aes-128-cbc', Buffer.alloc(16), Buffer.alloc(16));