Skip to content

Commit a149976

Browse files
emargolispull[bot]
authored andcommitted
Fix Dependency Loop Error Introduced with #14676 (#15127)
Moved some of the Spake2p defines to the CHIPCryptoPAL.h
1 parent f9a2aa7 commit a149976

File tree

12 files changed

+79
-57
lines changed

12 files changed

+79
-57
lines changed

examples/chip-tool/commands/pairing/OpenCommissioningWindowCommand.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ class OpenCommissioningWindowCommand : public CHIPCommand
3131
AddArgument("node-id", 0, UINT64_MAX, &mNodeId);
3232
AddArgument("option", 0, 2, &mCommissioningWindowOption);
3333
AddArgument("timeout", 0, UINT16_MAX, &mTimeout);
34-
AddArgument("iteration", chip::kPBKDFMinimumIterations, chip::kPBKDFMaximumIterations, &mIteration);
34+
AddArgument("iteration", chip::Crypto::kSpake2pPBKDFMinimumIterations, chip::Crypto::kSpake2pPBKDFMaximumIterations,
35+
&mIteration);
3536
AddArgument("discriminator", 0, 4096, &mDiscriminator);
3637
}
3738

src/app/clusters/administrator-commissioning-server/administrator-commissioning-server.cpp

+8-4
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,14 @@ bool emberAfAdministratorCommissioningClusterOpenCommissioningWindowCallback(
109109
VerifyOrExit(Server::GetInstance().GetCommissioningWindowManager().CommissioningWindowStatus() ==
110110
CommissioningWindowStatus::kWindowNotOpen,
111111
status.Emplace(StatusCode::EMBER_ZCL_STATUS_CODE_BUSY));
112-
VerifyOrExit(iterations >= kPBKDFMinimumIterations, status.Emplace(StatusCode::EMBER_ZCL_STATUS_CODE_PAKE_PARAMETER_ERROR));
113-
VerifyOrExit(iterations <= kPBKDFMaximumIterations, status.Emplace(StatusCode::EMBER_ZCL_STATUS_CODE_PAKE_PARAMETER_ERROR));
114-
VerifyOrExit(salt.size() >= kPBKDFMinimumSaltLen, status.Emplace(StatusCode::EMBER_ZCL_STATUS_CODE_PAKE_PARAMETER_ERROR));
115-
VerifyOrExit(salt.size() <= kPBKDFMaximumSaltLen, status.Emplace(StatusCode::EMBER_ZCL_STATUS_CODE_PAKE_PARAMETER_ERROR));
112+
VerifyOrExit(iterations >= Crypto::kSpake2pPBKDFMinimumIterations,
113+
status.Emplace(StatusCode::EMBER_ZCL_STATUS_CODE_PAKE_PARAMETER_ERROR));
114+
VerifyOrExit(iterations <= Crypto::kSpake2pPBKDFMaximumIterations,
115+
status.Emplace(StatusCode::EMBER_ZCL_STATUS_CODE_PAKE_PARAMETER_ERROR));
116+
VerifyOrExit(salt.size() >= Crypto::kSpake2pPBKDFMinimumSaltLen,
117+
status.Emplace(StatusCode::EMBER_ZCL_STATUS_CODE_PAKE_PARAMETER_ERROR));
118+
VerifyOrExit(salt.size() <= Crypto::kSpake2pPBKDFMaximumSaltLen,
119+
status.Emplace(StatusCode::EMBER_ZCL_STATUS_CODE_PAKE_PARAMETER_ERROR));
116120
VerifyOrExit(commissioningTimeout <= kMaxCommissionioningTimeoutSeconds,
117121
status.Emplace(StatusCode::EMBER_ZCL_STATUS_CODE_PAKE_PARAMETER_ERROR));
118122
VerifyOrExit(discriminator <= kMaxDiscriminatorValue, status.Emplace(StatusCode::EMBER_ZCL_STATUS_CODE_PAKE_PARAMETER_ERROR));

src/app/server/CommissioningWindowManager.cpp

+8-8
Original file line numberDiff line numberDiff line change
@@ -187,18 +187,18 @@ CHIP_ERROR CommissioningWindowManager::OpenCommissioningWindow()
187187
}
188188
else
189189
{
190-
uint32_t iterationCount = 0;
191-
uint8_t salt[kPBKDFMaximumSaltLen] = { 0 };
192-
size_t saltLen = 0;
193-
PASEVerifierSerialized serializedVerifier = { 0 };
194-
size_t serializedVerifierLen = 0;
190+
uint32_t iterationCount = 0;
191+
uint8_t salt[Crypto::kSpake2pPBKDFMaximumSaltLen] = { 0 };
192+
size_t saltLen = 0;
193+
PASEVerifierSerialized serializedVerifier = { 0 };
194+
size_t serializedVerifierLen = 0;
195195
PASEVerifier verifier;
196196

197197
ReturnErrorOnFailure(DeviceLayer::ConfigurationMgr().GetSpake2pIterationCount(iterationCount));
198198
ReturnErrorOnFailure(DeviceLayer::ConfigurationMgr().GetSpake2pSalt(salt, sizeof(salt), saltLen));
199-
ReturnErrorOnFailure(DeviceLayer::ConfigurationMgr().GetSpake2pVerifier(serializedVerifier, kSpake2pSerializedVerifierSize,
200-
serializedVerifierLen));
201-
VerifyOrReturnError(kSpake2pSerializedVerifierSize == serializedVerifierLen, CHIP_ERROR_INVALID_ARGUMENT);
199+
ReturnErrorOnFailure(DeviceLayer::ConfigurationMgr().GetSpake2pVerifier(
200+
serializedVerifier, Crypto::kSpake2pSerializedVerifierSize, serializedVerifierLen));
201+
VerifyOrReturnError(Crypto::kSpake2pSerializedVerifierSize == serializedVerifierLen, CHIP_ERROR_INVALID_ARGUMENT);
202202
ReturnErrorOnFailure(verifier.Deserialize(ByteSpan(serializedVerifier)));
203203

204204
ReturnErrorOnFailure(

src/app/server/CommissioningWindowManager.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ class CommissioningWindowManager : public SessionEstablishmentDelegate
111111
PasscodeId mECMPasscodeID = kDefaultCommissioningPasscodeId;
112112
uint32_t mECMIterations = 0;
113113
uint32_t mECMSaltLength = 0;
114-
uint8_t mECMSalt[kPBKDFMaximumSaltLen];
114+
uint8_t mECMSalt[Crypto::kSpake2pPBKDFMaximumSaltLen];
115115
};
116116

117117
} // namespace chip

