comparison dcrypt/crypto/macs/HMAC.d @ 4:3de3a2de13a0

Added MAC base class and HMAC. Added StreamCipherWrapper as part of the work on the high-level cipher API. Running on fumes, so hopefully there isn't too much stupid mixed into the code.
author Thomas Dixon <reikon@reikon.us>
date Thu, 14 Aug 2008 01:45:24 -0400
parents
children 5cb17e09d685
comparison
equal deleted inserted replaced
3:a5789a7b3b3b 4:3de3a2de13a0
1 /**
2 * This file is part of the dcrypt project.
3 *
4 * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved.
5 * License: MIT
6 * Authors: Thomas Dixon
7 */
8
9 module dcrypt.crypto.macs.HMAC;
10
11 import dcrypt.crypto.MAC;
12 import dcrypt.crypto.Hash;
13 import dcrypt.crypto.params.SymmetricKey;
14 import dcrypt.crypto.errors.NotInitializedError;
15
16 version (UnitTest) {
17 import dcrypt.crypto.hashes.SHA1;
18 }
19
20 /** Conforms: RFC2104 */
21 class HMAC : MAC {
22 private {
23 ubyte[] ipad, opad, key;
24 Hash inner, outer;
25 bool initialized;
26 }
27
28 this (Hash hash, void[] key=null) {
29 hash.reset();
30
31 inner = hash;
32 outer = hash.copy();
33
34 ipad = new ubyte[blockSize];
35 opad = new ubyte[blockSize];
36
37 reset();
38
39 if (key)
40 init(new SymmetricKey(key)); // I'm lazy.
41 }
42
43 void init(CipherParameters params) {
44 SymmetricKey keyParams = cast(SymmetricKey)params;
45 if (!keyParams)
46 throw new InvalidParameterError(
47 name()~": Invalid parameter passed to init");
48
49 if (keyParams.key.length > blockSize) {
50 inner.update(keyParams.key);
51 key = inner.digest();
52 } else
53 key = keyParams.key;
54
55 foreach (uint i, ubyte j; key) {
56 ipad[i] ^= j;
57 opad[i] ^= j;
58 }
59
60 inner.update(ipad);
61 outer.update(opad);
62
63 initialized = true;
64 }
65
66 void update(void[] input_) {
67 if (!initialized)
68 throw new NotInitializedError(
69 name()~": MAC not initialized.");
70 inner.update(input_);
71 }
72
73 char[] name() {
74 return inner.name~"/HMAC";
75 }
76
77 void reset() {
78 ipad[] = 0x36;
79 opad[] = 0x5c;
80
81 inner.reset();
82 outer.reset();
83 }
84
85 uint blockSize() {
86 return inner.blockSize;
87 }
88
89 uint macSize() {
90 return inner.digestSize;
91 }
92
93 ubyte[] finish() {
94 outer.update(inner.digest());
95 ubyte[] r = outer.digest();
96 reset();
97 return r;
98 }
99
100 char[] hexFinish() {
101 return Util.ubytesToHex(finish());
102 }
103
104 HMAC copy() {
105 // Ghetto... oh so ghetto :\
106 HMAC h = new HMAC(inner.copy());
107 h.inner = inner.copy();
108 h.outer = outer.copy();
109 h.initialized = true;
110 return h;
111 }
112
113 version (UnitTest) {
114 unittest {
115 static char[][] test_keys = [
116 "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
117 "4a656665", // Jefe?
118 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
119 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"~
120 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"~
121 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"~
122 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
123 ];
124
125 static char[][] test_inputs = [
126 "4869205468657265",
127 "7768617420646f2079612077616e7420666f72206e6f7468696e673f",
128 "dd",
129 "54657374205573696e67204c6172676572205468616e20426c6f63"~
130 "6b2d53697a65204b6579202d2048617368204b6579204669727374"
131 ];
132
133 static const int[] test_repeat = [
134 1, 1, 50, 1
135 ];
136
137 static const char[][] test_results = [
138 "b617318655057264e28bc0b6fb378c8ef146be00",
139 "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79",
140 "125d7342b9ac11cd91a39af48aa17b4f63f175d3",
141 "aa4ae5e15272d00e95705637ce8a3b55ed402112"
142 ];
143
144 HMAC h = new HMAC(new SHA1());
145 foreach (uint i, char[] k; test_keys) {
146 h.init(new SymmetricKey(Util.hexToUbytes(k)));
147 for (int j = 0; j < test_repeat[i]; j++)
148 h.update(Util.hexToUbytes(test_inputs[i]));
149 char[] mac = h.hexFinish();
150 assert(mac == test_results[i],
151 h.name~": ("~mac~") != ("~test_results[i]~")");
152 }
153 }
154 }
155 }