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);
}