src/app/tests/TestCommissionManager.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,8 @@ void CheckCommissioningWindowManagerEnhancedWindowTask(intptr_t context)
118118
NL_TEST_ASSERT(suite, err == CHIP_NO_ERROR);
119119
uint16_t newDiscriminator = static_cast<uint16_t>(originDiscriminator + 1);
120120
chip::PASEVerifier verifier;
121-
constexpr uint32_t kIterations = chip::kPBKDFMinimumIterations;
122-
uint8_t salt[chip::kPBKDFMinimumSaltLen];
121+
constexpr uint32_t kIterations = chip::Crypto::kSpake2pPBKDFMinimumIterations;
122+
uint8_t salt[chip::Crypto::kSpake2pPBKDFMinimumSaltLen];
123123
chip::ByteSpan saltData(salt);
124124
constexpr chip::PasscodeId kPasscodeID = 1;
125125
uint16_t currentDiscriminator;

src/controller/java/CHIPDeviceController-JNI.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,8 @@ JNI_METHOD(jobject, computePaseVerifier)
644644
err = verifier.Serialize(serializedVerifierSpan);
645645
SuccessOrExit(err);
646646

647-
err = JniReferences::GetInstance().N2J_ByteArray(env, serializedVerifier, kSpake2pSerializedVerifierSize, verifierBytes);
647+
err =
648+
JniReferences::GetInstance().N2J_ByteArray(env, serializedVerifier, Crypto::kSpake2pSerializedVerifierSize, verifierBytes);
648649
SuccessOrExit(err);
649650

650651
err = N2J_PaseVerifierParams(env, setupPincode, static_cast<jlong>(passcodeId), verifierBytes, params);

