bool CRegProtocol::ValidateMac(BufferObj &data, uint8 *hmac, BufferObj &key) { uint8 dataMac[BUF_SIZE_256_BITS]; //First calculate the hmac of the data if(HMAC(EVP_sha256(), key.GetBuf(), SIZE_256_BITS, data.GetBuf(), data.Length(), dataMac, NULL) == NULL) { TUTRACE((TUTRACE_ERR, "RPROTO: HMAC failed\n")); if (TUTRACELEVEL & TUVERBOSE && g_verbose) { // for debugging purposes printf("Computed HMAC (note: only first 64 bits will be compared)\n"); for (int i = 0; i < BUF_SIZE_256_BITS; i++) { printf("%2x ",dataMac[i]); } printf("\nHMAC from Authenticator(should match first 64 bits of computed HMAC)\n"); for (int i = 0; i < 8; i++) { printf("%2x ",hmac[i]); } printf("\nKey is:\n"); for (int i = 0; i < 8; i++) { printf("%2x ",(key.GetBuf())[i]); } printf("\n"); } throw RPROT_ERR_CRYPTO; } else { if (TUTRACELEVEL & TUVERBOSE && g_verbose) { // for debugging purposes printf("Computed HMAC (note: only first 64 bits will be compared)\n"); for (int i = 0; i < BUF_SIZE_256_BITS; i++) { printf("%2x ",dataMac[i]); } printf("\nHMAC from Authenticator(should match first 64 bits of computed HMAC)\n"); for (int i = 0; i < 8; i++) { printf("%2x ",hmac[i]); } printf("\nKey is:\n"); for (int i = 0; i < BUF_SIZE_256_BITS; i++) { printf("%2x ",(key.GetBuf())[i]); } printf("\n"); } } //next, compare it against the received hmac TUTRACE((TUTRACE_INFO, "RPROTO: Verifying the first 64 bits of the generated HMAC\n")); if(memcmp(dataMac, hmac, SIZE_64_BITS) != 0) { printf("RPROTO: HMAC results don't match\n"); return false; } TUTRACE((TUTRACE_VERBOSE, "RPROTO: HMAC results match\n")); return true; }
void CTlvEsM8Sta::write(BufferObj &theBuf, BufferObj &authKey, bool isWirelessWPS) { LPLISTITR itr; CTlvCredential *pCredential; //there should be at least one credential TLV if(isWirelessWPS && 0 == ListGetCount(credential)) throw RPROT_ERR_REQD_TLV_MISSING; try { if (isWirelessWPS) { // skip including Credential if not in wireless WPS mode if(!(itr = ListItrCreate(credential))) throw WSC_ERR_OUTOFMEMORY; while((pCredential = (CTlvCredential *)ListItrGetNext(itr))) { pCredential->write(theBuf); } } //write the optional new password and device password ID if(new_pwd.Length()) { new_pwd.Write(theBuf); pwdId.Write(theBuf); } //calculate the hmac and append the TLV to the buffer uint8 hmac[SIZE_256_BITS]; if(HMAC(EVP_sha256(), authKey.GetBuf(), SIZE_256_BITS, theBuf.GetBuf(), theBuf.Length(), hmac, NULL) == NULL) { TUTRACE((TUTRACE_ERR, "RPROTO: Error generating HMAC\n")); throw RPROT_ERR_CRYPTO; } CTlvAuthenticator( WSC_ID_KEY_WRAP_AUTH, theBuf, hmac, SIZE_64_BITS); if (isWirelessWPS) { // itr is only valid if in wireless WPS mode ListItrDelete(itr); } } catch(...) { if(itr) ListItrDelete(itr); } }
void CRegProtocol::DeriveKey(BufferObj &KDK, BufferObj &prsnlString, uint32 keyBits, BufferObj &key) { uint32 i = 0, iterations = 0; BufferObj input, output; uint8 hmac[SIZE_256_BITS]; uint32 hmacLen = 0; uint8 *inPtr; uint32 temp; TUTRACE((TUTRACE_INFO, "RPROTO: Deriving a key of %d bits\n", keyBits)); iterations = ((keyBits/8) + PRF_DIGEST_SIZE - 1)/PRF_DIGEST_SIZE; //Prepare the input buffer. During the iterations, we need only replace the //value of i at the start of the buffer. temp = WscHtonl(i); input.Append(SIZE_4_BYTES, (uint8 *)&temp); input.Append(prsnlString.Length(), prsnlString.GetBuf()); temp = WscHtonl(keyBits); input.Append(SIZE_4_BYTES, (uint8 *)&temp); inPtr = input.GetBuf(); for(i = 0; i < iterations; i++) { //Set the current value of i at the start of the input buffer *(uint32 *)inPtr = WscHtonl(i+1); //i should start at 1 if(HMAC(EVP_sha256(), KDK.GetBuf(), SIZE_256_BITS, input.GetBuf(), input.Length(), hmac, &hmacLen) == NULL) { TUTRACE((TUTRACE_ERR, "RPROTO: HMAC failed\n")); throw RPROT_ERR_CRYPTO; } output.Append(hmacLen, hmac); } //Sanity check if(keyBits/8 > output.Length()) { TUTRACE((TUTRACE_ERR, "RPROTO: Key derivation generated less bits " "than asked\n")); throw RPROT_ERR_CRYPTO; } //We now have at least the number of key bits requested. //Return only the number of bits asked for. Discard the excess. key.Append(keyBits/8, output.GetBuf()); }
//Encrypted settings for M7 //ES when M7 is from an enrollee void CTlvEsM7Enr::parse(BufferObj &theBuf, BufferObj &authKey, bool allocate) { nonce = CTlvNonce(WSC_ID_E_SNONCE2, theBuf, SIZE_128_BITS); if(WSC_ID_IDENTITY_PROOF == theBuf.NextType()) idProof = CTlvIdentityProof(WSC_ID_IDENTITY_PROOF, theBuf, 0, allocate); // Skip attributes until the KeyWrapAuthenticator while(WSC_ID_KEY_WRAP_AUTH != theBuf.NextType()) { //advance past the TLV uint8 *Pos = theBuf.Advance( sizeof(S_WSC_TLV_HEADER) + WscNtohs(*(uint16 *)(theBuf.Pos()+sizeof(uint16))) ); //If Advance returned NULL, it means there's no more data in the //buffer. This is an error. if(Pos == NULL) throw RPROT_ERR_REQD_TLV_MISSING; } uint8 * startOfAuthenticator = theBuf.Pos(); keyWrapAuth = CTlvAuthenticator(WSC_ID_KEY_WRAP_AUTH, theBuf, SIZE_64_BITS); //validate the mac uint8 dataMac[BUF_SIZE_256_BITS]; //calculate the hmac of the data (data only, not the last auth TLV) if(HMAC(EVP_sha256(), authKey.GetBuf(), SIZE_256_BITS, theBuf.GetBuf(), startOfAuthenticator - theBuf.GetBuf(), dataMac, NULL) == NULL) { TUTRACE((TUTRACE_ERR, "RPROTO: HMAC failed\n")); throw RPROT_ERR_CRYPTO; } //compare it against the received hmac if(memcmp(dataMac, keyWrapAuth.Value(), SIZE_64_BITS) != 0) { TUTRACE((TUTRACE_ERR, "RPROTO: HMAC results don't match\n")); throw RPROT_ERR_INVALID_VALUE; } }
void CTlvEsNonce::write(BufferObj &theBuf, BufferObj &authKey) { nonce.Write(theBuf); //calculate the hmac and append the TLV to the buffer uint8 hmac[SIZE_256_BITS]; if(HMAC(EVP_sha256(), authKey.GetBuf(), SIZE_256_BITS, theBuf.GetBuf(), theBuf.Length(), hmac, NULL) == NULL) { TUTRACE((TUTRACE_ERR, "RPROTO: Error generating HMAC\n")); throw RPROT_ERR_CRYPTO; } CTlvAuthenticator( WSC_ID_KEY_WRAP_AUTH, theBuf, hmac, SIZE_64_BITS); //Only the first 64 bits are sent }
void CRegProtocol::GenerateSHA256Hash(BufferObj &inBuf, BufferObj &outBuf) { uint8 Hash[SIZE_256_BITS]; if(SHA256(inBuf.GetBuf(), inBuf.Length(), Hash) == NULL) { TUTRACE((TUTRACE_ERR, "RPROTO: SHA256 calculation failed\n")); throw RPROT_ERR_CRYPTO; } outBuf.Append(SIZE_256_BITS, Hash); }//GenerateHash
bool CRegProtocol::ValidateKeyWrapAuth(BufferObj &data, uint8 *hmac, BufferObj &key) { //Same as ValidateMac, except only the first 64 bits are validated uint8 dataMac[BUF_SIZE_256_BITS]; //First calculate the hmac of the data if(HMAC(EVP_sha256(), key.GetBuf(), SIZE_256_BITS, data.GetBuf(), data.Length(), dataMac, NULL) == NULL) { TUTRACE((TUTRACE_ERR, "RPROTO: HMAC failed\n")); throw RPROT_ERR_CRYPTO; } //next, compare it against the received hmac if(memcmp(dataMac, hmac, SIZE_64_BITS) != 0) { TUTRACE((TUTRACE_ERR, "RPROTO: HMAC results don't match\n")); return false; } return true; }
void CTlvEsM8Sta::parse(BufferObj &theBuf, BufferObj &authKey, bool allocate, bool isWirelessWPS) { //There should be at least 1 credential TLV CTlvCredential *pCredential; if (isWirelessWPS) { // Credential(s) are processed only when doing wireless WPS pCredential = new CTlvCredential(); pCredential->parse(theBuf, allocate); ListAddItem(credential, pCredential); //now parse any additional credential TLVs while(WSC_ID_CREDENTIAL == theBuf.NextType()) { pCredential = new CTlvCredential(); pCredential->parse(theBuf, allocate); ListAddItem(credential, pCredential); } } // Note that all Credentials are ignored if not doing wireless WPS. Also, if a Credential // is present in this case, then the new password attribute will be ignored as well, because // the Credential attribute will be next to be parsed in the message, which will cause the code // to drop down to just skipping all attributes until the key wrap authenticator. if(WSC_ID_NEW_PWD == theBuf.NextType()) { //If the New Password TLV is included, the Device password ID is required new_pwd = CTlvNewPwd(WSC_ID_NEW_PWD, theBuf, SIZE_64_BYTES, allocate); pwdId = CTlvDevicePwdId(WSC_ID_DEVICE_PWD_ID, theBuf); } // Skip attributes until the KeyWrapAuthenticator while(WSC_ID_KEY_WRAP_AUTH != theBuf.NextType()) { //advance past the TLV uint8 *Pos = theBuf.Advance( sizeof(S_WSC_TLV_HEADER) + WscNtohs(*(uint16 *)(theBuf.Pos()+sizeof(uint16))) ); //If Advance returned NULL, it means there's no more data in the //buffer. This is an error. if(Pos == NULL) throw RPROT_ERR_REQD_TLV_MISSING; } uint8 * startOfAuthenticator = theBuf.Pos(); keyWrapAuth = CTlvAuthenticator(WSC_ID_KEY_WRAP_AUTH, theBuf, SIZE_64_BITS); //validate the mac uint8 dataMac[BUF_SIZE_256_BITS]; //calculate the hmac of the data (data only, not the last auth TLV) if(HMAC(EVP_sha256(), authKey.GetBuf(), SIZE_256_BITS, theBuf.GetBuf(), startOfAuthenticator - theBuf.GetBuf(), dataMac, NULL) == NULL) { TUTRACE((TUTRACE_ERR, "RPROTO: HMAC failed\n")); throw RPROT_ERR_CRYPTO; } //compare it against the received hmac if(memcmp(dataMac, keyWrapAuth.Value(), SIZE_64_BITS) != 0) { TUTRACE((TUTRACE_ERR, "RPROTO: HMAC results don't match\n")); throw RPROT_ERR_INVALID_VALUE; } }
void CTlvEsM8Ap::write(BufferObj &theBuf, BufferObj &authKey) { LPLISTITR indexItr, keyItr; CTlvNwKeyIndex *keyIndex; CTlvNwKey *key; try { if(!(indexItr = ListItrCreate(nwKeyIndex))) throw WSC_ERR_OUTOFMEMORY; if(!(keyItr = ListItrCreate(nwKey))) throw WSC_ERR_OUTOFMEMORY; //nwIndex is an optional field if(nwIndex.Length()) nwIndex.Write(theBuf); ssid.Write(theBuf); authType.Write(theBuf); encrType.Write(theBuf); //write the network index and network key to the buffer if(ListGetCount(nwKeyIndex) == 0) { //Condition1. There is no key index, so there can only be 1 nw key if(!(key = (CTlvNwKey *) ListItrGetNext(keyItr))) throw WSC_ERR_OUTOFMEMORY; key->Write(theBuf); } else { //Condition2. There are multiple network keys. while((keyIndex= (CTlvNwKeyIndex *) ListItrGetNext(indexItr))) { if(!(key = (CTlvNwKey *) ListItrGetNext(keyItr))) throw WSC_ERR_OUTOFMEMORY; keyIndex->Write(theBuf); key->Write(theBuf); }//while }//else //write the mac address macAddr.Write(theBuf); //write the optional new password and device password ID if(new_pwd.Length()) { new_pwd.Write(theBuf); pwdId.Write(theBuf); } //calculate the hmac and append the TLV to the buffer uint8 hmac[SIZE_256_BITS]; if(HMAC(EVP_sha256(), authKey.GetBuf(), SIZE_256_BITS, theBuf.GetBuf(), theBuf.Length(), hmac, NULL) == NULL) { TUTRACE((TUTRACE_ERR, "RPROTO: Error generating HMAC\n")); throw RPROT_ERR_CRYPTO; } CTlvAuthenticator( WSC_ID_KEY_WRAP_AUTH, theBuf, hmac, SIZE_64_BITS); ListItrDelete(indexItr); ListItrDelete(keyItr); } catch(...) { if(indexItr) ListItrDelete(indexItr); if(keyItr) ListItrDelete(keyItr); throw; } }
void CTlvEsM8Ap::parse(BufferObj &theBuf, BufferObj &authKey, bool allocate) { CTlvNwKeyIndex *keyIndex; CTlvNwKey *key; //NW Index is optional if(WSC_ID_NW_INDEX == theBuf.NextType()) nwIndex = CTlvNwIndex(WSC_ID_NW_INDEX, theBuf); ssid = CTlvSsid(WSC_ID_SSID, theBuf, SIZE_32_BYTES, allocate); authType = CTlvAuthType(WSC_ID_AUTH_TYPE, theBuf); encrType = CTlvEncrType(WSC_ID_ENCR_TYPE, theBuf); //The next field is network key index. There are two possibilities: //1. The TLV is omitted, in which case, there is only 1 network key //2. The TLV is present, in which case, there may be 1 or more network keys //condition 1. If the next field is a network Key, the index TLV was omitted if(WSC_ID_NW_KEY == theBuf.NextType()) { key = new CTlvNwKey(WSC_ID_NW_KEY, theBuf, SIZE_64_BYTES, allocate); if(!key) throw WSC_ERR_OUTOFMEMORY; ListAddItem(nwKey, key); } else { //condition 2. any other possibities are illegal & will be caught later while(WSC_ID_NW_KEY_INDEX == theBuf.NextType()) { keyIndex = new CTlvNwKeyIndex(WSC_ID_NW_KEY_INDEX, theBuf); if(!keyIndex) throw WSC_ERR_OUTOFMEMORY; ListAddItem(nwKeyIndex, keyIndex); key = new CTlvNwKey(WSC_ID_NW_KEY, theBuf, SIZE_64_BYTES, allocate); if(!key) throw WSC_ERR_OUTOFMEMORY; ListAddItem(nwKey, key); }//while }//else macAddr = CTlvMacAddr(WSC_ID_MAC_ADDR, theBuf, SIZE_6_BYTES, allocate); if(WSC_ID_NEW_PWD == theBuf.NextType()) { //If the New Password TLV is included, the Device password ID is required new_pwd = CTlvNewPwd(WSC_ID_NEW_PWD, theBuf, SIZE_64_BYTES, allocate); pwdId = CTlvDevicePwdId(WSC_ID_DEVICE_PWD_ID, theBuf); } //skip Permitted Config Methods field. if(WSC_ID_PERM_CFG_METHODS == theBuf.NextType()) { //advance past the TLV theBuf.Advance( sizeof(S_WSC_TLV_HEADER) + WscNtohs(*(uint16 *)(theBuf.Pos()+sizeof(uint16))) ); } // Skip attributes until the KeyWrapAuthenticator while(WSC_ID_KEY_WRAP_AUTH != theBuf.NextType()) { //advance past the TLV uint8 *Pos = theBuf.Advance( sizeof(S_WSC_TLV_HEADER) + WscNtohs(*(uint16 *)(theBuf.Pos()+sizeof(uint16))) ); //If Advance returned NULL, it means there's no more data in the //buffer. This is an error. if(Pos == NULL) throw RPROT_ERR_REQD_TLV_MISSING; } uint8 * startOfAuthenticator = theBuf.Pos(); keyWrapAuth = CTlvAuthenticator(WSC_ID_KEY_WRAP_AUTH, theBuf, SIZE_64_BITS); //validate the mac uint8 dataMac[BUF_SIZE_256_BITS]; //calculate the hmac of the data (data only, not the last auth TLV) if(HMAC(EVP_sha256(), authKey.GetBuf(), SIZE_256_BITS, theBuf.GetBuf(), startOfAuthenticator - theBuf.GetBuf(), dataMac, NULL) == NULL) { TUTRACE((TUTRACE_ERR, "RPROTO: HMAC failed\n")); throw RPROT_ERR_CRYPTO; } //compare it against the received hmac if(memcmp(dataMac, keyWrapAuth.Value(), SIZE_64_BITS) != 0) { TUTRACE((TUTRACE_ERR, "RPROTO: HMAC results don't match\n")); throw RPROT_ERR_INVALID_VALUE; } }
void CRegProtocol::DecryptData(BufferObj &cipherText, BufferObj &iv, BufferObj &encrKey, BufferObj &authKey, BufferObj &plainText) { EVP_CIPHER_CTX ctx; if(0 == EVP_DecryptInit(&ctx, EVP_aes_128_cbc(), encrKey.GetBuf(), iv.GetBuf())) { TUTRACE((TUTRACE_ERR, "RPROTO: DecryptInit failed\n")); throw RPROT_ERR_CRYPTO; } BufferObj buf; int bufLen = 1024; uint8 outBuf[1024]; int outLen, currentLength; //block size = 1024 bytes - 128 bits, //leave 128 bits at the end to accommodate any possible padding //and avoid a buffer overflow int blockSize = bufLen - SIZE_128_BITS; int length = cipherText.Length(); uint8 *bufPtr = cipherText.GetBuf(); while(length) { if(length > blockSize) currentLength = blockSize; else currentLength = length; if(0 == EVP_DecryptUpdate(&ctx, outBuf, &outLen, bufPtr, currentLength)) { TUTRACE((TUTRACE_ERR, "RPROTO: DecryptUpdate failed\n")); throw RPROT_ERR_CRYPTO; } buf.Append(outLen, outBuf); bufPtr += currentLength; length -= currentLength; } if(0 == EVP_DecryptFinal(&ctx, outBuf, &outLen)) { TUTRACE((TUTRACE_ERR, "RPROTO: DecryptFinal failed\n")); throw RPROT_ERR_CRYPTO; } buf.Append(outLen, outBuf); //Validate the mac at the end of the decrypted buffer //uint8 *mac = buf.GetBuf()+(buf.Length()-SIZE_256_BITS);//get the last 256 bits //if(0 == ValidateMac(BufferObj(buf.GetBuf(), buf.Length()-SIZE_256_BITS), mac, authKey)) //{ // TUTRACE((TUTRACE_ERR, "RPROTO: Mac validation failed\n")); // throw RPROT_ERR_INVALID_VALUE; //} //plainText.Append(buf.Length()-SIZE_256_BITS, buf.GetBuf()); plainText.Append(buf.Length(), buf.GetBuf()); plainText.Rewind(plainText.Length()); }
void CRegProtocol::EncryptData(BufferObj &plainText, BufferObj &encrKey, BufferObj &authKey, BufferObj &cipherText, BufferObj &iv) { BufferObj buf; uint8 ivBuf[SIZE_128_BITS]; if(0 == plainText.Length()) throw WSC_ERR_INVALID_PARAMETERS; //Generate a random iv RAND_bytes(ivBuf, SIZE_128_BITS); iv.Reset(); iv.Append(SIZE_128_BITS, ivBuf); //Now encrypt the plaintext and mac using the encryption key and IV. buf.Append(plainText.Length(), plainText.GetBuf()); EVP_CIPHER_CTX ctx; if(0 == EVP_EncryptInit(&ctx, EVP_aes_128_cbc(), encrKey.GetBuf(), ivBuf)) { TUTRACE((TUTRACE_ERR, "RPROTO: EncryptInit failed\n")); throw RPROT_ERR_CRYPTO; } int bufLen = 1024; uint8 outBuf[1024]; int outLen, currentLength; //block size = 1024 bytes - 128 bits, //leave 128 bits at the end to accommodate any possible padding //and avoid a buffer overflow int blockSize = bufLen - SIZE_128_BITS; int length = buf.Length(); uint8 *bufPtr = buf.GetBuf(); while(length) { if(length > blockSize) currentLength = blockSize; else currentLength = length; if(0 == EVP_EncryptUpdate(&ctx, outBuf, &outLen, bufPtr, currentLength)) { TUTRACE((TUTRACE_ERR, "RPROTO: EncryptUpdate failed\n")); throw RPROT_ERR_CRYPTO; } cipherText.Append(outLen, outBuf); bufPtr += currentLength; length -= currentLength; } if(0 == EVP_EncryptFinal(&ctx, outBuf, &outLen)) { TUTRACE((TUTRACE_ERR, "RPROTO: EncryptFinal failed\n")); throw RPROT_ERR_CRYPTO; } cipherText.Append(outLen, outBuf); }