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 
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);
}
uint32 CRegProtocol::GenerateDHKeyPair(DH **DHKeyPair, BufferObj &pubKey)
{
    uint8 temp[SIZE_PUB_KEY];
    try
    {
        //1. Initialize the DH structure
        *DHKeyPair = DH_new();
        if(*DHKeyPair == NULL)
        {
            TUTRACE((TUTRACE_ERR, "RPROTO: DH_new failed\n"));
            throw RPROT_ERR_CRYPTO;
        }

        (*DHKeyPair)->p = BN_new();
        (*DHKeyPair)->g = BN_new();
       
        //2. load the value of P
        if(BN_bin2bn(DH_P_VALUE, 
                     BUF_SIZE_1536_BITS, 
                     (*DHKeyPair)->p)==NULL)
        {
            TUTRACE((TUTRACE_ERR, "RPROTO: BN_bin2bn P: %s", 
                    ERR_error_string(ERR_get_error(), NULL)));
            throw RPROT_ERR_CRYPTO;
        }

        //3. load the value of G
        uint32 g = WscHtonl(DH_G_VALUE);
        if(BN_bin2bn((uint8 *)&g, 
                     4, 
                     (*DHKeyPair)->g)==NULL)
        {
            TUTRACE((TUTRACE_ERR, "RPROTO: BN_bin2bn G: %s", 
                    ERR_error_string(ERR_get_error(), NULL)));
            throw RPROT_ERR_CRYPTO;
        }

        //4. generate the DH key
        if(DH_generate_key(*DHKeyPair) == 0)
        {
            TUTRACE((TUTRACE_ERR, "RPROTO: DH_generate_key: %s", 
                    ERR_error_string(ERR_get_error(), NULL)));
            throw RPROT_ERR_CRYPTO;
        }

        //5. extract the DH public key
        int len = BN_bn2bin((*DHKeyPair)->pub_key, temp);
        if(0 == len)
        {
            TUTRACE((TUTRACE_ERR, "RPROTO: BN_bn2bin: %s", 
                    ERR_error_string(ERR_get_error(), NULL)));
            throw RPROT_ERR_CRYPTO;
        }
        pubKey.Append(SIZE_PUB_KEY, temp);
        return WSC_SUCCESS;
    }
    catch(uint32 err)
    {
        return err;
    }
    catch(...)
    {
        return WSC_ERR_SYSTEM;
    }
}//GenerateDHKeyPair