src/crypto/CHIPCryptoPAL.h

+20
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,26 @@ const uint8_t spake2p_N_p256[65] = {
134134
0xd3, 0x60, 0x34, 0x80, 0x8c, 0xd5, 0x64, 0x49, 0x0b, 0x1e, 0x65, 0x6e, 0xdb, 0xe7,
135135
};
136136

137+
/** @brief Spake2p parameters.
138+
*
139+
* Specifications section 3.9. Password-Based Key Derivation Function
140+
* Specifications section 5.1.1.6
141+
**/
142+
constexpr uint32_t kSpake2pPBKDFMinimumIterations = 1000;
143+
constexpr uint32_t kSpake2pPBKDFMaximumIterations = 100000;
144+
constexpr uint32_t kSpake2pPBKDFMinimumSaltLen = 16;
145+
constexpr uint32_t kSpake2pPBKDFMaximumSaltLen = 32;
146+
147+
/** @brief Serialized format of the PASE Verifier components.
148+
*
149+
* This is used when the Verifier should be presented in a serialized form.
150+
* For example, when it is generated using PBKDF function, when stored in the
151+
* memory or when sent over the wire.
152+
* The serialized format is concatentation of { W0, L } verifier components
153+
* as per Specifications section 3.10. Password-Authenticated Key Exchange.
154+
**/
155+
constexpr size_t kSpake2pSerializedVerifierSize = kP256_FE_Length + kP256_Point_Length;
156+
137157
/**
138158
* Spake2+ state machine to ensure proper execution of the protocol.
139159
*/

src/include/platform/internal/GenericConfigurationManagerImpl.cpp

+12-7
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#define GENERIC_CONFIGURATION_MANAGER_IMPL_CPP
2828

2929
#include <ble/CHIPBleServiceData.h>
30+
#include <crypto/CHIPCryptoPAL.h>
3031
#include <inttypes.h>
3132
#include <lib/core/CHIPConfig.h>
3233
#include <lib/support/Base64.h>
@@ -35,7 +36,6 @@
3536
#include <lib/support/ScopedBuffer.h>
3637
#include <platform/internal/CHIPDeviceLayerInternal.h>
3738
#include <platform/internal/GenericConfigurationManagerImpl.h>
38-
#include <protocols/secure_channel/PASESession.h>
3939

