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 10namespace node { 11 12using v8::FunctionCallbackInfo; 13using v8::Int32; 14using v8::Just; 15using v8::Maybe; 16using v8::Nothing; 17using v8::Uint32; 18using v8::Value; 19 20namespace crypto { 21#ifndef OPENSSL_NO_SCRYPT 22 23ScryptConfig::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), 31 length(other.length) {} 32 33ScryptConfig& ScryptConfig::operator=(ScryptConfig&& other) noexcept { 34 if (&other == this) return *this; 35 this->~ScryptConfig(); 36 return *new (this) ScryptConfig(std::move(other)); 37} 38 39void ScryptConfig::MemoryInfo(MemoryTracker* tracker) const { 40 if (mode == kCryptoJobAsync) { 41 tracker->TrackFieldWithSize("pass", pass.size()); 42 tracker->TrackFieldWithSize("salt", salt.size()); 43 } 44} 45 46Maybe<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 55Maybe<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 117bool 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