Mercurial > projects > dcrypt
view dcrypt/crypto/macs/HMAC.d @ 14:5ce3012f1def
Removed some redundancy in code. Added NotSupportedError, a base PRNG class and a class which creates a PRNG from a hash function. Changed the MAC class' finalization methods to digest and hexDigest instead of finish and hexFinish respectively. Also added a base Checksum class, crc32 and adler32 in dcrypt.misc as per request.
author | Thomas Dixon <reikon@reikon.us> |
---|---|
date | Tue, 18 Nov 2008 18:03:40 -0500 |
parents | 5cb17e09d685 |
children | 0de48552be35 |
line wrap: on
line source
/** * This file is part of the dcrypt project. * * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. * License: MIT * Authors: Thomas Dixon */ module dcrypt.crypto.macs.HMAC; import dcrypt.crypto.MAC; import dcrypt.crypto.Hash; import dcrypt.crypto.params.SymmetricKey; import dcrypt.crypto.errors.NotInitializedError; version (UnitTest) { import dcrypt.crypto.hashes.SHA1; } /** * Implementation of Keyed-Hash Message Authentication Code (HMAC) * * Conforms: RFC 2104 * References: http://www.faqs.org/rfcs/rfc2104.html */ class HMAC : MAC { private { ubyte[] ipad, opad, key; Hash inner, outer; bool initialized; } this (Hash hash, void[] key=null) { hash.reset(); inner = hash; outer = hash.copy(); ipad = new ubyte[blockSize]; opad = new ubyte[blockSize]; reset(); if (key) init(new SymmetricKey(key)); // I'm lazy. } void init(CipherParameters params) { SymmetricKey keyParams = cast(SymmetricKey)params; if (!keyParams) throw new InvalidParameterError( name()~": Invalid parameter passed to init"); if (keyParams.key.length > blockSize) { inner.update(keyParams.key); key = inner.digest(); } else key = keyParams.key; foreach (uint i, ubyte j; key) { ipad[i] ^= j; opad[i] ^= j; } inner.update(ipad); outer.update(opad); initialized = true; } void update(void[] input_) { if (!initialized) throw new NotInitializedError( name()~": MAC not initialized."); inner.update(input_); } char[] name() { return inner.name~"/HMAC"; } void reset() { ipad[] = 0x36; opad[] = 0x5c; inner.reset(); outer.reset(); } uint blockSize() { return inner.blockSize; } uint macSize() { return inner.digestSize; } ubyte[] digest() { outer.update(inner.digest()); ubyte[] r = outer.digest(); reset(); return r; } char[] hexDigest() { return Util.ubytesToHex(finish()); } HMAC copy() { // Ghetto... oh so ghetto :\ HMAC h = new HMAC(inner.copy()); h.inner = inner.copy(); h.outer = outer.copy(); h.initialized = true; return h; } version (UnitTest) { unittest { static char[][] test_keys = [ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "4a656665", // Jefe? "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"~ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"~ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"~ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ]; static char[][] test_inputs = [ "4869205468657265", "7768617420646f2079612077616e7420666f72206e6f7468696e673f", "dd", "54657374205573696e67204c6172676572205468616e20426c6f63"~ "6b2d53697a65204b6579202d2048617368204b6579204669727374" ]; static const int[] test_repeat = [ 1, 1, 50, 1 ]; static const char[][] test_results = [ "b617318655057264e28bc0b6fb378c8ef146be00", "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79", "125d7342b9ac11cd91a39af48aa17b4f63f175d3", "aa4ae5e15272d00e95705637ce8a3b55ed402112" ]; HMAC h = new HMAC(new SHA1()); foreach (uint i, char[] k; test_keys) { h.init(new SymmetricKey(Util.hexToUbytes(k))); for (int j = 0; j < test_repeat[i]; j++) h.update(Util.hexToUbytes(test_inputs[i])); char[] mac = h.hexDigest(); assert(mac == test_results[i], h.name~": ("~mac~") != ("~test_results[i]~")"); } } } }