Created SRP6A:createVerifyCode()

This generates an SRP verification code from a setupCode and randomly-generated salt.  Function creates the salt internally and returns both the resulting verification code and salt that was used.  These are stored in NVS permanently.

Next Step: create SRP6A:loadVerifycode()
This commit is contained in:
Gregg 2020-09-20 22:00:01 -05:00
parent b0307c9ab0
commit 446679abab
5 changed files with 63 additions and 4 deletions

View File

@ -13,6 +13,34 @@ void HAPClient::init(){
Serial.print("\n"); Serial.print("\n");
nvs_handle srpHandle;
struct { // temporary structure to hold SRP verification code and salt stored in NVS
uint8_t salt[16];
uint8_t verifyCode[384];
} verifyData;
nvs_open("SRP",NVS_READWRITE,&srpHandle); // open SRP data namespace in NVS
if(!nvs_get_blob(srpHandle,"VERIFYDATA",NULL,&len)){ // if found verification code data in NVS
nvs_get_blob(srpHandle,"VERIFYDATA",&verifyData,&len); // retrieve data
// Serial.print("Found SRP Verification Data\n\n");
// hexPrintRow(verifyData.salt,16); Serial.print("\n");
// hexPrintRow(verifyData.verifyCode,384); Serial.print("\n");
} else {
char c[128];
sprintf(c,"Generating SRP verification data for default Setup Code: %.3s-%.2s-%.3s\n\n",homeSpan.defaultSetupCode,homeSpan.defaultSetupCode+3,homeSpan.defaultSetupCode+5);
Serial.print(c);
srp.createVerifyCode(homeSpan.defaultSetupCode,verifyData.verifyCode,verifyData.salt); // create verification code from default Setup Code and random salt
nvs_set_blob(srpHandle,"VERIFYDATA",&verifyData,sizeof(verifyData)); // update data
nvs_commit(srpHandle); // commit to NVS
// hexPrintRow(verifyData.salt,16); Serial.print("\n");
// hexPrintRow(verifyData.verifyCode,384); Serial.print("\n");
}
nvs_close(srpHandle);
nvs_open("HAP",NVS_READWRITE,&nvsHandle); // open HAP data namespace in NVS nvs_open("HAP",NVS_READWRITE,&nvsHandle); // open HAP data namespace in NVS
if(!nvs_get_blob(nvsHandle,"ACCESSORY",NULL,&len)){ // if found long-term Accessory data in NVS if(!nvs_get_blob(nvsHandle,"ACCESSORY",NULL,&len)){ // if found long-term Accessory data in NVS
@ -52,7 +80,7 @@ void HAPClient::init(){
printControllers(); printControllers();
tlv8.create(kTLVType_State,1,"STATE"); // define each the actual TLV records needed for the implementation of HAP; one for each kTLVType needed (HAP Table 5-6) tlv8.create(kTLVType_State,1,"STATE"); // define the actual TLV records needed for the implementation of HAP; one for each kTLVType needed (HAP Table 5-6)
tlv8.create(kTLVType_PublicKey,384,"PUBKEY"); tlv8.create(kTLVType_PublicKey,384,"PUBKEY");
tlv8.create(kTLVType_Method,1,"METHOD"); tlv8.create(kTLVType_Method,1,"METHOD");
tlv8.create(kTLVType_Salt,16,"SALT"); tlv8.create(kTLVType_Salt,16,"SALT");
@ -384,8 +412,8 @@ int HAPClient::postPairSetupURL(){
tlv8.clear(); tlv8.clear();
tlv8.val(kTLVType_State,pairState_M2); // set State=<M2> tlv8.val(kTLVType_State,pairState_M2); // set State=<M2>
srp.createPublicKey(); // create accessory public key from random Pair-Setup code (displayed to user) srp.createPublicKey(); // create accessory public key from random Pair-Setup code (displayed to user)
srp.loadTLV(kTLVType_PublicKey,&srp.B); // load server public key, B (MUST MAKE THIS A LIVE CALCULATION TO GENERATE RANDOM SET-UP CODE) srp.loadTLV(kTLVType_PublicKey,&srp.B); // load server public key, B
srp.loadTLV(kTLVType_Salt,&srp.s); // load salt, s (MUST MAKE THIS RANDOM AS WELL) srp.loadTLV(kTLVType_Salt,&srp.s); // load salt, s
tlvRespond(); // send response to client tlvRespond(); // send response to client
pairStatus=pairState_M3; // set next expected pair-state request from client pairStatus=pairState_M3; // set next expected pair-state request from client

View File

@ -53,7 +53,7 @@ void Span::begin(Category catID, char *displayName, char *hostNameBase, char *mo
if(!digitalRead(resetPin)){ // factory reset pin is low upon start-up if(!digitalRead(resetPin)){ // factory reset pin is low upon start-up
nvs_flash_erase(); // erase NVS storage nvs_flash_erase(); // erase NVS storage
Serial.print("** FACTORY RESET PIN LOW! ALL STORED DATA ERASED **\n"); Serial.print("** FACTORY RESET PIN LOW! ALL STORED DATA ERASED **\n\n");
statusLED.start(100); statusLED.start(100);
delay(5000); delay(5000);
Serial.print("Re-starting...\n\n"); Serial.print("Re-starting...\n\n");

View File

@ -48,6 +48,7 @@ struct Span{
char *modelName; // model name of this device - broadcast as Bonjour field "md" char *modelName; // model name of this device - broadcast as Bonjour field "md"
char category[3]=""; // category ID of primary accessory - broadcast as Bonjour field "ci" (HAP Section 13) char category[3]=""; // category ID of primary accessory - broadcast as Bonjour field "ci" (HAP Section 13)
unsigned long snapTime; // current time (in millis) snapped before entering Service loops() or updates() unsigned long snapTime; // current time (in millis) snapped before entering Service loops() or updates()
char *defaultSetupCode="46637726"; // default Setup Code upon factory reset; user will change to desired code when configuring network
int resetPin=21; // drive this pin low to "factory" reset NVS data on start-up int resetPin=21; // drive this pin low to "factory" reset NVS data on start-up
int resetPressed=0; // tracks pressing of reset button int resetPressed=0; // tracks pressing of reset button

View File

@ -62,6 +62,33 @@ SRP6A::SRP6A(){
////////////////////////////////////// //////////////////////////////////////
void SRP6A::createVerifyCode(const char *setupCode, uint8_t *verifyCode, uint8_t *salt){
uint8_t tBuf[80]; // temporary buffer for staging
uint8_t tHash[64]; // temporary buffer for storing SHA-512 results
char icp[22]; // storage for I:P
randombytes_buf(salt,16); // generate 16 random bytes using libsodium (which uses the ESP32 hardware-based random number generator)
mbedtls_mpi_read_binary(&s,salt,16);
sprintf(icp,"Pair-Setup:%.3s-%.2s-%.3s",setupCode,setupCode+3,setupCode+5);
// compute x = SHA512( s | SHA512( I | ":" | P ) )
mbedtls_mpi_write_binary(&s,tBuf,16); // write s into first 16 bytes of staging buffer
mbedtls_sha512_ret((uint8_t *)icp,strlen(icp),tBuf+16,0); // create hash of username:password and write into last 64 bytes of staging buffer
mbedtls_sha512_ret(tBuf,80,tHash,0); // create second hash of salted, hashed username:password
mbedtls_mpi_read_binary(&x,tHash,64); // load hash result into mpi structure x
// compute v = g^x % N
mbedtls_mpi_exp_mod(&v,&g,&x,&N,&_rr); // create verifier, v (_rr is an internal "helper" structure that mbedtls uses to speed up subsequent exponential calculations)
mbedtls_mpi_write_binary(&v,verifyCode,384); // write v into verifyCode
}
//////////////////////////////////////
void SRP6A::createPublicKey(){ void SRP6A::createPublicKey(){
uint8_t tBuf[80]; // temporary buffer for staging uint8_t tBuf[80]; // temporary buffer for staging

View File

@ -40,6 +40,9 @@ struct SRP6A {
uint8_t sharedSecret[64]; // permanent storage for binary version of SHARED SECRET KEY for ease of use upstream uint8_t sharedSecret[64]; // permanent storage for binary version of SHARED SECRET KEY for ease of use upstream
SRP6A(); // initializes N, G, and computes k SRP6A(); // initializes N, G, and computes k
void createVerifyCode(const char *setupCode, uint8_t *verifyCode, uint8_t *salt);
void getSalt(); // generates and stores random 16-byte salt, s void getSalt(); // generates and stores random 16-byte salt, s
void getPrivateKey(); // generates and stores random 32-byte private key, b void getPrivateKey(); // generates and stores random 32-byte private key, b
void getSetupCode(char *c); // generates and displays random 8-digit Pair-Setup code, P, in format XXX-XX-XXX void getSetupCode(char *c); // generates and displays random 8-digit Pair-Setup code, P, in format XXX-XX-XXX