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::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
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());
}
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
}
int WPSRegistrar::ProcessDone()
{
	uint32 err;

	err = g_regProtocol.ProcessMessageDone(&m_regInfo, m_msgBuffer );
    if(WSC_SUCCESS != err)
    {
		return err_process_Done;
    }
	printf("\n*****  Successfully processed Message Done\n");
	if (m_regInfo.p_enrolleeInfo) {
		WPSDeviceWasAuthenticated(* ((GUID*) & (m_regInfo.p_enrolleeInfo->uuid)));
	}

	//****** Derivation of UPnP Protected Setup AuthKey and KeyWrapKey ******
    //1. declare and initialize the appropriate buffer objects
	BufferObj kdkBuf(m_regInfo.emsk.GetBuf(), SIZE_256_BITS);
    BufferObj pString((uint8 *)UPNP_PERSONALIZATION_STRING, 
                        strlen(UPNP_PERSONALIZATION_STRING));
    BufferObj keys;

    //2. call the key derivation function
    g_regProtocol.DeriveKey(kdkBuf, pString, 256 + 128, keys);

    //3. split the key into the component keys and store them
    keys.Rewind(keys.Length());
    m_regInfo.UPnPPSauthKey.Reset();
	m_regInfo.UPnPPSkeyWrapKey.Reset();

	m_regInfo.UPnPPSauthKey.Append(SIZE_256_BITS, keys.Pos());
    keys.Advance(SIZE_256_BITS);

    m_regInfo.UPnPPSkeyWrapKey.Append(SIZE_128_BITS, keys.Pos());
	// **** End of key derivation code

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