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