4040
#if CHIP_DEVICE_CONFIG_ENABLE_THREAD
4141
#include <platform/ThreadStackManager.h>
@@ -332,9 +332,11 @@ CHIP_ERROR GenericConfigurationManagerImpl<ConfigClass>::GetSpake2pIterationCoun
332332
template <class ConfigClass>
333333
CHIP_ERROR GenericConfigurationManagerImpl<ConfigClass>::GetSpake2pSalt(uint8_t * buf, size_t bufSize, size_t & saltLen)
334334
{
335-
CHIP_ERROR err = CHIP_NO_ERROR;
336-
char saltB64[BASE64_ENCODED_LEN(chip::kPBKDFMaximumSaltLen) + 1] = { 0 };
337-
size_t saltB64Len = 0;
335+
static constexpr size_t kSpake2pSalt_MaxBase64Len = BASE64_ENCODED_LEN(chip::Crypto::kSpake2pPBKDFMaximumSaltLen) + 1;
336+
337+
CHIP_ERROR err = CHIP_NO_ERROR;
338+
char saltB64[kSpake2pSalt_MaxBase64Len] = { 0 };
339+
size_t saltB64Len = 0;
338340

339341
err = ReadConfigValueStr(ConfigClass::kConfigKey_Spake2pSalt, saltB64, sizeof(saltB64), saltB64Len);
340342
err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
@@ -359,9 +361,12 @@ CHIP_ERROR GenericConfigurationManagerImpl<ConfigClass>::GetSpake2pSalt(uint8_t
359361
template <class ConfigClass>
360362
CHIP_ERROR GenericConfigurationManagerImpl<ConfigClass>::GetSpake2pVerifier(uint8_t * buf, size_t bufSize, size_t & verifierLen)
361363
{
362-
CHIP_ERROR err = CHIP_NO_ERROR;
363-
char verifierB64[BASE64_ENCODED_LEN(chip::kSpake2pSerializedVerifierSize) + 1] = { 0 };
364-
size_t verifierB64Len = 0;
364+
static constexpr size_t kSpake2pSerializedVerifier_MaxBase64Len =
365+
BASE64_ENCODED_LEN(chip::Crypto::kSpake2pSerializedVerifierSize) + 1;
366+
367+
CHIP_ERROR err = CHIP_NO_ERROR;
368+
char verifierB64[kSpake2pSerializedVerifier_MaxBase64Len] = { 0 };
369+
size_t verifierB64Len = 0;
365370

366371
err = ReadConfigValueStr(ConfigClass::kConfigKey_Spake2pVerifier, verifierB64, sizeof(verifierB64), verifierB64Len);
367372
err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;

src/protocols/secure_channel/PASESession.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,8 @@ CHIP_ERROR PASESession::WaitForPairing(const PASEVerifier & verifier, uint32_t p
280280
// Return early on error here, as we have not initialized any state yet
281281
ReturnErrorCodeIf(salt.empty(), CHIP_ERROR_INVALID_ARGUMENT);
282282
ReturnErrorCodeIf(salt.data() == nullptr, CHIP_ERROR_INVALID_ARGUMENT);
283-
ReturnErrorCodeIf(salt.size() < kPBKDFMinimumSaltLen || salt.size() > kPBKDFMaximumSaltLen, CHIP_ERROR_INVALID_ARGUMENT);
283+
ReturnErrorCodeIf(salt.size() < Crypto::kSpake2pPBKDFMinimumSaltLen || salt.size() > Crypto::kSpake2pPBKDFMaximumSaltLen,
284+
CHIP_ERROR_INVALID_ARGUMENT);
284285

285286
CHIP_ERROR err = Init(mySessionId, kSetupPINCodeUndefinedValue, delegate);
286287
// From here onwards, let's go to exit on error, as some state might have already
@@ -974,19 +975,19 @@ CHIP_ERROR PASESession::OnMessageReceived(ExchangeContext * exchange, const Payl
974975

975976
CHIP_ERROR PASEVerifier::Serialize(MutableByteSpan & outSerialized)
976977
{
977-
VerifyOrReturnError(outSerialized.size() >= kSpake2pSerializedVerifierSize, CHIP_ERROR_INVALID_ARGUMENT);
978+
VerifyOrReturnError(outSerialized.size() >= Crypto::kSpake2pSerializedVerifierSize, CHIP_ERROR_INVALID_ARGUMENT);
978979

979980
memcpy(&outSerialized.data()[0], mW0, sizeof(mW0));
980981
memcpy(&outSerialized.data()[sizeof(mW0)], mL, sizeof(mL));
981982

982-
outSerialized.reduce_size(kSpake2pSerializedVerifierSize);
983+
outSerialized.reduce_size(Crypto::kSpake2pSerializedVerifierSize);
983984

984985
return CHIP_NO_ERROR;
985986
}
986987

987988
CHIP_ERROR PASEVerifier::Deserialize(ByteSpan inSerialized)
988989
{
989-
VerifyOrReturnError(inSerialized.size() >= kSpake2pSerializedVerifierSize, CHIP_ERROR_INVALID_ARGUMENT);
990+
VerifyOrReturnError(inSerialized.size() >= Crypto::kSpake2pSerializedVerifierSize, CHIP_ERROR_INVALID_ARGUMENT);
990991

991992
memcpy(mW0, &inSerialized.data()[0], sizeof(mW0));
992993
memcpy(mL, &inSerialized.data()[sizeof(mW0)], sizeof(mL));

src/protocols/secure_channel/PASESession.h

+2-18
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,6 @@ extern const char * kSpake2pR2ISessionInfo;
5050

5151
constexpr uint16_t kPBKDFParamRandomNumberSize = 32;
5252

53-
// Specifications section 3.9. Password-Based Key Derivation Function
54-
constexpr uint32_t kPBKDFMinimumIterations = 1000;
55-
constexpr uint32_t kPBKDFMaximumIterations = 100000;
56-
constexpr uint32_t kPBKDFMinimumSaltLen = 16;
57-
constexpr uint32_t kPBKDFMaximumSaltLen = 32;
58-
59-
// Specifications section 5.1.1.6
6053
constexpr uint32_t kSetupPINCodeMaximumValue = 99999998;
6154
constexpr uint32_t kSetupPINCodeUndefinedValue = 0;
6255

@@ -75,17 +68,6 @@ struct PASESessionSerializable
7568
uint16_t mPeerSessionId;
7669
};
7770

78-
/** @brief Serialized format of the PASE Verifier components.
79-
*
80-
* This is used when the Verifier should be presented in a serialized form.
81-
* For example, when it is generated using PBKDF function, when stored in the
82-
* memory or when sent over the wire.
83-
* The serialized format is concatentation of 'W0' and 'L' verifier components:
84-
* { PASEVerifier.mW0[kP256_FE_Length], PASEVerifier.mL[kP256_Point_Length] }
85-
**/
86-
constexpr size_t kSpake2pSerializedVerifierSize = kP256_FE_Length + kP256_Point_Length;
87-
typedef uint8_t PASEVerifierSerialized[kSpake2pSerializedVerifierSize];
88-
8971
struct PASEVerifier
9072
{
9173
uint8_t mW0[kP256_FE_Length];
@@ -95,6 +77,8 @@ struct PASEVerifier
9577
CHIP_ERROR Deserialize(ByteSpan inSerialized);
9678
};
9779

80+
typedef uint8_t PASEVerifierSerialized[Crypto::kSpake2pSerializedVerifierSize];
81+
9882
class DLL_EXPORT PASESession : public Messaging::ExchangeDelegate, public PairingSession
9983
{
10084
public:

src/protocols/secure_channel/tests/TestPASESession.cpp

+6-4
Original file line numberDiff line numberDiff line change
@@ -445,15 +445,17 @@ void PASEVerifierSerializeTest(nlTestSuite * inSuite, void * inContext)
445445
PASEVerifierSerialized serializedVerifier;
446446
MutableByteSpan serializedVerifierSpan(serializedVerifier);
447447
NL_TEST_ASSERT(inSuite, verifier.Serialize(serializedVerifierSpan) == CHIP_NO_ERROR);
448-
NL_TEST_ASSERT(inSuite, serializedVerifierSpan.size() == kSpake2pSerializedVerifierSize);
449-
NL_TEST_ASSERT(inSuite, memcmp(serializedVerifier, sTestSpake2p01_SerializedVerifier, kSpake2pSerializedVerifierSize) == 0);
448+
NL_TEST_ASSERT(inSuite, serializedVerifierSpan.size() == Crypto::kSpake2pSerializedVerifierSize);
449+
NL_TEST_ASSERT(inSuite,
450+
memcmp(serializedVerifier, sTestSpake2p01_SerializedVerifier, Crypto::kSpake2pSerializedVerifierSize) == 0);
450451

451452
PASEVerifierSerialized serializedVerifier2;
452453
MutableByteSpan serializedVerifier2Span(serializedVerifier2);
453-
NL_TEST_ASSERT(inSuite, chip::Crypto::DRBG_get_bytes(serializedVerifier, kSpake2pSerializedVerifierSize) == CHIP_NO_ERROR);
454+
NL_TEST_ASSERT(inSuite,
455+
chip::Crypto::DRBG_get_bytes(serializedVerifier, Crypto::kSpake2pSerializedVerifierSize) == CHIP_NO_ERROR);
454456
NL_TEST_ASSERT(inSuite, verifier.Deserialize(ByteSpan(serializedVerifier)) == CHIP_NO_ERROR);
455457
NL_TEST_ASSERT(inSuite, verifier.Serialize(serializedVerifier2Span) == CHIP_NO_ERROR);
456-
NL_TEST_ASSERT(inSuite, memcmp(serializedVerifier, serializedVerifier2, kSpake2pSerializedVerifierSize) == 0);
458+
NL_TEST_ASSERT(inSuite, memcmp(serializedVerifier, serializedVerifier2, Crypto::kSpake2pSerializedVerifierSize) == 0);
457459
}
458460

459461
// Test Suite

src/tools/spake2p/Cmd_GenVerifier.cpp

+11-7
Original file line numberDiff line numberDiff line change
@@ -168,15 +168,17 @@ bool HandleOption(const char * progName, OptionSet * optSet, int id, const char
168168

169169
case 'i':
170170
if (!ParseInt(arg, gIterationCount) ||
171-
!(gIterationCount >= chip::kPBKDFMinimumIterations && gIterationCount <= chip::kPBKDFMaximumIterations))
171+
!(gIterationCount >= chip::Crypto::kSpake2pPBKDFMinimumIterations &&
172+
gIterationCount <= chip::Crypto::kSpake2pPBKDFMaximumIterations))
172173
{
173174
PrintArgError("%s: Invalid value specified for the iteration-count parameter: %s\n", progName, arg);
174175
return false;
175176
}
176177
break;
177178

178179
case 'l':
179-
if (!ParseInt(arg, gSaltLen) || !(gSaltLen >= chip::kPBKDFMinimumSaltLen && gSaltLen <= chip::kPBKDFMaximumSaltLen))
180+
if (!ParseInt(arg, gSaltLen) ||
181+
!(gSaltLen >= chip::Crypto::kSpake2pPBKDFMinimumSaltLen && gSaltLen <= chip::Crypto::kSpake2pPBKDFMaximumSaltLen))
180182
{
181183
PrintArgError("%s: Invalid value specified for salt length parameter: %s\n", progName, arg);
182184
return false;
@@ -185,7 +187,8 @@ bool HandleOption(const char * progName, OptionSet * optSet, int id, const char
185187

186188
case 's':
187189
gSalt = arg;
188-
if (!(strlen(gSalt) >= chip::kPBKDFMinimumSaltLen && strlen(gSalt) <= chip::kPBKDFMaximumSaltLen))
190+
if (!(strlen(gSalt) >= chip::Crypto::kSpake2pPBKDFMinimumSaltLen &&
191+
strlen(gSalt) <= chip::Crypto::kSpake2pPBKDFMaximumSaltLen))
189192
{
190193
fprintf(stderr, "%s: Invalid legth of the specified salt parameter: %s\n", progName, arg);
191194
return false;
@@ -268,7 +271,7 @@ bool Cmd_GenVerifier(int argc, char * argv[])
268271

269272
for (uint32_t i = 0; i < gCount; i++)
270273
{
271-
uint8_t salt[chip::kPBKDFMaximumSaltLen];
274+
uint8_t salt[chip::Crypto::kSpake2pPBKDFMaximumSaltLen];
272275
if (gSalt == nullptr)
273276
{
274277
CHIP_ERROR err = chip::Crypto::DRBG_get_bytes(salt, gSaltLen);
@@ -301,12 +304,13 @@ bool Cmd_GenVerifier(int argc, char * argv[])
301304
return false;
302305
}
303306

304-
char saltB64[BASE64_ENCODED_LEN(chip::kPBKDFMaximumSaltLen) + 1];
307+
char saltB64[BASE64_ENCODED_LEN(chip::Crypto::kSpake2pPBKDFMaximumSaltLen) + 1];
305308
uint32_t saltB64Len = chip::Base64Encode32(salt, gSaltLen, saltB64);
306309
saltB64[saltB64Len] = '\0';
307310

308-
char verifierB64[BASE64_ENCODED_LEN(chip::kSpake2pSerializedVerifierSize) + 1];
309-
uint32_t verifierB64Len = chip::Base64Encode32(serializedVerifier, chip::kSpake2pSerializedVerifierSize, verifierB64);
311+
char verifierB64[BASE64_ENCODED_LEN(chip::Crypto::kSpake2pSerializedVerifierSize) + 1];
312+
uint32_t verifierB64Len =
313+
chip::Base64Encode32(serializedVerifier, chip::Crypto::kSpake2pSerializedVerifierSize, verifierB64);
310314
verifierB64[verifierB64Len] = '\0';
311315

312316
if (fprintf(outFile, "%d,%08d,%d,%s,%s\n", i, gPinCode, gIterationCount, saltB64, verifierB64) < 0 || ferror(outFile))

0 commit comments

Comments
 (0)