spake2p: generate verifier sets with specified PIN codes in a file (#23606)
* spake2: generate verifier sets with specific PIN codes in a file
* Restyled by clang-format
* Restyled by prettier-markdown
* reviewing changes
Co-authored-by: Restyled.io <commits@restyled.io>
diff --git a/src/tools/spake2p/Cmd_GenVerifier.cpp b/src/tools/spake2p/Cmd_GenVerifier.cpp
index 959c4d3..04bfe99 100644
--- a/src/tools/spake2p/Cmd_GenVerifier.cpp
+++ b/src/tools/spake2p/Cmd_GenVerifier.cpp
@@ -30,6 +30,7 @@
#include "spake2p.h"
#include <errno.h>
+#include <stdio.h>
#include <CHIPVersion.h>
#include <crypto/CHIPCryptoPAL.h>
@@ -52,6 +53,7 @@
{
{ "count", kArgumentRequired, 'c' },
{ "pin-code", kArgumentRequired, 'p' },
+ { "pin-code-file", kArgumentRequired, 'f' },
{ "iteration-count", kArgumentRequired, 'i' },
{ "salt-len", kArgumentRequired, 'l' },
{ "salt", kArgumentRequired, 's' },
@@ -85,6 +87,20 @@
" * 12345678\n"
" * 87654321\n"
"\n"
+ " -f, --pin-code-file <file>\n"
+ "\n"
+ " A file which contains all the PIN codes to generate verifiers.\n"
+ " Each line in this file should be a valid PIN code in the decimal number format. If the row count\n"
+ " of this file is less than the number of pin-code/verifier parameter sets to be generated, the\n"
+ " first few verifier sets will be generated using the PIN codes in this file, and the next will\n"
+ " use the random PIN codes.\n"
+ " The following file is a example with 5 PIN codes:\n"
+ " 1234\n"
+ " 2345\n"
+ " 3456\n"
+ " 4567\n"
+ " 5678\n"
+ "\n"
" -i, --iteration-count <int>\n"
"\n"
" SPAKE2P PBKDF iteration count. The value should be positive integer in range [1000..100000].\n"
@@ -143,6 +159,33 @@
uint8_t gSaltDecodedLen = 0;
uint8_t gSaltLen = 0;
const char * gOutFileName = nullptr;
+FILE * gPinCodeFile = nullptr;
+
+static uint32_t GetNextPinCode()
+{
+ if (!gPinCodeFile)
+ {
+ return chip::kSetupPINCodeUndefinedValue;
+ }
+ char * pinCodeStr = nullptr;
+ size_t readSize = 8;
+ uint32_t pinCode = chip::kSetupPINCodeUndefinedValue;
+ if (getline(&pinCodeStr, &readSize, gPinCodeFile) != -1)
+ {
+ if (readSize > 8)
+ {
+ pinCodeStr[8] = 0;
+ }
+ pinCode = static_cast<uint32_t>(atoi(pinCodeStr));
+ if (!chip::SetupPayload::IsValidSetupPIN(pinCode))
+ {
+ fprintf(stderr, "The line %s in PIN codes file is invalid, using a random PIN code.\n", pinCodeStr);
+ pinCode = chip::kSetupPINCodeUndefinedValue;
+ }
+ free(pinCodeStr);
+ }
+ return pinCode;
+}
bool HandleOption(const char * progName, OptionSet * optSet, int id, const char * name, const char * arg)
{
@@ -157,17 +200,23 @@
break;
case 'p':
// Specifications sections 5.1.1.6 and 5.1.6.1
- if (!ParseInt(arg, gPinCode) || (gPinCode > chip::kSetupPINCodeMaximumValue) ||
- (gPinCode == chip::kSetupPINCodeUndefinedValue) || (gPinCode == 11111111) || (gPinCode == 22222222) ||
- (gPinCode == 33333333) || (gPinCode == 44444444) || (gPinCode == 55555555) || (gPinCode == 66666666) ||
- (gPinCode == 77777777) || (gPinCode == 88888888) || (gPinCode == 99999999) || (gPinCode == 12345678) ||
- (gPinCode == 87654321))
+ if (!ParseInt(arg, gPinCode) || (!chip::SetupPayload::IsValidSetupPIN(gPinCode)))
{
PrintArgError("%s: Invalid value specified for pin-code parameter: %s\n", progName, arg);
return false;
}
break;
+ case 'f':
+ gPinCodeFile = fopen(arg, "r");
+ if (!gPinCodeFile)
+ {
+ PrintArgError("%s: Failed to open the PIN code file: %s\n", progName, arg);
+ return false;
+ }
+ gPinCode = GetNextPinCode();
+ break;
+
case 'i':
if (!ParseInt(arg, gIterationCount) ||
!(gIterationCount >= chip::kSpake2p_Min_PBKDF_Iterations && gIterationCount <= chip::kSpake2p_Max_PBKDF_Iterations))
@@ -334,10 +383,15 @@
return false;
}
- // On the next iteration the PIN Code and Salt will be randomly generated.
- gPinCode = chip::kSetupPINCodeUndefinedValue;
+ // If the file with PIN codes is not provided, the PIN code on next iteration will be randomly generated.
+ gPinCode = GetNextPinCode();
+ // On the next iteration the Salt will be randomly generated.
gSaltDecodedLen = 0;
}
+ if (gPinCodeFile)
+ {
+ fclose(gPinCodeFile);
+ }
return true;
}
diff --git a/src/tools/spake2p/README.md b/src/tools/spake2p/README.md
index b895f12..d6cb3da 100644
--- a/src/tools/spake2p/README.md
+++ b/src/tools/spake2p/README.md
@@ -31,3 +31,13 @@
```
./spake2p gen-verifier --count 100 --iteration-count 15000 --salt-len 32 --out spake2p-provisioning-data.csv
```
+
+Example command that generates 100 sets of spake2p parameters (Specific PIN
+Codes, random Salts and corresponding Verifiers):
+
+```
+./spake2p gen-verifier --count 100 --pin-code-file pincodes.csv --iteration-count 15000 --salt-len 32 --out spake2p-provisioning-data.csv
+```
+
+Notes: Each line of the `pincodes.csv` should be a valid PIN code. You can use
+`spake2p --help` to get the example content of the file.