Repository: nodejs/node
Pull request: src: update crypto.getCipherInfo() to use DictionaryTemplate

Also, have it use a null prototype, lowercase in the C++ layer, eliminate an unnecessary string conversion, and improve argument validation. Semver-major due to a couple of the changes.

Results in about a 25% performance improvment:

```
crypto/getcipherinfo.js n=50 cipher='aes-128-cbc-hmac-sha1'           ***     24.04 %       ±3.97%  ±5.28%  ±6.88%
crypto/getcipherinfo.js n=50 cipher='aes-128-cbc-hmac-sha256'         ***     24.03 %       ±5.43%  ±7.24%  ±9.43%
crypto/getcipherinfo.js n=50 cipher='aes-128-cbc'                     ***     24.60 %       ±3.35%  ±4.46%  ±5.82%
crypto/getcipherinfo.js n=50 cipher='aes-128-ccm'                     ***     27.13 %       ±6.63%  ±8.85% ±11.59%
crypto/getcipherinfo.js n=50 cipher='aes-128-cfb'                     ***     23.69 %       ±6.45%  ±8.61% ±11.26%
crypto/getcipherinfo.js n=50 cipher='aes-128-cfb1'                    ***     19.27 %       ±7.62% ±10.22% ±13.48%
crypto/getcipherinfo.js n=50 cipher='aes-128-cfb8'                    ***     24.89 %       ±5.68%  ±7.56%  ±9.86%
crypto/getcipherinfo.js n=50 cipher='aes-128-ctr'                     ***     24.81 %       ±3.85%  ±5.12%  ±6.68%
crypto/getcipherinfo.js n=50 cipher='aes-128-ecb'                       *      9.92 %       ±9.88% ±13.16% ±17.16%
crypto/getcipherinfo.js n=50 cipher='aes-128-gcm'                     ***     27.28 %       ±4.57%  ±6.10%  ±7.95%
crypto/getcipherinfo.js n=50 cipher='aes-128-ocb'                     ***     25.66 %       ±3.99%  ±5.31%  ±6.92%
crypto/getcipherinfo.js n=50 cipher='aes-128-ofb'                     ***     25.06 %       ±8.94% ±11.96% ±15.69%
crypto/getcipherinfo.js n=50 cipher='aes-128-xts'                     ***     26.20 %       ±3.72%  ±4.95%  ±6.44%
crypto/getcipherinfo.js n=50 cipher='aes-192-cbc'                     ***     20.86 %       ±6.90%  ±9.24% ±12.16%
crypto/getcipherinfo.js n=50 cipher='aes-192-ccm'                     ***     28.44 %       ±6.56%  ±8.75% ±11.42%
crypto/getcipherinfo.js n=50 cipher='aes-192-cfb'                     ***     26.19 %       ±3.14%  ±4.18%  ±5.45%
crypto/getcipherinfo.js n=50 cipher='aes-192-cfb1'                    ***     21.09 %      ±10.11% ±13.47% ±17.56%
crypto/getcipherinfo.js n=50 cipher='aes-192-cfb8'                    ***     21.76 %       ±7.15%  ±9.52% ±12.43%
crypto/getcipherinfo.js n=50 cipher='aes-192-ctr'                     ***     28.04 %       ±3.62%  ±4.82%  ±6.28%
crypto/getcipherinfo.js n=50 cipher='aes-192-ecb'                     ***     18.21 %       ±8.67% ±11.56% ±15.09%
crypto/getcipherinfo.js n=50 cipher='aes-192-gcm'                     ***     27.97 %       ±7.59% ±10.10% ±13.15%
crypto/getcipherinfo.js n=50 cipher='aes-192-ocb'                     ***     23.01 %       ±4.63%  ±6.16%  ±8.03%
crypto/getcipherinfo.js n=50 cipher='aes-192-ofb'                     ***     22.79 %       ±4.94%  ±6.61%  ±8.66%
crypto/getcipherinfo.js n=50 cipher='aes-256-cbc-hmac-sha1'           ***     25.51 %       ±9.36% ±12.46% ±16.22%
crypto/getcipherinfo.js n=50 cipher='aes-256-cbc-hmac-sha256'         ***     22.15 %       ±4.07%  ±5.43%  ±7.11%
crypto/getcipherinfo.js n=50 cipher='aes-256-cbc'                     ***     24.14 %       ±4.44%  ±5.91%  ±7.70%
crypto/getcipherinfo.js n=50 cipher='aes-256-ccm'                     ***     27.65 %       ±6.64%  ±8.85% ±11.57%
crypto/getcipherinfo.js n=50 cipher='aes-256-cfb'                     ***     27.22 %       ±5.74%  ±7.65%  ±9.96%
crypto/getcipherinfo.js n=50 cipher='aes-256-cfb1'                    ***     27.32 %       ±3.95%  ±5.26%  ±6.85%
crypto/getcipherinfo.js n=50 cipher='aes-256-cfb8'                    ***     25.64 %       ±7.25%  ±9.71% ±12.75%
crypto/getcipherinfo.js n=50 cipher='aes-256-ctr'                     ***     21.32 %       ±8.48% ±11.36% ±14.92%
crypto/getcipherinfo.js n=50 cipher='aes-256-ecb'                     ***     20.79 %       ±4.18%  ±5.56%  ±7.24%
crypto/getcipherinfo.js n=50 cipher='aes-256-gcm'                     ***     30.72 %       ±4.47%  ±5.97%  ±7.80%
crypto/getcipherinfo.js n=50 cipher='aes-256-ocb'                     ***     22.76 %       ±8.13% ±10.89% ±14.30%
crypto/getcipherinfo.js n=50 cipher='aes-256-ofb'                     ***     27.56 %       ±6.41%  ±8.56% ±11.20%
crypto/getcipherinfo.js n=50 cipher='aes-256-xts'                     ***     27.02 %       ±4.12%  ±5.49%  ±7.14%
crypto/getcipherinfo.js n=50 cipher='aes128-wrap-pad'                 ***     23.07 %       ±7.21%  ±9.62% ±12.56%
crypto/getcipherinfo.js n=50 cipher='aes128-wrap'                     ***     26.98 %       ±7.98% ±10.63% ±13.87%
crypto/getcipherinfo.js n=50 cipher='aes128'                          ***     24.27 %       ±6.82%  ±9.11% ±11.93%
crypto/getcipherinfo.js n=50 cipher='aes192-wrap-pad'                 ***     24.17 %       ±5.16%  ±6.89%  ±9.03%
crypto/getcipherinfo.js n=50 cipher='aes192-wrap'                     ***     23.82 %       ±4.35%  ±5.80%  ±7.58%
crypto/getcipherinfo.js n=50 cipher='aes192'                          ***     28.81 %       ±6.53%  ±8.73% ±11.44%
crypto/getcipherinfo.js n=50 cipher='aes256-wrap-pad'                 ***     21.66 %       ±3.71%  ±4.95%  ±6.47%
crypto/getcipherinfo.js n=50 cipher='aes256-wrap'                     ***     22.02 %       ±8.41% ±11.22% ±14.64%
crypto/getcipherinfo.js n=50 cipher='aes256'                          ***     26.91 %       ±4.22%  ±5.61%  ±7.31%
crypto/getcipherinfo.js n=50 cipher='aria-128-cbc'                    ***     28.75 %       ±3.64%  ±4.85%  ±6.31%
crypto/getcipherinfo.js n=50 cipher='aria-128-ccm'                    ***     31.79 %       ±7.26%  ±9.70% ±12.72%
crypto/getcipherinfo.js n=50 cipher='aria-128-cfb'                    ***     24.47 %       ±5.10%  ±6.79%  ±8.84%
crypto/getcipherinfo.js n=50 cipher='aria-128-cfb1'                   ***     24.65 %       ±9.06% ±12.09% ±15.78%
crypto/getcipherinfo.js n=50 cipher='aria-128-cfb8'                   ***     30.60 %       ±7.95% ±10.63% ±13.95%
crypto/getcipherinfo.js n=50 cipher='aria-128-ctr'                    ***     24.28 %       ±4.14%  ±5.51%  ±7.17%
crypto/getcipherinfo.js n=50 cipher='aria-128-ecb'                    ***     19.81 %       ±4.09%  ±5.45%  ±7.09%
crypto/getcipherinfo.js n=50 cipher='aria-128-gcm'                    ***     24.89 %       ±9.90% ±13.18% ±17.18%
crypto/getcipherinfo.js n=50 cipher='aria-128-ofb'                    ***     24.23 %       ±9.08% ±12.11% ±15.81%
crypto/getcipherinfo.js n=50 cipher='aria-192-cbc'                    ***     26.87 %       ±7.13%  ±9.52% ±12.45%
crypto/getcipherinfo.js n=50 cipher='aria-192-ccm'                    ***     24.25 %       ±7.09%  ±9.46% ±12.36%
crypto/getcipherinfo.js n=50 cipher='aria-192-cfb'                    ***     32.22 %       ±3.85%  ±5.13%  ±6.68%
crypto/getcipherinfo.js n=50 cipher='aria-192-cfb1'                   ***     28.46 %       ±5.21%  ±6.93%  ±9.02%
crypto/getcipherinfo.js n=50 cipher='aria-192-cfb8'                   ***     23.23 %       ±6.73%  ±9.01% ±11.84%
crypto/getcipherinfo.js n=50 cipher='aria-192-ctr'                    ***     24.19 %       ±8.42% ±11.25% ±14.75%
crypto/getcipherinfo.js n=50 cipher='aria-192-ecb'                    ***     17.84 %       ±4.54%  ±6.05%  ±7.87%
crypto/getcipherinfo.js n=50 cipher='aria-192-gcm'                    ***     22.88 %       ±4.96%  ±6.61%  ±8.63%
crypto/getcipherinfo.js n=50 cipher='aria-192-ofb'                    ***     24.70 %       ±3.90%  ±5.20%  ±6.79%
crypto/getcipherinfo.js n=50 cipher='aria-256-cbc'                    ***     30.75 %       ±7.13%  ±9.52% ±12.47%
crypto/getcipherinfo.js n=50 cipher='aria-256-ccm'                    ***     27.45 %       ±5.35%  ±7.15%  ±9.36%
crypto/getcipherinfo.js n=50 cipher='aria-256-cfb'                    ***     25.01 %       ±3.87%  ±5.15%  ±6.71%
crypto/getcipherinfo.js n=50 cipher='aria-256-cfb1'                   ***     25.91 %       ±3.51%  ±4.68%  ±6.11%
crypto/getcipherinfo.js n=50 cipher='aria-256-cfb8'                   ***     25.88 %       ±4.56%  ±6.08%  ±7.95%
crypto/getcipherinfo.js n=50 cipher='aria-256-ctr'                    ***     25.38 %       ±4.89%  ±6.51%  ±8.49%
crypto/getcipherinfo.js n=50 cipher='aria-256-ecb'                    ***     17.98 %       ±7.54% ±10.11% ±13.34%
crypto/getcipherinfo.js n=50 cipher='aria-256-gcm'                    ***     25.10 %       ±9.43% ±12.56% ±16.38%
crypto/getcipherinfo.js n=50 cipher='aria-256-ofb'                    ***     31.12 %       ±7.36%  ±9.81% ±12.80%
crypto/getcipherinfo.js n=50 cipher='aria128'                         ***     21.19 %       ±5.54%  ±7.38%  ±9.63%
crypto/getcipherinfo.js n=50 cipher='aria192'                         ***     23.67 %       ±5.56%  ±7.42%  ±9.71%
crypto/getcipherinfo.js n=50 cipher='aria256'                         ***     21.71 %       ±4.36%  ±5.81%  ±7.56%
crypto/getcipherinfo.js n=50 cipher='camellia-128-cbc'                ***     21.29 %       ±5.16%  ±6.91%  ±9.09%
crypto/getcipherinfo.js n=50 cipher='camellia-128-cfb'                ***     23.92 %       ±3.46%  ±4.60%  ±6.00%
crypto/getcipherinfo.js n=50 cipher='camellia-128-cfb1'               ***     30.88 %       ±4.40%  ±5.86%  ±7.63%
crypto/getcipherinfo.js n=50 cipher='camellia-128-cfb8'               ***     27.27 %       ±4.08%  ±5.43%  ±7.07%
crypto/getcipherinfo.js n=50 cipher='camellia-128-ctr'                ***     27.63 %       ±7.40%  ±9.89% ±12.95%
crypto/getcipherinfo.js n=50 cipher='camellia-128-ecb'                ***     19.92 %       ±6.49%  ±8.66% ±11.34%
crypto/getcipherinfo.js n=50 cipher='camellia-128-ofb'                ***     22.31 %       ±7.86% ±10.55% ±13.93%
crypto/getcipherinfo.js n=50 cipher='camellia-192-cbc'                ***     22.62 %       ±4.14%  ±5.52%  ±7.21%
crypto/getcipherinfo.js n=50 cipher='camellia-192-cfb'                ***     21.87 %       ±4.17%  ±5.54%  ±7.21%
crypto/getcipherinfo.js n=50 cipher='camellia-192-cfb1'               ***     25.32 %       ±8.56% ±11.42% ±14.92%
crypto/getcipherinfo.js n=50 cipher='camellia-192-cfb8'               ***     26.37 %       ±5.25%  ±7.01%  ±9.16%
crypto/getcipherinfo.js n=50 cipher='camellia-192-ctr'                ***     24.61 %       ±4.07%  ±5.42%  ±7.07%
crypto/getcipherinfo.js n=50 cipher='camellia-192-ecb'                ***     13.95 %       ±6.85%  ±9.15% ±11.98%
crypto/getcipherinfo.js n=50 cipher='camellia-192-ofb'                ***     25.58 %      ±10.01% ±13.34% ±17.41%
crypto/getcipherinfo.js n=50 cipher='camellia-256-cbc'                ***     24.91 %       ±6.03%  ±8.03% ±10.49%
crypto/getcipherinfo.js n=50 cipher='camellia-256-cfb'                ***     26.73 %       ±3.72%  ±4.95%  ±6.45%
crypto/getcipherinfo.js n=50 cipher='camellia-256-cfb1'               ***     23.61 %       ±7.64% ±10.19% ±13.32%
crypto/getcipherinfo.js n=50 cipher='camellia-256-cfb8'               ***     18.95 %       ±8.10% ±10.86% ±14.29%
crypto/getcipherinfo.js n=50 cipher='camellia-256-ctr'                ***     25.33 %       ±6.50%  ±8.64% ±11.25%
crypto/getcipherinfo.js n=50 cipher='camellia-256-ecb'                ***     20.75 %       ±6.91%  ±9.24% ±12.13%
crypto/getcipherinfo.js n=50 cipher='camellia-256-ofb'                ***     22.48 %       ±4.15%  ±5.54%  ±7.24%
crypto/getcipherinfo.js n=50 cipher='camellia128'                     ***     19.67 %       ±4.46%  ±5.95%  ±7.78%
crypto/getcipherinfo.js n=50 cipher='camellia192'                     ***     24.55 %       ±9.68% ±12.88% ±16.76%
crypto/getcipherinfo.js n=50 cipher='camellia256'                     ***     24.64 %       ±4.02%  ±5.35%  ±6.96%
crypto/getcipherinfo.js n=50 cipher='chacha20-poly1305'               ***     18.13 %       ±4.59%  ±6.11%  ±7.97%
crypto/getcipherinfo.js n=50 cipher='chacha20'                                 9.12 %      ±11.50% ±15.46% ±20.44%
crypto/getcipherinfo.js n=50 cipher='des-ede-cbc'                     ***     27.26 %       ±7.17%  ±9.56% ±12.49%
crypto/getcipherinfo.js n=50 cipher='des-ede-cfb'                     ***     30.05 %       ±8.95% ±11.99% ±15.78%
crypto/getcipherinfo.js n=50 cipher='des-ede-ecb'                     ***     13.67 %       ±6.58%  ±8.82% ±11.63%
crypto/getcipherinfo.js n=50 cipher='des-ede-ofb'                     ***     26.55 %       ±8.20% ±10.92% ±14.22%
crypto/getcipherinfo.js n=50 cipher='des-ede'                         ***     16.86 %       ±3.89%  ±5.18%  ±6.75%
crypto/getcipherinfo.js n=50 cipher='des-ede3-cbc'                    ***     27.59 %       ±6.69%  ±8.95% ±11.76%
crypto/getcipherinfo.js n=50 cipher='des-ede3-cfb'                    ***     27.23 %       ±5.83%  ±7.76% ±10.11%
crypto/getcipherinfo.js n=50 cipher='des-ede3-cfb1'                   ***     23.37 %       ±5.02%  ±6.69%  ±8.72%
crypto/getcipherinfo.js n=50 cipher='des-ede3-cfb8'                   ***     30.01 %       ±7.03%  ±9.39% ±12.31%
crypto/getcipherinfo.js n=50 cipher='des-ede3-ecb'                    ***     18.88 %       ±3.82%  ±5.08%  ±6.62%
crypto/getcipherinfo.js n=50 cipher='des-ede3-ofb'                    ***     28.47 %       ±6.91%  ±9.23% ±12.07%
crypto/getcipherinfo.js n=50 cipher='des-ede3'                         **     14.12 %       ±8.06% ±10.81% ±14.25%
crypto/getcipherinfo.js n=50 cipher='des3-wrap'                        **     11.27 %       ±7.12%  ±9.55% ±12.58%
crypto/getcipherinfo.js n=50 cipher='des3'                            ***     26.43 %       ±6.70%  ±8.93% ±11.66%
crypto/getcipherinfo.js n=50 cipher='id-aes128-CCM'                   ***     27.17 %       ±5.50%  ±7.34%  ±9.59%
crypto/getcipherinfo.js n=50 cipher='id-aes128-GCM'                   ***     23.14 %       ±7.64% ±10.24% ±13.48%
crypto/getcipherinfo.js n=50 cipher='id-aes128-wrap-pad'              ***     24.21 %       ±5.31%  ±7.07%  ±9.22%
crypto/getcipherinfo.js n=50 cipher='id-aes128-wrap'                  ***     21.14 %       ±3.98%  ±5.30%  ±6.92%
crypto/getcipherinfo.js n=50 cipher='id-aes192-CCM'                   ***     22.72 %       ±5.21%  ±6.95%  ±9.08%
crypto/getcipherinfo.js n=50 cipher='id-aes192-GCM'                   ***     28.66 %       ±7.32%  ±9.76% ±12.74%
crypto/getcipherinfo.js n=50 cipher='id-aes192-wrap-pad'              ***     25.01 %       ±4.78%  ±6.36%  ±8.30%
crypto/getcipherinfo.js n=50 cipher='id-aes192-wrap'                  ***     23.00 %       ±3.99%  ±5.32%  ±6.94%
crypto/getcipherinfo.js n=50 cipher='id-aes256-CCM'                   ***     28.18 %       ±6.65%  ±8.87% ±11.59%
crypto/getcipherinfo.js n=50 cipher='id-aes256-GCM'                   ***     23.89 %       ±8.07% ±10.82% ±14.27%
crypto/getcipherinfo.js n=50 cipher='id-aes256-wrap-pad'              ***     22.32 %       ±5.55%  ±7.41%  ±9.69%
crypto/getcipherinfo.js n=50 cipher='id-aes256-wrap'                  ***     29.74 %       ±7.38%  ±9.84% ±12.87%
crypto/getcipherinfo.js n=50 cipher='id-smime-alg-CMS3DESwrap'        ***     12.80 %       ±5.11%  ±6.82%  ±8.93%
crypto/getcipherinfo.js n=50 cipher='sm4-cbc'                         ***     27.52 %       ±4.53%  ±6.03%  ±7.86%
crypto/getcipherinfo.js n=50 cipher='sm4-cfb'                         ***     25.15 %       ±5.41%  ±7.20%  ±9.37%
crypto/getcipherinfo.js n=50 cipher='sm4-ctr'                         ***     25.26 %       ±4.07%  ±5.42%  ±7.06%
crypto/getcipherinfo.js n=50 cipher='sm4-ecb'                         ***     20.02 %       ±3.92%  ±5.21%  ±6.79%
crypto/getcipherinfo.js n=50 cipher='sm4-ofb'                         ***     25.72 %       ±4.88%  ±6.50%  ±8.47%
crypto/getcipherinfo.js n=50 cipher='sm4'                             ***     26.27 %       ±4.73%  ±6.30%  ±8.20%
```


