From 1069852c70bfd2726c27be7810327db3092f344f Mon Sep 17 00:00:00 2001 From: Wang Qixiang <43193572+wqx6@users.noreply.github.com> Date: Mon, 21 Nov 2022 07:10:19 +0800 Subject: [PATCH] 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 --- src/tools/spake2p/Cmd_GenVerifier.cpp | 68 ++++++++++++++++++++++++--- src/tools/spake2p/README.md | 10 ++++ 2 files changed, 71 insertions(+), 7 deletions(-) diff --git a/src/tools/spake2p/Cmd_GenVerifier.cpp b/src/tools/spake2p/Cmd_GenVerifier.cpp index 959c4d354de4a7..04bfe995a91ead 100644 --- a/src/tools/spake2p/Cmd_GenVerifier.cpp +++ b/src/tools/spake2p/Cmd_GenVerifier.cpp @@ -30,6 +30,7 @@ #include "spake2p.h" #include +#include #include #include @@ -52,6 +53,7 @@ OptionDef gCmdOptionDefs[] = { { "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 @@ const char * const gCmdOptionHelp = " * 12345678\n" " * 87654321\n" "\n" + " -f, --pin-code-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 \n" "\n" " SPAKE2P PBKDF iteration count. The value should be positive integer in range [1000..100000].\n" @@ -143,6 +159,33 @@ uint8_t gSalt[BASE64_MAX_DECODED_LEN(BASE64_ENCODED_LEN(chip::kSpake2p_Max_PBKDF 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(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 @@ bool HandleOption(const char * progName, OptionSet * optSet, int id, const char 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 @@ bool Cmd_GenVerifier(int argc, char * argv[]) 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 b895f1284bfa40..d6cb3da681fd78 100644 --- a/src/tools/spake2p/README.md +++ b/src/tools/spake2p/README.md @@ -31,3 +31,13 @@ random Salts and corresponding Verifiers): ``` ./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.