2 // HMACSHA1.cs: Handles HMAC with SHA-1
5 // Sebastien Pouliot (spouliot@motus.com)
7 // (C) 2002 Motus Technologies Inc. (http://www.motus.com)
12 using System.Security.Cryptography;
14 namespace System.Security.Cryptography {
17 // a. FIPS PUB 198: The Keyed-Hash Message Authentication Code (HMAC), 2002 March.
18 // http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf
19 // b. Internet RFC 2104, HMAC, Keyed-Hashing for Message Authentication
20 // (include C source for HMAC-MD5)
21 // http://www.ietf.org/rfc/rfc2104.txt
22 // c. IETF RFC2202: Test Cases for HMAC-MD5 and HMAC-SHA-1
23 // (include C source for HMAC-MD5 and HAMAC-SHA1)
24 // http://www.ietf.org/rfc/rfc2202.txt
25 // d. ANSI X9.71, Keyed Hash Message Authentication Code.
27 // http://webstore.ansi.org/ansidocstore/product.asp?sku=ANSI+X9%2E71%2D2000
29 // Generic HMAC mechanisms - most of HMAC work is done in here.
30 // It should work with any hash function e.g. MD5 for HMACMD5 (RFC2104)
31 internal class HMACAlgorithm {
34 private HashAlgorithm algo;
35 private string hashName;
36 private CryptoStream stream;
38 public HMACAlgorithm (string algoName)
40 CreateHash (algoName);
48 private void CreateHash (string algoName)
50 algo = (HashAlgorithm) CryptoConfig.CreateFromName (algoName);
54 public void Dispose ()
59 public HashAlgorithm Algo {
63 public string HashName {
64 get { return hashName; }
66 // only if its not too late for a change
72 public byte[] HashValue {
79 if ((value != null) && (value.Length > 64))
80 key = algo.ComputeHash (value);
82 key = (byte[]) value.Clone();
86 public void Initialize ()
91 private byte[] KeySetup (byte[] key, byte padding)
93 byte[] buf = new byte [64];
95 for (int i = 0; i < key.Length; ++i)
96 buf [i] = (byte) ((byte) key [i] ^ padding);
98 for (int i = key.Length; i < 64; ++i)
104 public void Core (byte[] rgb, int ib, int cb)
106 if (stream == null) {
107 byte[] buf = KeySetup (key, 0x36);
109 stream = new CryptoStream (Stream.Null, algo, CryptoStreamMode.Write);
110 stream.Write (buf, 0, buf.Length);
112 stream.Write (rgb, ib, cb);
115 public byte[] Final ()
119 byte[] intermediate = algo.Hash;
120 byte[] buf = KeySetup (key, 0x5C);
123 stream = new CryptoStream (Stream.Null, algo, CryptoStreamMode.Write);
124 stream.Write (buf, 0, buf.Length);
125 stream.Write (intermediate, 0, intermediate.Length);
134 // Note: this key is different (well most of the time) from the key
135 // used in KeyHashAlgorithm (this one may be padded or hashed). So
136 // it need to be zeroized independently.
137 public void ZeroizeKey ()
140 Array.Clear (key, 0, key.Length);
144 public class HMACSHA1: KeyedHashAlgorithm {
145 private HMACAlgorithm hmac;
147 public HMACSHA1 () : base ()
149 hmac = new HMACAlgorithm ("SHA1");
154 public HMACSHA1 (byte[] rgbKey)
156 hmac = new HMACAlgorithm ("SHA1");
166 public override byte[] Key {
167 get { return base.Key; }
174 public string HashName {
175 get { return hmac.HashName; }
176 set { hmac.HashName = value; }
179 protected override void Dispose (bool disposing)
183 base.Dispose (disposing);
186 // generate a random 64 bits key
187 private void GenerateKey ()
189 KeyValue = new byte[8];
190 RandomNumberGenerator rng = RandomNumberGenerator.Create();
191 rng.GetBytes (KeyValue);
195 public override void Initialize ()
201 protected override void HashCore (byte[] rgb, int ib, int cb)
204 // let us throw an exception if hash name is invalid
205 // for HMACSHA1 (obviously this can't be done by the
206 // generic HMAC class)
207 if (! (hmac.Algo is SHA1))
208 throw new InvalidCastException ();
211 hmac.Core (rgb, ib, cb);
214 protected override byte[] HashFinal ()
217 return hmac.Final ();