예제 #1
0
void ComputeBootloaderFingerprint (byte *bootLoaderBuf, unsigned int bootLoaderSize, byte* fingerprint)
{
    // compute Whirlpool+SHA512 fingerprint of bootloader including MBR
    // we skip user configuration fields:
    // TC_BOOT_SECTOR_PIM_VALUE_OFFSET = 400
    // TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET = 402
    //  => TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_SIZE = 4
    // TC_BOOT_SECTOR_USER_MESSAGE_OFFSET     = 406
    //  => TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH = 24
    // TC_BOOT_SECTOR_USER_CONFIG_OFFSET      = 438
    //
    // we have: TC_BOOT_SECTOR_USER_MESSAGE_OFFSET = TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET + TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_SIZE

    WHIRLPOOL_CTX whirlpool;
    sha512_ctx sha2;

    WHIRLPOOL_init (&whirlpool);
    sha512_begin (&sha2);

    WHIRLPOOL_add (bootLoaderBuf, TC_BOOT_SECTOR_PIM_VALUE_OFFSET, &whirlpool);
    sha512_hash (bootLoaderBuf, TC_BOOT_SECTOR_PIM_VALUE_OFFSET, &sha2);

    WHIRLPOOL_add (bootLoaderBuf + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET + TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH, (TC_BOOT_SECTOR_USER_CONFIG_OFFSET - (TC_BOOT_SECTOR_USER_MESSAGE_OFFSET + TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH)), &whirlpool);
    sha512_hash (bootLoaderBuf + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET + TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH, (TC_BOOT_SECTOR_USER_CONFIG_OFFSET - (TC_BOOT_SECTOR_USER_MESSAGE_OFFSET + TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH)), &sha2);

    WHIRLPOOL_add (bootLoaderBuf + TC_BOOT_SECTOR_USER_CONFIG_OFFSET + 1, (TC_MAX_MBR_BOOT_CODE_SIZE - (TC_BOOT_SECTOR_USER_CONFIG_OFFSET + 1)), &whirlpool);
    sha512_hash (bootLoaderBuf + TC_BOOT_SECTOR_USER_CONFIG_OFFSET + 1, (TC_MAX_MBR_BOOT_CODE_SIZE - (TC_BOOT_SECTOR_USER_CONFIG_OFFSET + 1)), &sha2);

    WHIRLPOOL_add (bootLoaderBuf + TC_SECTOR_SIZE_BIOS, (bootLoaderSize - TC_SECTOR_SIZE_BIOS), &whirlpool);
    sha512_hash (bootLoaderBuf + TC_SECTOR_SIZE_BIOS, (bootLoaderSize - TC_SECTOR_SIZE_BIOS), &sha2);

    WHIRLPOOL_finalize (&whirlpool, fingerprint);
    sha512_end (&fingerprint [WHIRLPOOL_DIGESTSIZE], &sha2);
}
예제 #2
0
파일: Pkcs5.c 프로젝트: goofwear/VeraCrypt
void hmac_sha512
(
	  char *k,		/* secret key */
	  int lk,		/* length of the key in bytes */
	  char *d,		/* data and also output buffer of at least 64 bytes */
	  int ld			/* length of data in bytes */	  
)
{
	hmac_sha512_ctx hmac;
	char key[SHA512_DIGESTSIZE];

    /* If the key is longer than the hash algorithm block size,
	   let key = sha512(key), as per HMAC specifications. */
	if (lk > SHA512_BLOCKSIZE)
	{
		sha512_ctx tctx;

		sha512_begin (&tctx);
		sha512_hash ((unsigned char *) k, lk, &tctx);
		sha512_end ((unsigned char *) key, &tctx);

		k = key;
		lk = SHA512_DIGESTSIZE;

		burn (&tctx, sizeof(tctx));		// Prevent leaks
	}

	hmac_sha512_internal (k, lk, d, ld, &hmac);

	/* Prevent leaks */
	burn (&hmac, sizeof(hmac));
	burn (key, sizeof(key));
}
예제 #3
0
    void digestBuf()
    {
        // Mangle the data
        for(size_t j = 0; j < 3; j++)
        {
            // Taint the bytes
            GAssert(DIGEST_BYTES >= 32);
            if(m_pTaint)
                Taint_buffer(m_pBuf, m_pTaint + (m_rand.next() % (DIGEST_BYTES - 32)), 32, j);

            // Shuffle the bytes
            shuffleBytes(m_pBuf, DIGEST_BYTES);

            // Hash each 64-bit chunk with sha-512
            unsigned char* pChunk = m_pBuf;
            for(size_t i = 0; i < (DIGEST_BYTES / 64); i++)
            {
                sha512_ctx ctx;
                sha512_begin(&ctx);
                sha512_hash(pChunk, 64, &ctx);
                sha512_end(pChunk, &ctx);
                pChunk += 64;
            }
        }

        // Add it to the hash
        uint64_t* pA = (uint64_t*)m_pBuf;
        uint64_t* pB = (uint64_t*)m_pHash;
        for(size_t i = 0; i < (DIGEST_BYTES / sizeof(uint64_t)); i++)
        {
            (*pB) += (*pA);
            pB++;
            pA++;
        }
    }
