| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent f9d10a3 commit 3d05a1d
9 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -211,28 +211,16 @@ function argon2DeriveBits(algorithm, baseKey, length) { | |||
| 211 | 211 | 'Argon2id': kTypeArgon2id, | |
| 212 | 212 | }[algorithm.name]; | |
| 213 | 213 | ||
| 214 | - let message; | ||
| 215 | - try { | ||
| 216 | - // TODO(panva): call the job directly without needing to re-export the handle | ||
| 217 | - message = getCryptoKeyHandle(baseKey).export(); | ||
| 218 | - } catch (err) { | ||
| 219 | - throw lazyDOMException( | ||
| 220 | - 'The operation failed for an operation-specific reason', | ||
| 221 | - { name: 'OperationError', cause: err }); | ||
| 222 | - } | ||
| 223 | - | ||
| 224 | - const empty = new Uint8Array(0); | ||
| 225 | - | ||
| 226 | 214 | return jobPromise(() => new Argon2Job( | |
| 227 | 215 | kCryptoJobWebCrypto, | |
| 228 | - message, | ||
| 216 | + getCryptoKeyHandle(baseKey), | ||
| 229 | 217 | algorithm.nonce, | |
| 230 | 218 | algorithm.parallelism, | |
| 231 | 219 | length / 8, | |
| 232 | 220 | algorithm.memory, | |
| 233 | 221 | algorithm.passes, | |
| 234 | - algorithm.secretValue === undefined ? empty : algorithm.secretValue, | ||
| 235 | - algorithm.associatedData === undefined ? empty : algorithm.associatedData, | ||
| 222 | + algorithm.secretValue === undefined ? new Uint8Array() : algorithm.secretValue, | ||
| 223 | + algorithm.associatedData === undefined ? new Uint8Array() : algorithm.associatedData, | ||
| 236 | 224 | type)); | |
| 237 | 225 | } | |
| 238 | 226 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -29,10 +29,9 @@ const { | |||
| 29 | 29 | } = require('internal/crypto/util'); | |
| 30 | 30 | ||
| 31 | 31 | const { | |
| 32 | - createSecretKey, | ||
| 33 | 32 | getCryptoKeyHandle, | |
| 34 | - getKeyObjectHandle, | ||
| 35 | 33 | isKeyObject, | |
| 34 | + prepareSecretKey, | ||
| 36 | 35 | } = require('internal/crypto/keys'); | |
| 37 | 36 | ||
| 38 | 37 | const { | |
@@ -78,10 +77,10 @@ const validateParameters = hideStackFrames((hash, key, salt, info, length) => { | |||
| 78 | 77 | ||
| 79 | 78 | function prepareKey(key) { | |
| 80 | 79 | if (isKeyObject(key)) | |
| 81 | - return getKeyObjectHandle(key); | ||
| 80 | + return prepareSecretKey(key); | ||
| 82 | 81 | ||
| 83 | 82 | if (isAnyArrayBuffer(key)) | |
| 84 | - return getKeyObjectHandle(createSecretKey(key)); | ||
| 83 | + return key; | ||
| 85 | 84 | ||
| 86 | 85 | key = toBuf(key); | |
| 87 | 86 | ||
@@ -99,7 +98,7 @@ function prepareKey(key) { | |||
| 99 | 98 | key); | |
| 100 | 99 | } | |
| 101 | 100 | ||
| 102 | - return getKeyObjectHandle(createSecretKey(key)); | ||
| 101 | + return key; | ||
| 103 | 102 | } | |
| 104 | 103 | ||
| 105 | 104 | function hkdf(hash, key, salt, info, length, callback) { | |
@@ -157,18 +156,9 @@ function hkdfDeriveBits(algorithm, baseKey, length) { | |||
| 157 | 156 | if (length === 0) | |
| 158 | 157 | return PromiseResolve(new ArrayBuffer(0)); | |
| 159 | 158 | ||
| 160 | - let normalizedHash; | ||
| 161 | - try { | ||
| 162 | - normalizedHash = normalizeHashName(hash.name); | ||
| 163 | - } catch (err) { | ||
| 164 | - throw lazyDOMException( | ||
| 165 | - 'The operation failed for an operation-specific reason', | ||
| 166 | - { name: 'OperationError', cause: err }); | ||
| 167 | - } | ||
| 168 | - | ||
| 169 | 159 | return jobPromise(() => new HKDFJob( | |
| 170 | 160 | kCryptoJobWebCrypto, | |
| 171 | - normalizedHash, | ||
| 161 | + normalizeHashName(hash.name), | ||
| 172 | 162 | getCryptoKeyHandle(baseKey), | |
| 173 | 163 | salt, | |
| 174 | 164 | info, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -116,25 +116,13 @@ function pbkdf2DeriveBits(algorithm, baseKey, length) { | |||
| 116 | 116 | if (length === 0) | |
| 117 | 117 | return PromiseResolve(new ArrayBuffer(0)); | |
| 118 | 118 | ||
| 119 | - let password; | ||
| 120 | - let normalizedHash; | ||
| 121 | - try { | ||
| 122 | - // TODO(panva): call the job directly without needing to re-export the handle | ||
| 123 | - password = getCryptoKeyHandle(baseKey).export(); | ||
| 124 | - normalizedHash = normalizeHashName(hash.name); | ||
| 125 | - } catch (err) { | ||
| 126 | - throw lazyDOMException( | ||
| 127 | - 'The operation failed for an operation-specific reason', | ||
| 128 | - { name: 'OperationError', cause: err }); | ||
| 129 | - } | ||
| 130 | - | ||
| 131 | 119 | return jobPromise(() => new PBKDF2Job( | |
| 132 | 120 | kCryptoJobWebCrypto, | |
| 133 | - password, | ||
| 121 | + getCryptoKeyHandle(baseKey), | ||
| 134 | 122 | salt, | |
| 135 | 123 | iterations, | |
| 136 | 124 | length / 8, | |
| 137 | - normalizedHash)); | ||
| 125 | + normalizeHashName(hash.name))); | ||
| 138 | 126 | } | |
| 139 | 127 | ||
| 140 | 128 | module.exports = { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,5 +1,8 @@ | |||
| 1 | 1 | #include "crypto/crypto_argon2.h" | |
| 2 | 2 | #include "async_wrap-inl.h" | |
| 3 | + #include "base_object-inl.h" | ||
| 4 | + #include "crypto/crypto_keys.h" | ||
| 5 | + #include "memory_tracker-inl.h" | ||
| 3 | 6 | #include "threadpoolwork-inl.h" | |
| 4 | 7 | ||
| 5 | 8 | #if OPENSSL_WITH_ARGON2 | |
@@ -19,6 +22,7 @@ using v8::Value; | |||
| 19 | 22 | ||
| 20 | 23 | Argon2Config::Argon2Config(Argon2Config&& other) noexcept | |
| 21 | 24 | : mode{other.mode}, | |
| 25 | + key{std::move(other.key)}, | ||
| 22 | 26 | pass{std::move(other.pass)}, | |
| 23 | 27 | salt{std::move(other.salt)}, | |
| 24 | 28 | secret{std::move(other.secret)}, | |
@@ -36,8 +40,9 @@ Argon2Config& Argon2Config::operator=(Argon2Config&& other) noexcept { | |||
| 36 | 40 | } | |
| 37 | 41 | ||
| 38 | 42 | void Argon2Config::MemoryInfo(MemoryTracker* tracker) const { | |
| 43 | + if (key) tracker->TrackField("key", key); | ||
| 39 | 44 | if (IsCryptoJobAsync(mode)) { | |
| 40 | - tracker->TrackFieldWithSize("pass", pass.size()); | ||
| 45 | + if (!key) tracker->TrackFieldWithSize("pass", pass.size()); | ||
| 41 | 46 | tracker->TrackFieldWithSize("salt", salt.size()); | |
| 42 | 47 | tracker->TrackFieldWithSize("secret", secret.size()); | |
| 43 | 48 | tracker->TrackFieldWithSize("ad", ad.size()); | |
@@ -59,14 +64,23 @@ Maybe<void> Argon2Traits::AdditionalConfig( | |||
| 59 | 64 | ||
| 60 | 65 | config->mode = mode; | |
| 61 | 66 | ||
| 62 | - ArrayBufferOrViewContents<char> pass(args[offset]); | ||
| 67 | + CHECK(KeyObjectHandle::HasInstance(env, args[offset]) || | ||
| 68 | + IsAnyBufferSource(args[offset])); // pass | ||
| 63 | 69 | ArrayBufferOrViewContents<char> salt(args[offset + 1]); | |
| 64 | 70 | ArrayBufferOrViewContents<char> secret(args[offset + 6]); | |
| 65 | 71 | ArrayBufferOrViewContents<char> ad(args[offset + 7]); | |
| 66 | 72 | ||
| 67 | - if (!pass.CheckSizeInt32()) [[unlikely]] { | ||
| 68 | - THROW_ERR_OUT_OF_RANGE(env, "pass is too large"); | ||
| 69 | - return Nothing<void>(); | ||
| 73 | + if (KeyObjectHandle::HasInstance(env, args[offset])) { | ||
| 74 | + KeyObjectHandle* key; | ||
| 75 | + ASSIGN_OR_RETURN_UNWRAP(&key, args[offset], Nothing<void>()); | ||
| 76 | + config->key = key->Data().addRef(); | ||
| 77 | + } else { | ||
| 78 | + ArrayBufferOrViewContents<char> pass(args[offset]); | ||
| 79 | + if (!pass.CheckSizeInt32()) [[unlikely]] { | ||
| 80 | + THROW_ERR_OUT_OF_RANGE(env, "pass is too large"); | ||
| 81 | + return Nothing<void>(); | ||
| 82 | + } | ||
| 83 | + config->pass = IsCryptoJobAsync(mode) ? pass.ToCopy() : pass.ToByteSource(); | ||
| 70 | 84 | } | |
| 71 | 85 | ||
| 72 | 86 | if (!salt.CheckSizeInt32()) [[unlikely]] { | |
@@ -85,7 +99,6 @@ Maybe<void> Argon2Traits::AdditionalConfig( | |||
| 85 | 99 | } | |
| 86 | 100 | ||
| 87 | 101 | const bool isAsync = IsCryptoJobAsync(mode); | |
| 88 | - config->pass = isAsync ? pass.ToCopy() : pass.ToByteSource(); | ||
| 89 | 102 | config->salt = isAsync ? salt.ToCopy() : salt.ToByteSource(); | |
| 90 | 103 | config->secret = isAsync ? secret.ToCopy() : secret.ToByteSource(); | |
| 91 | 104 | config->ad = isAsync ? ad.ToCopy() : ad.ToByteSource(); | |
@@ -118,7 +131,13 @@ bool Argon2Traits::DeriveBits(Environment* env, | |||
| 118 | 131 | } | |
| 119 | 132 | ||
| 120 | 133 | // Both the pass and salt may be zero-length at this point | |
| 121 | - auto dp = ncrypto::argon2(config.pass, | ||
| 134 | + const ncrypto::Buffer<const char> pass{ | ||
| 135 | + .data = config.key ? config.key.GetSymmetricKey() | ||
| 136 | + : config.pass.data<const char>(), | ||
| 137 | + .len = config.key ? config.key.GetSymmetricKeySize() : config.pass.size(), | ||
| 138 | + }; | ||
| 139 | + | ||
| 140 | + auto dp = ncrypto::argon2(pass, | ||
| 122 | 141 | config.salt, | |
| 123 | 142 | config.lanes, | |
| 124 | 143 | config.keylen, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | 4 | #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS | |
| 5 | 5 | ||
| 6 | + #include "crypto/crypto_keys.h" | ||
| 6 | 7 | #include "crypto/crypto_util.h" | |
| 7 | 8 | ||
| 8 | 9 | namespace node::crypto { | |
@@ -22,6 +23,7 @@ namespace node::crypto { | |||
| 22 | 23 | ||
| 23 | 24 | struct Argon2Config final : public MemoryRetainer { | |
| 24 | 25 | CryptoJobMode mode; | |
| 26 | + KeyObjectData key; | ||
| 25 | 27 | ByteSource pass; | |
| 26 | 28 | ByteSource salt; | |
| 27 | 29 | ByteSource secret; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -24,6 +24,7 @@ HKDFConfig::HKDFConfig(HKDFConfig&& other) noexcept | |||
| 24 | 24 | length(other.length), | |
| 25 | 25 | digest(other.digest), | |
| 26 | 26 | key(std::move(other.key)), | |
| 27 | + key_data(std::move(other.key_data)), | ||
| 27 | 28 | salt(std::move(other.salt)), | |
| 28 | 29 | info(std::move(other.info)) {} | |
| 29 | 30 | ||
@@ -49,7 +50,8 @@ Maybe<void> HKDFTraits::AdditionalConfig( | |||
| 49 | 50 | params->mode = mode; | |
| 50 | 51 | ||
| 51 | 52 | CHECK(args[offset]->IsString()); // Hash | |
| 52 | - CHECK(args[offset + 1]->IsObject()); // Key | ||
| 53 | + CHECK(KeyObjectHandle::HasInstance(env, args[offset + 1]) || | ||
| 54 | + IsAnyBufferSource(args[offset + 1])); // Key | ||
| 53 | 55 | CHECK(IsAnyBufferSource(args[offset + 2])); // Salt | |
| 54 | 56 | CHECK(IsAnyBufferSource(args[offset + 3])); // Info | |
| 55 | 57 | CHECK(args[offset + 4]->IsUint32()); // Length | |
@@ -61,9 +63,19 @@ Maybe<void> HKDFTraits::AdditionalConfig( | |||
| 61 | 63 | return Nothing<void>(); | |
| 62 | 64 | } | |
| 63 | 65 | ||
| 64 | - KeyObjectHandle* key; | ||
| 65 | - ASSIGN_OR_RETURN_UNWRAP(&key, args[offset + 1], Nothing<void>()); | ||
| 66 | - params->key = key->Data().addRef(); | ||
| 66 | + if (KeyObjectHandle::HasInstance(env, args[offset + 1])) { | ||
| 67 | + KeyObjectHandle* key; | ||
| 68 | + ASSIGN_OR_RETURN_UNWRAP(&key, args[offset + 1], Nothing<void>()); | ||
| 69 | + params->key = key->Data().addRef(); | ||
| 70 | + } else { | ||
| 71 | + ArrayBufferOrViewContents<char> key_data(args[offset + 1]); | ||
| 72 | + if (!key_data.CheckSizeInt32()) [[unlikely]] { | ||
| 73 | + THROW_ERR_OUT_OF_RANGE(env, "key is too big"); | ||
| 74 | + return Nothing<void>(); | ||
| 75 | + } | ||
| 76 | + params->key_data = | ||
| 77 | + IsCryptoJobAsync(mode) ? key_data.ToCopy() : key_data.ToByteSource(); | ||
| 78 | + } | ||
| 67 | 79 | ||
| 68 | 80 | ArrayBufferOrViewContents<char> salt(args[offset + 2]); | |
| 69 | 81 | ArrayBufferOrViewContents<char> info(args[offset + 3]); | |
@@ -97,12 +109,16 @@ bool HKDFTraits::DeriveBits(Environment* env, | |||
| 97 | 109 | const HKDFConfig& params, | |
| 98 | 110 | ByteSource* out, | |
| 99 | 111 | CryptoJobMode mode) { | |
| 112 | + const ncrypto::Buffer<const unsigned char> key_data{ | ||
| 113 | + .data = params.key ? reinterpret_cast<const unsigned char*>( | ||
| 114 | + params.key.GetSymmetricKey()) | ||
| 115 | + : params.key_data.data<unsigned char>(), | ||
| 116 | + .len = params.key ? params.key.GetSymmetricKeySize() | ||
| 117 | + : params.key_data.size(), | ||
| 118 | + }; | ||
| 119 | + | ||
| 100 | 120 | auto dp = ncrypto::hkdf(params.digest, | |
| 101 | - ncrypto::Buffer<const unsigned char>{ | ||
| 102 | - .data = reinterpret_cast<const unsigned char*>( | ||
| 103 | - params.key.GetSymmetricKey()), | ||
| 104 | - .len = params.key.GetSymmetricKeySize(), | ||
| 105 | - }, | ||
| 121 | + key_data, | ||
| 106 | 122 | ncrypto::Buffer<const unsigned char>{ | |
| 107 | 123 | .data = params.info.data<const unsigned char>(), | |
| 108 | 124 | .len = params.info.size(), | |
@@ -120,9 +136,10 @@ bool HKDFTraits::DeriveBits(Environment* env, | |||
| 120 | 136 | } | |
| 121 | 137 | ||
| 122 | 138 | void HKDFConfig::MemoryInfo(MemoryTracker* tracker) const { | |
| 123 | - tracker->TrackField("key", key); | ||
| 139 | + if (key) tracker->TrackField("key", key); | ||
| 124 | 140 | // If the job is sync, then the HKDFConfig does not own the data | |
| 125 | 141 | if (IsCryptoJobAsync(mode)) { | |
| 142 | + if (!key) tracker->TrackFieldWithSize("key", key_data.size()); | ||
| 126 | 143 | tracker->TrackFieldWithSize("salt", salt.size()); | |
| 127 | 144 | tracker->TrackFieldWithSize("info", info.size()); | |
| 128 | 145 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -16,6 +16,7 @@ struct HKDFConfig final : public MemoryRetainer { | |||
| 16 | 16 | size_t length; | |
| 17 | 17 | ncrypto::Digest digest; | |
| 18 | 18 | KeyObjectData key; | |
| 19 | + ByteSource key_data; | ||
| 19 | 20 | ByteSource salt; | |
| 20 | 21 | ByteSource info; | |
| 21 | 22 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,5 +1,7 @@ | |||
| 1 | 1 | #include "crypto/crypto_pbkdf2.h" | |
| 2 | 2 | #include "async_wrap-inl.h" | |
| 3 | + #include "base_object-inl.h" | ||
| 4 | + #include "crypto/crypto_keys.h" | ||
| 3 | 5 | #include "crypto/crypto_util.h" | |
| 4 | 6 | #include "env-inl.h" | |
| 5 | 7 | #include "memory_tracker-inl.h" | |
@@ -21,6 +23,7 @@ using v8::Value; | |||
| 21 | 23 | namespace crypto { | |
| 22 | 24 | PBKDF2Config::PBKDF2Config(PBKDF2Config&& other) noexcept | |
| 23 | 25 | : mode(other.mode), | |
| 26 | + key(std::move(other.key)), | ||
| 24 | 27 | pass(std::move(other.pass)), | |
| 25 | 28 | salt(std::move(other.salt)), | |
| 26 | 29 | iterations(other.iterations), | |
@@ -34,9 +37,10 @@ PBKDF2Config& PBKDF2Config::operator=(PBKDF2Config&& other) noexcept { | |||
| 34 | 37 | } | |
| 35 | 38 | ||
| 36 | 39 | void PBKDF2Config::MemoryInfo(MemoryTracker* tracker) const { | |
| 37 | - // The job is sync, the PBKDF2Config does not own the data. | ||
| 40 | + // If the job is sync, PBKDF2Config does not own the data. | ||
| 41 | + if (key) tracker->TrackField("key", key); | ||
| 38 | 42 | if (IsCryptoJobAsync(mode)) { | |
| 39 | - tracker->TrackFieldWithSize("pass", pass.size()); | ||
| 43 | + if (!key) tracker->TrackFieldWithSize("pass", pass.size()); | ||
| 40 | 44 | tracker->TrackFieldWithSize("salt", salt.size()); | |
| 41 | 45 | } | |
| 42 | 46 | } | |
@@ -63,21 +67,28 @@ Maybe<void> PBKDF2Traits::AdditionalConfig( | |||
| 63 | 67 | ||
| 64 | 68 | params->mode = mode; | |
| 65 | 69 | ||
| 66 | - ArrayBufferOrViewContents<char> pass(args[offset]); | ||
| 70 | + CHECK(KeyObjectHandle::HasInstance(env, args[offset]) || | ||
| 71 | + IsAnyBufferSource(args[offset])); // pass | ||
| 67 | 72 | ArrayBufferOrViewContents<char> salt(args[offset + 1]); | |
| 68 | 73 | ||
| 69 | - if (!pass.CheckSizeInt32()) [[unlikely]] { | ||
| 70 | - THROW_ERR_OUT_OF_RANGE(env, "pass is too large"); | ||
| 71 | - return Nothing<void>(); | ||
| 74 | + if (KeyObjectHandle::HasInstance(env, args[offset])) { | ||
| 75 | + KeyObjectHandle* key; | ||
| 76 | + ASSIGN_OR_RETURN_UNWRAP(&key, args[offset], Nothing<void>()); | ||
| 77 | + params->key = key->Data().addRef(); | ||
| 78 | + } else { | ||
| 79 | + ArrayBufferOrViewContents<char> pass(args[offset]); | ||
| 80 | + if (!pass.CheckSizeInt32()) [[unlikely]] { | ||
| 81 | + THROW_ERR_OUT_OF_RANGE(env, "pass is too large"); | ||
| 82 | + return Nothing<void>(); | ||
| 83 | + } | ||
| 84 | + params->pass = IsCryptoJobAsync(mode) ? pass.ToCopy() : pass.ToByteSource(); | ||
| 72 | 85 | } | |
| 73 | 86 | ||
| 74 | 87 | if (!salt.CheckSizeInt32()) [[unlikely]] { | |
| 75 | 88 | THROW_ERR_OUT_OF_RANGE(env, "salt is too large"); | |
| 76 | 89 | return Nothing<void>(); | |
| 77 | 90 | } | |
| 78 | 91 | ||
| 79 | - params->pass = IsCryptoJobAsync(mode) ? pass.ToCopy() : pass.ToByteSource(); | ||
| 80 | - | ||
| 81 | 92 | params->salt = IsCryptoJobAsync(mode) ? salt.ToCopy() : salt.ToByteSource(); | |
| 82 | 93 | ||
| 83 | 94 | CHECK(args[offset + 2]->IsInt32()); // iteration_count | |
@@ -111,11 +122,14 @@ bool PBKDF2Traits::DeriveBits(Environment* env, | |||
| 111 | 122 | ByteSource* out, | |
| 112 | 123 | CryptoJobMode mode) { | |
| 113 | 124 | // Both pass and salt may be zero length here. | |
| 125 | + const ncrypto::Buffer<const char> pass{ | ||
| 126 | + .data = params.key ? params.key.GetSymmetricKey() | ||
| 127 | + : params.pass.data<const char>(), | ||
| 128 | + .len = params.key ? params.key.GetSymmetricKeySize() : params.pass.size(), | ||
| 129 | + }; | ||
| 130 | + | ||
| 114 | 131 | auto dp = ncrypto::pbkdf2(params.digest, | |
| 115 | - ncrypto::Buffer<const char>{ | ||
| 116 | - .data = params.pass.data<const char>(), | ||
| 117 | - .len = params.pass.size(), | ||
| 118 | - }, | ||
| 132 | + pass, | ||
| 119 | 133 | ncrypto::Buffer<const unsigned char>{ | |
| 120 | 134 | .data = params.salt.data<unsigned char>(), | |
| 121 | 135 | .len = params.salt.size(), | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3,8 +3,9 @@ | |||
| 3 | 3 | ||
| 4 | 4 | #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS | |
| 5 | 5 | ||
| 6 | - #include "crypto/crypto_util.h" | ||
| 7 | 6 | #include "async_wrap.h" | |
| 7 | + #include "crypto/crypto_keys.h" | ||
| 8 | + #include "crypto/crypto_util.h" | ||
| 8 | 9 | #include "env.h" | |
| 9 | 10 | #include "memory_tracker.h" | |
| 10 | 11 | #include "v8.h" | |
@@ -26,6 +27,7 @@ namespace crypto { | |||
| 26 | 27 | ||
| 27 | 28 | struct PBKDF2Config final : public MemoryRetainer { | |
| 28 | 29 | CryptoJobMode mode; | |
| 30 | + KeyObjectData key; | ||
| 29 | 31 | ByteSource pass; | |
| 30 | 32 | ByteSource salt; | |
| 31 | 33 | int32_t iterations; | |
| Back | FazBrowse Home | New Git URL |
0 commit comments