/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 |