예제 #4
0
파일: Pkcs5.c 프로젝트: goofwear/VeraCrypt
void hmac_sha512_internal
(
	  char *k,		/* secret key */
	  int lk,		/* length of the key in bytes */
	  char *d,		/* data and also output buffer of at least 64 bytes */
	  int ld,			/* length of data in bytes */
	  hmac_sha512_ctx* hmac
)
{
	sha512_ctx* ctx = &(hmac->ctx);
	char* buf = hmac->buf;
	int i;

	/**** Inner Digest ****/

	sha512_begin (ctx);

	/* Pad the key for inner digest */
	for (i = 0; i < lk; ++i)
		buf[i] = (char) (k[i] ^ 0x36);
	for (i = lk; i < SHA512_BLOCKSIZE; ++i)
		buf[i] = 0x36;

	sha512_hash ((unsigned char *) buf, SHA512_BLOCKSIZE, ctx);
	sha512_hash ((unsigned char *) d, ld, ctx);

	sha512_end ((unsigned char *) d, ctx);

	/**** Outer Digest ****/

	sha512_begin (ctx);

	for (i = 0; i < lk; ++i)
		buf[i] = (char) (k[i] ^ 0x5C);
	for (i = lk; i < SHA512_BLOCKSIZE; ++i)
		buf[i] = 0x5C;

	sha512_hash ((unsigned char *) buf, SHA512_BLOCKSIZE, ctx);
	sha512_hash ((unsigned char *) d, SHA512_DIGESTSIZE, ctx);

	sha512_end ((unsigned char *) d, ctx);
}
예제 #5
0
파일: Pkcs5.c 프로젝트: goofwear/VeraCrypt
void derive_key_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, uint32 iterations, char *dk, int dklen)
{
	hmac_sha512_ctx hmac;
	int b, l, r;
	char key[SHA512_DIGESTSIZE];

    /* If the password is longer than the hash algorithm block size,
	   let pwd = sha512(pwd), as per HMAC specifications. */
	if (pwd_len > SHA512_BLOCKSIZE)
	{
		sha512_ctx tctx;

		sha512_begin (&tctx);
		sha512_hash ((unsigned char *) pwd, pwd_len, &tctx);
		sha512_end ((unsigned char *) key, &tctx);

		pwd = key;
		pwd_len = SHA512_DIGESTSIZE;

		burn (&tctx, sizeof(tctx));		// Prevent leaks
	}

	if (dklen % SHA512_DIGESTSIZE)
	{
		l = 1 + dklen / SHA512_DIGESTSIZE;
	}
	else
	{
		l = dklen / SHA512_DIGESTSIZE;
	}

	r = dklen - (l - 1) * SHA512_DIGESTSIZE;

	/* first l - 1 blocks */
	for (b = 1; b < l; b++)
	{
		derive_u_sha512 (pwd, pwd_len, salt, salt_len, iterations, b, &hmac);
		memcpy (dk, hmac.u, SHA512_DIGESTSIZE);
		dk += SHA512_DIGESTSIZE;
	}

	/* last block */
	derive_u_sha512 (pwd, pwd_len, salt, salt_len, iterations, b, &hmac);
	memcpy (dk, hmac.u, r);


	/* Prevent possible leaks. */
	burn (&hmac, sizeof(hmac));
	burn (key, sizeof(key));
}
예제 #6
0
파일: Random.c 프로젝트: makomi/VeraCrypt
/* The random pool mixing function */
BOOL Randmix ()
{
	if (bRandmixEnabled)
	{
		unsigned char hashOutputBuffer [MAX_DIGESTSIZE];
		WHIRLPOOL_CTX	wctx;
		RMD160_CTX		rctx;
		sha512_ctx		sctx;
		sha256_ctx		s256ctx;
		int poolIndex, digestIndex, digestSize;

		switch (HashFunction)
		{
		case RIPEMD160:
			digestSize = RIPEMD160_DIGESTSIZE;
			break;

		case SHA512:
			digestSize = SHA512_DIGESTSIZE;
			break;

		case SHA256:
			digestSize = SHA256_DIGESTSIZE;
			break;

		case WHIRLPOOL:
			digestSize = WHIRLPOOL_DIGESTSIZE;
			break;

		default:
			TC_THROW_FATAL_EXCEPTION;
		}

		if (RNG_POOL_SIZE % digestSize)
			TC_THROW_FATAL_EXCEPTION;

		for (poolIndex = 0; poolIndex < RNG_POOL_SIZE; poolIndex += digestSize)		
		{
			/* Compute the message digest of the entire pool using the selected hash function. */
			switch (HashFunction)
			{
			case RIPEMD160:
				RMD160Init(&rctx);
				RMD160Update(&rctx, pRandPool, RNG_POOL_SIZE);
				RMD160Final(hashOutputBuffer, &rctx);
				break;

			case SHA512:
				sha512_begin (&sctx);
				sha512_hash (pRandPool, RNG_POOL_SIZE, &sctx);
				sha512_end (hashOutputBuffer, &sctx);
				break;

			case SHA256:
				sha256_begin (&s256ctx);
				sha256_hash (pRandPool, RNG_POOL_SIZE, &s256ctx);
				sha256_end (hashOutputBuffer, &s256ctx);
				break;

			case WHIRLPOOL:
				WHIRLPOOL_init (&wctx);
				WHIRLPOOL_add (pRandPool, RNG_POOL_SIZE * 8, &wctx);
				WHIRLPOOL_finalize (&wctx, hashOutputBuffer);
				break;

			default:		
				// Unknown/wrong ID
				TC_THROW_FATAL_EXCEPTION;
			}

			/* XOR the resultant message digest to the pool at the poolIndex position. */
			for (digestIndex = 0; digestIndex < digestSize; digestIndex++)
			{
				pRandPool [poolIndex + digestIndex] ^= hashOutputBuffer [digestIndex];
			}
		}

		/* Prevent leaks */
		burn (hashOutputBuffer, MAX_DIGESTSIZE);	
		switch (HashFunction)
		{
		case RIPEMD160:
			burn (&rctx, sizeof(rctx));		
			break;

		case SHA512:
			burn (&sctx, sizeof(sctx));		
			break;

		case SHA256:
			burn (&s256ctx, sizeof(s256ctx));		
			break;

		case WHIRLPOOL:
			burn (&wctx, sizeof(wctx));		
			break;

		default:		
			// Unknown/wrong ID
			TC_THROW_FATAL_EXCEPTION;
		}
	}
	return TRUE;
}
예제 #7
0
파일: Hash.cpp 프로젝트: AB9IL/VeraCrypt
	void Sha512::GetDigest (const BufferPtr &buffer)
	{
		if_debug (ValidateDigestParameters (buffer));
		sha512_end (buffer, (sha512_ctx *) Context.Ptr());
	}
