• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "crypto/crypto_pbkdf2.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::Value;
18 
19 namespace crypto {
PBKDF2Config(PBKDF2Config && other)20 PBKDF2Config::PBKDF2Config(PBKDF2Config&& other) noexcept
21     : mode(other.mode),
22       pass(std::move(other.pass)),
23       salt(std::move(other.salt)),
24       iterations(other.iterations),
25       length(other.length),
26       digest(other.digest) {}
27 
operator =(PBKDF2Config && other)28 PBKDF2Config& PBKDF2Config::operator=(PBKDF2Config&& other) noexcept {
29   if (&other == this) return *this;
30   this->~PBKDF2Config();
31   return *new (this) PBKDF2Config(std::move(other));
32 }
33 
MemoryInfo(MemoryTracker * tracker) const34 void PBKDF2Config::MemoryInfo(MemoryTracker* tracker) const {
35   // The job is sync, the PBKDF2Config does not own the data.
36   if (mode == kCryptoJobAsync) {
37     tracker->TrackFieldWithSize("pass", pass.size());
38     tracker->TrackFieldWithSize("salt", salt.size());
39   }
40 }
41 
EncodeOutput(Environment * env,const PBKDF2Config & params,ByteSource * out,v8::Local<v8::Value> * result)42 Maybe<bool> PBKDF2Traits::EncodeOutput(
43     Environment* env,
44     const PBKDF2Config& params,
45     ByteSource* out,
46     v8::Local<v8::Value>* result) {
47   *result = out->ToArrayBuffer(env);
48   return Just(!result->IsEmpty());
49 }
50 
51 // The input arguments for the job are:
52 //   1. CryptoJobMode
53 //   2. The password
54 //   3. The salt
55 //   4. The number of iterations
56 //   5. The number of bytes to generate
57 //   6. The digest algorithm name
AdditionalConfig(CryptoJobMode mode,const FunctionCallbackInfo<Value> & args,unsigned int offset,PBKDF2Config * params)58 Maybe<bool> PBKDF2Traits::AdditionalConfig(
59     CryptoJobMode mode,
60     const FunctionCallbackInfo<Value>& args,
61     unsigned int offset,
62     PBKDF2Config* params) {
63   Environment* env = Environment::GetCurrent(args);
64 
65   params->mode = mode;
66 
67   ArrayBufferOrViewContents<char> pass(args[offset]);
68   ArrayBufferOrViewContents<char> salt(args[offset + 1]);
69 
70   if (UNLIKELY(!pass.CheckSizeInt32())) {
71     THROW_ERR_OUT_OF_RANGE(env, "pass is too large");
72     return Nothing<bool>();
73   }
74 
75   if (UNLIKELY(!salt.CheckSizeInt32())) {
76     THROW_ERR_OUT_OF_RANGE(env, "salt is too large");
77     return Nothing<bool>();
78   }
79 
80   params->pass = mode == kCryptoJobAsync
81       ? pass.ToCopy()
82       : pass.ToByteSource();
83 
84   params->salt = mode == kCryptoJobAsync
85       ? salt.ToCopy()
86       : salt.ToByteSource();
87 
88   CHECK(args[offset + 2]->IsInt32());  // iteration_count
89   CHECK(args[offset + 3]->IsInt32());  // length
90   CHECK(args[offset + 4]->IsString());  // digest_name
91 
92   params->iterations = args[offset + 2].As<Int32>()->Value();
93   if (params->iterations < 0) {
94     THROW_ERR_OUT_OF_RANGE(env, "iterations must be <= %d", INT_MAX);
95     return Nothing<bool>();
96   }
97 
98   params->length = args[offset + 3].As<Int32>()->Value();
99   if (params->length < 0) {
100     THROW_ERR_OUT_OF_RANGE(env, "length must be <= %d", INT_MAX);
101     return Nothing<bool>();
102   }
103 
104   Utf8Value name(args.GetIsolate(), args[offset + 4]);
105   params->digest = EVP_get_digestbyname(*name);
106   if (params->digest == nullptr) {
107     THROW_ERR_CRYPTO_INVALID_DIGEST(env, "Invalid digest: %s", *name);
108     return Nothing<bool>();
109   }
110 
111   return Just(true);
112 }
113 
DeriveBits(Environment * env,const PBKDF2Config & params,ByteSource * out)114 bool PBKDF2Traits::DeriveBits(
115     Environment* env,
116     const PBKDF2Config& params,
117     ByteSource* out) {
118   ByteSource::Builder buf(params.length);
119 
120   // Both pass and salt may be zero length here.
121   // The generated bytes are stored in buf, which is
122   // assigned to out on success.
123 
124   if (PKCS5_PBKDF2_HMAC(params.pass.data<char>(),
125                         params.pass.size(),
126                         params.salt.data<unsigned char>(),
127                         params.salt.size(),
128                         params.iterations,
129                         params.digest,
130                         params.length,
131                         buf.data<unsigned char>()) <= 0) {
132     return false;
133   }
134   *out = std::move(buf).release();
135   return true;
136 }
137 
138 }  // namespace crypto
139 }  // namespace node
140