Changed files:
filename: benchmark/crypto/getcipherinfo.js
patch: @@ -0,0 +1,16 @@
+'use strict';
+
+const common = require('../common.js');
+const { getCiphers, getCipherInfo } = require('node:crypto');
+const bench = common.createBenchmark(main, {
+  cipher: getCiphers(),
+  n: 50,
+});
+
+function main({ n, cipher }) {
+  bench.start();
+  for (let i = 0; i < n; i++) {
+    getCipherInfo(cipher);
+  }
+  bench.end(n);
+}

filename: lib/internal/crypto/cipher.js
patch: @@ -1,9 +1,9 @@
 'use strict';
 
 const {
+  NumberIsInteger,
   ObjectSetPrototypeOf,
   ReflectApply,
-  StringPrototypeToLowerCase,
 } = primordials;
 
 const {
@@ -33,7 +33,7 @@ const {
 
 const {
   validateEncoding,
-  validateInt32,
+  validateUint32,
   validateObject,
   validateString,
 } = require('internal/validators');
@@ -251,31 +251,34 @@ ObjectSetPrototypeOf(Decipheriv.prototype, LazyTransform.prototype);
 ObjectSetPrototypeOf(Decipheriv, LazyTransform);
 addCipherPrototypeFunctions(Decipheriv);
 
-function getCipherInfo(nameOrNid, options) {
-  if (typeof nameOrNid !== 'string' && typeof nameOrNid !== 'number') {
-    throw new ERR_INVALID_ARG_TYPE(
-      'nameOrNid',
-      ['string', 'number'],
-      nameOrNid);
+const kMinNid = 1;
+const kMaxNid = 2_147_483_647;
+function getCipherInfo(nameOrNid, options = {}) {
+  validateObject(options, 'options');
+  const { keyLength, ivLength } = options;
+  if (keyLength !== undefined) {
+    validateUint32(keyLength, 'options.keyLength');
   }
-  if (typeof nameOrNid === 'number')
-    validateInt32(nameOrNid, 'nameOrNid');
-  let keyLength, ivLength;
-  if (options !== undefined) {
-    validateObject(options, 'options');
-    ({ keyLength, ivLength } = options);
-    if (keyLength !== undefined)
-      validateInt32(keyLength, 'options.keyLength');
-    if (ivLength !== undefined)
-      validateInt32(ivLength, 'options.ivLength');
+  if (ivLength !== undefined) {
+    validateUint32(ivLength, 'options.ivLength');
   }
 
-  const ret = _getCipherInfo({}, nameOrNid, keyLength, ivLength);
-  if (ret !== undefined) {
-    ret.name &&= StringPrototypeToLowerCase(ret.name);
-    ret.type &&= StringPrototypeToLowerCase(ret.type);
+  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);
   }
-  return ret;
+
+  throw new ERR_INVALID_ARG_TYPE(
+    'nameOrNid',
+    ['string', 'number'],
+    nameOrNid);
 }
 
 module.exports = {

filename: src/crypto/crypto_cipher.cc
patch: @@ -24,51 +24,71 @@ using v8::ArrayBuffer;
 using v8::BackingStore;
 using v8::BackingStoreInitializationMode;
 using v8::Context;
+using v8::DictionaryTemplate;
 using v8::FunctionCallbackInfo;
 using v8::FunctionTemplate;
 using v8::HandleScope;
 using v8::Int32;
 using v8::Isolate;
 using v8::Local;
 using v8::LocalVector;
+using v8::MaybeLocal;
 using v8::Object;
 using v8::Uint32;
+using v8::Undefined;
 using v8::Value;
 
 namespace crypto {
 namespace {
 // Collects and returns information on the given cipher
 void GetCipherInfo(const FunctionCallbackInfo<Value>& args) {
   Environment* env = Environment::GetCurrent(args);
-  CHECK(args[0]->IsObject());
-  Local<Object> info = args[0].As<Object>();
 
-  CHECK(args[1]->IsString() || args[1]->IsInt32());
+  auto tmpl = env->cipherinfo_detail_template();
+  if (tmpl.IsEmpty()) {
+    static constexpr std::string_view names[] = {
+        "mode",
+        "name",
+        "nid",
+        "keyLength",
+        "blockSize",
+        "ivLength",
+    };
+    tmpl = DictionaryTemplate::New(env->isolate(), names);
+    env->set_cipherinfo_detail_template(tmpl);
+  }
+  MaybeLocal<Value> values[] = {
+      Undefined(env->isolate()),  // mode
+      Undefined(env->isolate()),  // name
+      Undefined(env->isolate()),  // nid
+      Undefined(env->isolate()),  // keyLength
+      Undefined(env->isolate()),  // blockSize
+      Undefined(env->isolate()),  // ivLength
+  };
+
+  CHECK(args[0]->IsString() || args[0]->IsInt32());
 
   const auto cipher = ([&] {
-    if (args[1]->IsString()) {
-      Utf8Value name(env->isolate(), args[1]);
+    if (args[0]->IsString()) {
+      Utf8Value name(env->isolate(), args[0]);
       return Cipher::FromName(*name);
     } else {
-      int nid = args[1].As<Int32>()->Value();
+      int nid = args[0].As<Int32>()->Value();
       return Cipher::FromNid(nid);
     }
   })();
 
   if (!cipher) return;
 
-  int iv_length = cipher.getIvLength();
-  int key_length = cipher.getKeyLength();
-  int block_length = cipher.getBlockSize();
-  auto mode_label = cipher.getModeLabel();
-  auto name = cipher.getName();
+  size_t iv_length = cipher.getIvLength();
+  size_t key_length = cipher.getKeyLength();
 
   // If the testKeyLen and testIvLen arguments are specified,
   // then we will make an attempt to see if they are usable for
   // the cipher in question, returning undefined if they are not.
   // If they are, the info object will be returned with the values
   // given.
-  if (args[2]->IsInt32() || args[3]->IsInt32()) {
+  if (args[1]->IsUint32() || args[2]->IsUint32()) {
     // Test and input IV or key length to determine if it's acceptable.
     // If it is, then the getCipherInfo will succeed with the given
     // values.
@@ -77,16 +97,16 @@ void GetCipherInfo(const FunctionCallbackInfo<Value>& args) {
       return;
     }
 
-    if (args[2]->IsInt32()) {
-      int check_len = args[2].As<Int32>()->Value();
+    if (args[1]->IsUint32()) {
+      size_t check_len = args[1].As<Uint32>()->Value();
       if (!ctx.setKeyLength(check_len)) {
         return;
       }
       key_length = check_len;
     }
 
-    if (args[3]->IsInt32()) {
-      int check_len = args[3].As<Int32>()->Value();
+    if (args[2]->IsUint32()) {
+      size_t check_len = args[2].As<Uint32>()->Value();
       // For CCM modes, the IV may be between 7 and 13 bytes.
       // For GCM and OCB modes, we'll check by attempting to
       // set the value. For everything else, just check that
@@ -106,55 +126,30 @@ void GetCipherInfo(const FunctionCallbackInfo<Value>& args) {
     }
   }
 
-  if (mode_label.length() &&
-      info->Set(env->context(),
-                FIXED_ONE_BYTE_STRING(env->isolate(), "mode"),
-                OneByteString(
-                    env->isolate(), mode_label.data(), mode_label.length()))
-          .IsNothing()) {
-    return;
-  }
-
-  if (info->Set(env->context(),
-                env->name_string(),
-                OneByteString(env->isolate(), name))
-          .IsNothing()) {
-    return;
-  }
+  // Lowercase the name in place before we create the JS string from it.
+  std::string name_str(cipher.getName());
+  name_str = ToLower(name_str);
 
-  if (info->Set(env->context(),
-                FIXED_ONE_BYTE_STRING(env->isolate(), "nid"),
-                Int32::New(env->isolate(), cipher.getNid()))
-          .IsNothing()) {
-    return;
-  }
+  values[0] = ToV8Value(env->context(), cipher.getModeLabel(), env->isolate());
+  values[1] = ToV8Value(env->context(), name_str, env->isolate());
+  values[2] = Uint32::NewFromUnsigned(env->isolate(), cipher.getNid());
+  values[3] = Uint32::NewFromUnsigned(env->isolate(), key_length);
 
   // Stream ciphers do not have a meaningful block size
-  if (!cipher.isStreamMode() &&
-      info->Set(env->context(),
-                FIXED_ONE_BYTE_STRING(env->isolate(), "blockSize"),
-                Int32::New(env->isolate(), block_length))
-          .IsNothing()) {
-    return;
+  if (!cipher.isStreamMode()) {
+    values[4] = Uint32::NewFromUnsigned(env->isolate(), cipher.getBlockSize());
   }
 
   // Ciphers that do not use an IV shouldn't report a length
-  if (iv_length != 0 &&
-      info->Set(
-          env->context(),
-          FIXED_ONE_BYTE_STRING(env->isolate(), "ivLength"),
-          Int32::New(env->isolate(), iv_length)).IsNothing()) {
-    return;
+  if (iv_length != 0) {
+    values[5] = Uint32::NewFromUnsigned(env->isolate(), iv_length);
   }
 
-  if (info->Set(
-          env->context(),
-          FIXED_ONE_BYTE_STRING(env->isolate(), "keyLength"),
-          Int32::New(env->isolate(), key_length)).IsNothing()) {
-    return;
+  Local<Object> info;
+  if (NewDictionaryInstanceNullProto(env->context(), tmpl, values)
+          .ToLocal(&info)) {
+    args.GetReturnValue().Set(info);
   }
-
-  args.GetReturnValue().Set(info);
 }
 }  // namespace
 

filename: src/env_properties.h
patch: @@ -386,6 +386,7 @@
   V(blocklist_constructor_template, v8::FunctionTemplate)                      \
   V(caa_record_template, v8::DictionaryTemplate)                               \
   V(callsite_template, v8::DictionaryTemplate)                                 \
+  V(cipherinfo_detail_template, v8::DictionaryTemplate)                        \
   V(cipherinfo_template, v8::DictionaryTemplate)                               \
   V(cname_record_template, v8::DictionaryTemplate)                             \
   V(contextify_global_template, v8::ObjectTemplate)                            \