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::Just;
15 using v8::Maybe;
16 using v8::Nothing;
17 using v8::Uint32;
18 using v8::Value;
19 
20 namespace crypto {
21 #ifndef OPENSSL_NO_SCRYPT
22 
23 ScryptConfig::ScryptConfig(ScryptConfig&& other) noexcept
24   : mode(other.mode),
25     pass(std::move(other.pass)),
26     salt(std::move(other.salt)),
27     N(other.N),
28     r(other.r),
29     p(other.p),
30     maxmem(other.maxmem),
length(other.length)31     length(other.length) {}
32 
33 ScryptConfig& ScryptConfig::operator=(ScryptConfig&& other) noexcept {
34   if (&other == this) return *this;
35   this->~ScryptConfig();
36   return *new (this) ScryptConfig(std::move(other));
37 }
38 
MemoryInfo(MemoryTracker* tracker) const39 void ScryptConfig::MemoryInfo(MemoryTracker* tracker) const {
40   if (mode == kCryptoJobAsync) {
41     tracker->TrackFieldWithSize("pass", pass.size());
42     tracker->TrackFieldWithSize("salt", salt.size());
43   }
44 }
45 
EncodeOutput( Environment* env, const ScryptConfig& params, ByteSource* out, v8::Local<v8::Value>* result)46 Maybe<bool> ScryptTraits::EncodeOutput(
47     Environment* env,
48     const ScryptConfig& params,
49     ByteSource* out,
50     v8::Local<v8::Value>* result) {
51   *result = out->ToArrayBuffer(env);
52   return Just(!result->IsEmpty());
53 }
54 
AdditionalConfig( CryptoJobMode mode, const FunctionCallbackInfo<Value>& args, unsigned int offset, ScryptConfig* params)55 Maybe<bool> ScryptTraits::AdditionalConfig(
56     CryptoJobMode mode,
57     const FunctionCallbackInfo<Value>& args,
58     unsigned int offset,
59     ScryptConfig* params) {
60   Environment* env = Environment::GetCurrent(args);
61 
62   params->mode = mode;
63 
64   ArrayBufferOrViewContents<char> pass(args[offset]);
65   ArrayBufferOrViewContents<char> salt(args[offset + 1]);
66 
67   if (UNLIKELY(!pass.CheckSizeInt32())) {
68     THROW_ERR_OUT_OF_RANGE(env, "pass is too large");
69     return Nothing<bool>();
70   }
71 
72   if (UNLIKELY(!salt.CheckSizeInt32())) {
73     THROW_ERR_OUT_OF_RANGE(env, "salt is too large");
74     return Nothing<bool>();
75   }
76 
77   params->pass = mode == kCryptoJobAsync
78       ? pass.ToCopy()
79       : pass.ToByteSource();
80 
81   params->salt = mode == kCryptoJobAsync
82       ? salt.ToCopy()
83       : salt.ToByteSource();
84 
85   CHECK(args[offset + 2]->IsUint32());  // N
86   CHECK(args[offset + 3]->IsUint32());  // r
87   CHECK(args[offset + 4]->IsUint32());  // p
88   CHECK(args[offset + 5]->IsNumber());  // maxmem
89   CHECK(args[offset + 6]->IsInt32());  // length
90 
91   params->N = args[offset + 2].As<Uint32>()->Value();
92   params->r = args[offset + 3].As<Uint32>()->Value();
93   params->p = args[offset + 4].As<Uint32>()->Value();
94   params->maxmem = args[offset + 5]->IntegerValue(env->context()).ToChecked();
95 
96   if (EVP_PBE_scrypt(
97           nullptr,
98           0,
99           nullptr,
100           0,
101           params->N,
102           params->r,
103           params->p,
104           params->maxmem,
105           nullptr,
106           0) != 1) {
107     THROW_ERR_CRYPTO_INVALID_SCRYPT_PARAMS(env);
108     return Nothing<bool>();
109   }
110 
111   params->length = args[offset + 6].As<Int32>()->Value();
112   CHECK_GE(params->length, 0);
113 
114   return Just(true);
115 }
116 
DeriveBits( Environment* env, const ScryptConfig& params, ByteSource* out)117 bool ScryptTraits::DeriveBits(
118     Environment* env,
119     const ScryptConfig& params,
120     ByteSource* out) {
121   ByteSource::Builder buf(params.length);
122 
123   // Both the pass and salt may be zero-length at this point
124 
125   if (!EVP_PBE_scrypt(params.pass.data<char>(),
126                       params.pass.size(),
127                       params.salt.data<unsigned char>(),
128                       params.salt.size(),
129                       params.N,
130                       params.r,
131                       params.p,
132                       params.maxmem,
133                       buf.data<unsigned char>(),
134                       params.length)) {
135     return false;
136   }
137   *out = std::move(buf).release();
138   return true;
139 }
140 
141 #endif  // !OPENSSL_NO_SCRYPT
142 
143 }  // namespace crypto
144 }  // namespace node
145