Coverage Report

Created: 2025-12-30 08:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/node/src/crypto/crypto_scrypt.cc
Line
Count
Source
1
#include "crypto/crypto_scrypt.h"
2
#include "async_wrap-inl.h"
3
#include "crypto/crypto_util.h"
4
#include "env-inl.h"
5
#include "memory_tracker-inl.h"
6
#include "node_buffer.h"
7
#include "threadpoolwork-inl.h"
8
#include "v8.h"
9
10
namespace node {
11
12
using v8::FunctionCallbackInfo;
13
using v8::Int32;
14
using v8::JustVoid;
15
using v8::Maybe;
16
using v8::MaybeLocal;
17
using v8::Nothing;
18
using v8::Uint32;
19
using v8::Value;
20
21
namespace crypto {
22
#ifndef OPENSSL_NO_SCRYPT
23
24
ScryptConfig::ScryptConfig(ScryptConfig&& other) noexcept
25
0
  : mode(other.mode),
26
0
    pass(std::move(other.pass)),
27
0
    salt(std::move(other.salt)),
28
0
    N(other.N),
29
0
    r(other.r),
30
0
    p(other.p),
31
0
    maxmem(other.maxmem),
32
0
    length(other.length) {}
33
34
0
ScryptConfig& ScryptConfig::operator=(ScryptConfig&& other) noexcept {
35
0
  if (&other == this) return *this;
36
0
  this->~ScryptConfig();
37
0
  return *new (this) ScryptConfig(std::move(other));
38
0
}
39
40
0
void ScryptConfig::MemoryInfo(MemoryTracker* tracker) const {
41
0
  if (mode == kCryptoJobAsync) {
42
0
    tracker->TrackFieldWithSize("pass", pass.size());
43
0
    tracker->TrackFieldWithSize("salt", salt.size());
44
0
  }
45
0
}
46
47
MaybeLocal<Value> ScryptTraits::EncodeOutput(Environment* env,
48
                                             const ScryptConfig& params,
49
0
                                             ByteSource* out) {
50
0
  return out->ToArrayBuffer(env);
51
0
}
52
53
Maybe<void> ScryptTraits::AdditionalConfig(
54
    CryptoJobMode mode,
55
    const FunctionCallbackInfo<Value>& args,
56
    unsigned int offset,
57
0
    ScryptConfig* params) {
58
0
  Environment* env = Environment::GetCurrent(args);
59
60
0
  params->mode = mode;
61
62
0
  ArrayBufferOrViewContents<char> pass(args[offset]);
63
0
  ArrayBufferOrViewContents<char> salt(args[offset + 1]);
64
65
0
  if (!pass.CheckSizeInt32()) [[unlikely]] {
66
0
    THROW_ERR_OUT_OF_RANGE(env, "pass is too large");
67
0
    return Nothing<void>();
68
0
  }
69
70
0
  if (!salt.CheckSizeInt32()) [[unlikely]] {
71
0
    THROW_ERR_OUT_OF_RANGE(env, "salt is too large");
72
0
    return Nothing<void>();
73
0
  }
74
75
0
  params->pass = mode == kCryptoJobAsync
76
0
      ? pass.ToCopy()
77
0
      : pass.ToByteSource();
78
79
0
  params->salt = mode == kCryptoJobAsync
80
0
      ? salt.ToCopy()
81
0
      : salt.ToByteSource();
82
83
0
  CHECK(args[offset + 2]->IsUint32());  // N
84
0
  CHECK(args[offset + 3]->IsUint32());  // r
85
0
  CHECK(args[offset + 4]->IsUint32());  // p
86
0
  CHECK(args[offset + 5]->IsNumber());  // maxmem
87
0
  CHECK(args[offset + 6]->IsInt32());  // length
88
89
0
  params->N = args[offset + 2].As<Uint32>()->Value();
90
0
  params->r = args[offset + 3].As<Uint32>()->Value();
91
0
  params->p = args[offset + 4].As<Uint32>()->Value();
92
0
  params->maxmem = args[offset + 5]->IntegerValue(env->context()).ToChecked();
93
94
0
  params->length = args[offset + 6].As<Int32>()->Value();
95
0
  CHECK_GE(params->length, 0);
96
97
0
  if (!ncrypto::checkScryptParams(
98
0
          params->N, params->r, params->p, params->maxmem)) {
99
    // Do not use CryptoErrorStore or ThrowCryptoError here in order to maintain
100
    // backward compatibility with ERR_CRYPTO_INVALID_SCRYPT_PARAMS.
101
0
    uint32_t err = ERR_peek_last_error();
102
0
    if (err != 0) {
103
0
      char buf[256];
104
0
      ERR_error_string_n(err, buf, sizeof(buf));
105
0
      THROW_ERR_CRYPTO_INVALID_SCRYPT_PARAMS(
106
0
          env, "Invalid scrypt params: %s", buf);
107
0
    } else {
108
0
      THROW_ERR_CRYPTO_INVALID_SCRYPT_PARAMS(env);
109
0
    }
110
0
    return Nothing<void>();
111
0
  }
112
113
0
  return JustVoid();
114
0
}
115
116
bool ScryptTraits::DeriveBits(Environment* env,
117
                              const ScryptConfig& params,
118
                              ByteSource* out,
119
0
                              CryptoJobMode mode) {
120
  // If the params.length is zero-length, just return an empty buffer.
121
  // It's useless, yes, but allowed via the API.
122
0
  if (params.length == 0) {
123
0
    *out = ByteSource();
124
0
    return true;
125
0
  }
126
127
0
  auto dp = ncrypto::scrypt(
128
0
      ncrypto::Buffer<const char>{
129
0
          .data = params.pass.data<char>(),
130
0
          .len = params.pass.size(),
131
0
      },
132
0
      ncrypto::Buffer<const unsigned char>{
133
0
          .data = params.salt.data<unsigned char>(),
134
0
          .len = params.salt.size(),
135
0
      },
136
0
      params.N,
137
0
      params.r,
138
0
      params.p,
139
0
      params.maxmem,
140
0
      params.length);
141
142
0
  if (!dp) return false;
143
0
  DCHECK(!dp.isSecure());
144
0
  *out = ByteSource::Allocated(dp.release());
145
0
  return true;
146
0
}
147
148
#endif  // !OPENSSL_NO_SCRYPT
149
150
}  // namespace crypto
151
}  // namespace node