Repository: nodejs/node
Pull request: crypto: merge CipherBase.initiv into constructor

Now that `CipherBase.init` has been removed, instances of the class are always initialized by a call to `initiv` immediately after the constructor has returned. Instead of calling into C++ twice from `createCipherBase`, pass all required arguments to the constructor and fully initialize the instance before the constructor returns.

<!--
Before submitting a pull request, please read:

- the CONTRIBUTING guide at https://github.com/nodejs/node/blob/HEAD/CONTRIBUTING.md
- the commit message formatting guidelines at
  https://github.com/nodejs/node/blob/HEAD/doc/contributing/pull-requests.md#commit-message-guidelines

For code changes:
1. Include tests for any bug fixes or new features.
2. Update documentation if relevant.
3. Ensure that `make -j4 test` (UNIX), or `vcbuild test` (Windows) passes.

If you believe this PR should be highlighted in the Node.js CHANGELOG
please add the `notable-change` label.

Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
    have the right to submit it under the open source license
    indicated in the file; or

(b) The contribution is based upon previous work that, to the best
    of my knowledge, is covered under an appropriate open source
    license and I have the right under that license to submit that
    work with modifications, whether created in whole or in part
    by me, under the same open source license (unless I am
    permitted to submit under a different license), as indicated
    in the file; or

(c) The contribution was provided directly to me by some other
    person who certified (a), (b) or (c) and I have not modified
    it.

(d) I understand and agree that this project and the contribution
    are public and that a record of the contribution (including all
    personal information I submit with it, including my sign-off) is
    maintained indefinitely and may be redistributed consistent with
    this project or the open source license(s) involved.
-->


Changed files:
filename: lib/internal/crypto/cipher.js
patch: @@ -114,8 +114,7 @@ function getUIntOption(options, key) {
 
 function createCipherBase(cipher, credential, options, isEncrypt, iv) {
   const authTagLength = getUIntOption(options, 'authTagLength');
-  this[kHandle] = new CipherBase(isEncrypt);
-  this[kHandle].initiv(cipher, credential, iv, authTagLength);
+  this[kHandle] = new CipherBase(isEncrypt, cipher, credential, iv, authTagLength);
   this._decoder = null;
 
   ReflectApply(LazyTransform, this, [options]);

filename: src/crypto/crypto_cipher.cc
patch: @@ -231,7 +231,6 @@ void CipherBase::Initialize(Environment* env, Local<Object> target) {
 
   t->InstanceTemplate()->SetInternalFieldCount(CipherBase::kInternalFieldCount);
 
-  SetProtoMethod(isolate, t, "initiv", InitIv);
   SetProtoMethod(isolate, t, "update", Update);
   SetProtoMethod(isolate, t, "final", Final);
   SetProtoMethod(isolate, t, "setAutoPadding", SetAutoPadding);
@@ -274,7 +273,6 @@ void CipherBase::RegisterExternalReferences(
     ExternalReferenceRegistry* registry) {
   registry->Register(New);
 
-  registry->Register(InitIv);
   registry->Register(Update);
   registry->Register(Final);
   registry->Register(SetAutoPadding);
@@ -300,7 +298,39 @@ void CipherBase::RegisterExternalReferences(
 void CipherBase::New(const FunctionCallbackInfo<Value>& args) {
   CHECK(args.IsConstructCall());
   Environment* env = Environment::GetCurrent(args);
-  new CipherBase(env, args.This(), args[0]->IsTrue() ? kCipher : kDecipher);
+  CHECK_EQ(args.Length(), 5);
+
+  CipherBase* cipher =
+      new CipherBase(env, args.This(), args[0]->IsTrue() ? kCipher : kDecipher);
+
+  const Utf8Value cipher_type(env->isolate(), args[1]);
+
+  // The argument can either be a KeyObjectHandle or a byte source
+  // (e.g. ArrayBuffer, TypedArray, etc). Whichever it is, grab the
+  // raw bytes and proceed...
+  const ByteSource key_buf = ByteSource::FromSecretKeyBytes(env, args[2]);
+
+  if (key_buf.size() > INT_MAX) [[unlikely]] {
+    return THROW_ERR_OUT_OF_RANGE(env, "key is too big");
+  }
+
+  ArrayBufferOrViewContents<unsigned char> iv_buf(
+      !args[3]->IsNull() ? args[3] : Local<Value>());
+
+  if (!iv_buf.CheckSizeInt32()) [[unlikely]] {
+    return THROW_ERR_OUT_OF_RANGE(env, "iv is too big");
+  }
+  // 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[4]->IsUint32()) {
+    auth_tag_len = args[4].As<Uint32>()->Value();
+  } else {
+    CHECK(args[4]->IsInt32() && args[4].As<Int32>()->Value() == -1);
+    auth_tag_len = kNoAuthTagLength;
+  }
+
+  cipher->InitIv(*cipher_type, key_buf, iv_buf, auth_tag_len);
 }
 
 void CipherBase::CommonInit(const char* cipher_type,
@@ -391,43 +421,6 @@ void CipherBase::InitIv(const char* cipher_type,
       auth_tag_len);
 }
 
-void CipherBase::InitIv(const FunctionCallbackInfo<Value>& args) {
-  CipherBase* cipher;
-  ASSIGN_OR_RETURN_UNWRAP(&cipher, args.This());
-  Environment* env = cipher->env();
-
-  CHECK_GE(args.Length(), 4);
-
-  const Utf8Value cipher_type(env->isolate(), args[0]);
-
-  // The argument can either be a KeyObjectHandle or a byte source
-  // (e.g. ArrayBuffer, TypedArray, etc). Whichever it is, grab the
-  // raw bytes and proceed...
-  const ByteSource key_buf = ByteSource::FromSecretKeyBytes(env, args[1]);
-
-  if (key_buf.size() > INT_MAX) [[unlikely]] {
-    return THROW_ERR_OUT_OF_RANGE(env, "key is too big");
-  }
-
-  ArrayBufferOrViewContents<unsigned char> iv_buf(
-      !args[2]->IsNull() ? args[2] : Local<Value>());
-
-  if (!iv_buf.CheckSizeInt32()) [[unlikely]] {
-    return THROW_ERR_OUT_OF_RANGE(env, "iv is too big");
-  }
-  // 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[3]->IsUint32()) {
-    auth_tag_len = args[3].As<Uint32>()->Value();
-  } else {
-    CHECK(args[3]->IsInt32() && args[3].As<Int32>()->Value() == -1);
-    auth_tag_len = kNoAuthTagLength;
-  }
-
-  cipher->InitIv(*cipher_type, key_buf, iv_buf, auth_tag_len);
-}
-
 bool CipherBase::InitAuthenticated(const char* cipher_type,
                                    int iv_len,
                                    unsigned int auth_tag_len) {

filename: src/crypto/crypto_cipher.h
patch: @@ -70,7 +70,6 @@ class CipherBase : public BaseObject {
   bool MaybePassAuthTagToOpenSSL();
 
   static void New(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);
   static void SetAutoPadding(const v8::FunctionCallbackInfo<v8::Value>& args);