예제 #8
0
int CHashManager::HashFile(char *pszFile)
{
	FILE *fp = NULL;
	unsigned char pBuf[SIZE_HASH_BUFFER];
	unsigned long uRead = 0;
	unsigned char pTemp[256];
	char szTemp[RH_MAX_BUFFER];
	int i = 0;

	printf("File: <");
	printf(pszFile);
	printf(">");
	printf(CPS_NEWLINE);

	fp = fopen(pszFile, "rb");
	if(fp == NULL) return RH_CANNOT_OPEN_FILE;

	if(m_bAlgorithm[HASHID_CRC16]) crc16_init(&m_crc16);
	if(m_bAlgorithm[HASHID_CRC16CCITT]) crc16ccitt_init(&m_crc16ccitt);
	if(m_bAlgorithm[HASHID_CRC32]) crc32Init(&m_crc32);
	if(m_bAlgorithm[HASHID_FCS_16]) fcs16_init(&m_fcs16);
	if(m_bAlgorithm[HASHID_FCS_32]) fcs32_init(&m_fcs32);
	if(m_bAlgorithm[HASHID_GHASH_32_3] || m_bAlgorithm[HASHID_GHASH_32_5]) m_ghash.Init();
	if(m_bAlgorithm[HASHID_GOST]) gosthash_reset(&m_gost);
	if(m_bAlgorithm[HASHID_HAVAL]) haval_start(&m_haval);
	if(m_bAlgorithm[HASHID_MD2]) m_md2.Init();
	if(m_bAlgorithm[HASHID_MD4]) MD4Init(&m_md4);
	if(m_bAlgorithm[HASHID_MD5]) MD5Init(&m_md5, 0);
	if(m_bAlgorithm[HASHID_SHA1]) sha1_begin(&m_sha1);
	if(m_bAlgorithm[HASHID_SHA2_256]) sha256_begin(&m_sha256);
	if(m_bAlgorithm[HASHID_SHA2_384]) sha384_begin(&m_sha384);
	if(m_bAlgorithm[HASHID_SHA2_512]) sha512_begin(&m_sha512);
	if(m_bAlgorithm[HASHID_SIZE_32]) sizehash32_begin(&m_uSizeHash32);
	if(m_bAlgorithm[HASHID_TIGER]) tiger_init(&m_tiger);

	while(1)
	{
		uRead = fread(pBuf, 1, SIZE_HASH_BUFFER, fp);

		if(uRead != 0)
		{
			if(m_bAlgorithm[HASHID_CRC16])
				crc16_update(&m_crc16, pBuf, uRead);

			if(m_bAlgorithm[HASHID_CRC16CCITT])
				crc16ccitt_update(&m_crc16ccitt, pBuf, uRead);

			if(m_bAlgorithm[HASHID_CRC32])
				crc32Update(&m_crc32, pBuf, uRead);

			if(m_bAlgorithm[HASHID_FCS_16])
				fcs16_update(&m_fcs16, pBuf, uRead);

			if(m_bAlgorithm[HASHID_FCS_32])
				fcs32_update(&m_fcs32, pBuf, uRead);

			if(m_bAlgorithm[HASHID_GHASH_32_3] || m_bAlgorithm[HASHID_GHASH_32_5])
				m_ghash.Update(pBuf, uRead);

			if(m_bAlgorithm[HASHID_GOST])
				gosthash_update(&m_gost, pBuf, uRead);

			if(m_bAlgorithm[HASHID_HAVAL])
				haval_hash(&m_haval, pBuf, uRead);

			if(m_bAlgorithm[HASHID_MD2])
				m_md2.Update(pBuf, uRead);

			if(m_bAlgorithm[HASHID_MD4])
				MD4Update(&m_md4, pBuf, uRead);

			if(m_bAlgorithm[HASHID_MD5])
				MD5Update(&m_md5, pBuf, uRead);

			if(m_bAlgorithm[HASHID_SHA1])
				sha1_hash(pBuf, uRead, &m_sha1);

			if(m_bAlgorithm[HASHID_SHA2_256])
				sha256_hash(pBuf, uRead, &m_sha256);

			if(m_bAlgorithm[HASHID_SHA2_384])
				sha384_hash(pBuf, uRead, &m_sha384);

			if(m_bAlgorithm[HASHID_SHA2_512])
				sha512_hash(pBuf, uRead, &m_sha512);

			if(m_bAlgorithm[HASHID_SIZE_32])
				sizehash32_hash(&m_uSizeHash32, uRead);

			if(m_bAlgorithm[HASHID_TIGER])
				tiger_process(&m_tiger, pBuf, uRead);
		}

		if(uRead != SIZE_HASH_BUFFER) break;
	}

	fclose(fp); fp = NULL;

	// SizeHash-32 is the first hash, because it's the simplest one,
	// the fastest, and most widely used one. ;-)
	if(m_bAlgorithm[HASHID_SIZE_32])
	{
		sizehash32_end(&m_uSizeHash32);
		printf(SZ_SIZEHASH_32);
		printf(SZ_HASHPRE);

		printf("%08X", m_uSizeHash32);

		printf(CPS_NEWLINE);
	}

	if(m_bAlgorithm[HASHID_CRC16])
	{
		crc16_final(&m_crc16);
		printf(SZ_CRC16);
		printf(SZ_HASHPRE);

		printf("%04X", m_crc16);

		printf(CPS_NEWLINE);
	}

	if(m_bAlgorithm[HASHID_CRC16CCITT])
	{
		crc16ccitt_final(&m_crc16ccitt);
		printf(SZ_CRC16CCITT);
		printf(SZ_HASHPRE);

		printf("%04X", m_crc16ccitt);

		printf(CPS_NEWLINE);
	}

	if(m_bAlgorithm[HASHID_CRC32])
	{
		crc32Finish(&m_crc32);
		printf(SZ_CRC32);
		printf(SZ_HASHPRE);

		printf("%08X", m_crc32);

		printf(CPS_NEWLINE);
	}

	if(m_bAlgorithm[HASHID_FCS_16])
	{
		fcs16_final(&m_fcs16);
		printf(SZ_FCS_16);
		printf(SZ_HASHPRE);

		printf("%04X", m_fcs16);

		printf(CPS_NEWLINE);
	}

	if(m_bAlgorithm[HASHID_FCS_32])
	{
		fcs32_final(&m_fcs32);
		printf(SZ_FCS_32);
		printf(SZ_HASHPRE);

		printf("%08X", m_fcs32);

		printf(CPS_NEWLINE);
	}

	if(m_bAlgorithm[HASHID_GHASH_32_3])
	{
		m_ghash.FinalToStr(szTemp, 3);
		printf(SZ_GHASH_32_3);
		printf(SZ_HASHPRE);

		printf(szTemp);

		printf(CPS_NEWLINE);
	}
	if(m_bAlgorithm[HASHID_GHASH_32_5])
	{
		m_ghash.FinalToStr(szTemp, 5);
		printf(SZ_GHASH_32_5);
		printf(SZ_HASHPRE);

		printf(szTemp);

		printf(CPS_NEWLINE);
	}

	if(m_bAlgorithm[HASHID_GOST])
	{
		gosthash_final(&m_gost, pTemp);
		printf(SZ_GOST);
		printf(SZ_HASHPRE);

		for(i = 0; i < 32; i++)
		{
			fmtFixHashOutput(i);
			printf("%02X", pTemp[i]);
		}

		printf(CPS_NEWLINE);
	}

	if(m_bAlgorithm[HASHID_HAVAL])
	{
		haval_end(&m_haval, pTemp);
		printf(SZ_HAVAL);
		printf(SZ_HASHPRE);

		for(i = 0; i < 32; i++)
		{
			fmtFixHashOutput(i);
			printf("%02X", pTemp[i]);
		}

		printf(CPS_NEWLINE);
	}

	if(m_bAlgorithm[HASHID_MD2])
	{
		m_md2.TruncatedFinal(pTemp, 16);
		printf(SZ_MD2);
		printf(SZ_HASHPRE);

		for(i = 0; i < 16; i++)
		{
			fmtFixHashOutput(i);
			printf("%02X", pTemp[i]);
		}

		printf(CPS_NEWLINE);
	}

	if(m_bAlgorithm[HASHID_MD4])
	{
		MD4Final(pTemp, &m_md4);
		printf(SZ_MD4);
		printf(SZ_HASHPRE);

		for(i = 0; i < 16; i++)
		{
			fmtFixHashOutput(i);
			printf("%02X", pTemp[i]);
		}

		printf(CPS_NEWLINE);
	}

	if(m_bAlgorithm[HASHID_MD5])
	{
		MD5Final(&m_md5);
		printf(SZ_MD5);
		printf(SZ_HASHPRE);

		for(i = 0; i < 16; i++)
		{
			fmtFixHashOutput(i);
			printf("%02X", m_md5.digest[i]);
		}

		printf(CPS_NEWLINE);
	}

	if(m_bAlgorithm[HASHID_SHA1])
	{
		sha1_end(pTemp, &m_sha1);
		printf(SZ_SHA1);
		printf(SZ_HASHPRE);

		for(i = 0; i < 20; i++)
		{
			fmtFixHashOutput(i);
			printf("%02X", pTemp[i]);
		}

		printf(CPS_NEWLINE);
	}

	if(m_bAlgorithm[HASHID_SHA2_256])
	{
		sha256_end(pTemp, &m_sha256);
		printf(SZ_SHA2_256);
		printf(SZ_HASHPRE);

		for(i = 0; i < 32; i++)
		{
			fmtFixHashOutput(i);
			printf("%02X", pTemp[i]);
		}

		printf(CPS_NEWLINE);
	}
	if(m_bAlgorithm[HASHID_SHA2_384])
	{
		sha384_end(pTemp, &m_sha384);
		printf(SZ_SHA2_384);
		printf(SZ_HASHPRE);

		for(i = 0; i < 48; i++)
		{
			fmtFixHashOutput(i);
			printf("%02X", pTemp[i]);
		}

		printf(CPS_NEWLINE);
	}
	if(m_bAlgorithm[HASHID_SHA2_512])
	{
		sha512_end(pTemp, &m_sha512);
		printf(SZ_SHA2_512);
		printf(SZ_HASHPRE);

		for(i = 0; i < 64; i++)
		{
			fmtFixHashOutput(i);
			printf("%02X", pTemp[i]);
		}

		printf(CPS_NEWLINE);
	}

	if(m_bAlgorithm[HASHID_TIGER])
	{
		tiger_done(&m_tiger, pTemp);
		printf(SZ_TIGER);
		printf(SZ_HASHPRE);

		for(i = 0; i < 8; i++) { fmtFixHashOutput(i); printf("%02X", pTemp[7-i]); }
		for(i = 8; i < 16; i++) { fmtFixHashOutput(i); printf("%02X", pTemp[23-i]); }
		for(i = 16; i < 24; i++) { fmtFixHashOutput(i); printf("%02X", pTemp[39-i]); }

		printf(CPS_NEWLINE);
	}

	return RH_SUCCESS;
}
예제 #9
0
void hmac_sha512
(
	  char *k,		/* secret key */
	  int lk,		/* length of the key in bytes */
	  char *d,		/* data */
	  int ld,		/* length of data in bytes */
	  char *out,		/* output buffer, at least "t" bytes */
	  int t
)
{
	sha512_ctx ictx, octx;
	char isha[SHA512_DIGESTSIZE], osha[SHA512_DIGESTSIZE];
	char key[SHA512_DIGESTSIZE];
	char buf[SHA512_BLOCKSIZE];
	int i;

    /* If the key is longer than the hash algorithm block size,
	   let key = sha512(key), as per HMAC specifications. */
	if (lk > SHA512_BLOCKSIZE)
	{
		sha512_ctx tctx;

		sha512_begin (&tctx);
		sha512_hash ((unsigned char *) k, lk, &tctx);
		sha512_end ((unsigned char *) key, &tctx);

		k = key;
		lk = SHA512_DIGESTSIZE;

		burn (&tctx, sizeof(tctx));		// Prevent leaks
	}

	/**** Inner Digest ****/

	sha512_begin (&ictx);

	/* Pad the key for inner digest */
	for (i = 0; i < lk; ++i)
		buf[i] = (char) (k[i] ^ 0x36);
	for (i = lk; i < SHA512_BLOCKSIZE; ++i)
		buf[i] = 0x36;

	sha512_hash ((unsigned char *) buf, SHA512_BLOCKSIZE, &ictx);
	sha512_hash ((unsigned char *) d, ld, &ictx);

	sha512_end ((unsigned char *) isha, &ictx);

	/**** Outer Digest ****/

	sha512_begin (&octx);

	for (i = 0; i < lk; ++i)
		buf[i] = (char) (k[i] ^ 0x5C);
	for (i = lk; i < SHA512_BLOCKSIZE; ++i)
		buf[i] = 0x5C;

	sha512_hash ((unsigned char *) buf, SHA512_BLOCKSIZE, &octx);
	sha512_hash ((unsigned char *) isha, SHA512_DIGESTSIZE, &octx);

	sha512_end ((unsigned char *) osha, &octx);

	/* truncate and print the results */
	t = t > SHA512_DIGESTSIZE ? SHA512_DIGESTSIZE : t;
	hmac_truncate (osha, out, t);

	/* Prevent leaks */
	burn (&ictx, sizeof(ictx));
	burn (&octx, sizeof(octx));
	burn (isha, sizeof(isha));
	burn (osha, sizeof(osha));
	burn (buf, sizeof(buf));
	burn (key, sizeof(key));
}