summaryrefslogtreecommitdiff
path: root/qpid/dotnet/Qpid.Sasl/MD5HMAC.cs
blob: 7e310c536451add1e86598b11998c3a8cb24c540 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 */

using System;
using System.Security.Cryptography;

namespace Apache.Qpid.Sasl
{
   /// <summary>
   /// Rough HMAC MD5 implementation as presented in
   /// RFC 2104. Used because the HMACMD5 class in the 
   /// .NET framework is not available in v1.1.
   /// </summary>
   public sealed class MD5HMAC : IDisposable
   {
      private const int BLOCK_LEN = 64;
      private MD5 _hash;
      private byte[] _key;
      private byte[] _ipad;
      private byte[] _opad;

      public MD5HMAC(byte[] key)
      {
         if ( key == null || key.Length == 0 )
            throw new ArgumentNullException("key");

         _hash = new MD5CryptoServiceProvider();

         byte[] theKey = key;
         if ( theKey.Length > BLOCK_LEN )
         {
            theKey = _hash.ComputeHash(theKey);
         }
         // pad key with 0's up to BLOCK_LEN
         _key = new byte[BLOCK_LEN];
         Array.Copy(theKey, _key, theKey.Length);

         CreatePads();
      }

      public byte[] ComputeHash(byte[] input)
      {
         // H(K XOR opad, H(K XOR ipad, text))
         return H(_opad, H(_ipad, input));
      }

      public void Dispose()
      {
         if ( _hash != null )
         {
            ((IDisposable)_hash).Dispose();
            _hash = null;
         }
      }

      #region Private Methods
      //
      // Private Methods
      //

      private void CreatePads()
      {
         _ipad = new byte[BLOCK_LEN];
         _opad = new byte[BLOCK_LEN];
         for ( int i = 0; i < BLOCK_LEN; i++ )
         {
            _ipad[i] = 0x36;
            _opad[i] = 0x5c;
         }

         XOR(_ipad, _key);
         XOR(_opad, _key);
      }

      private static void XOR(byte[] dest, byte[] other)
      {
         // assume both are same size
         for ( int i = 0; i < dest.Length; i++ )
         {
            dest[i] ^= other[i];
         }
      }

      private byte[] H(byte[] v1, byte[] v2)
      {
         byte[] total = new byte[v1.Length + v2.Length];
         Array.Copy(v1, total, v1.Length);
         Array.Copy(v2, 0, total, v1.Length, v2.Length);

         return _hash.ComputeHash(total);
      }

      #endregion // Private Methods

   } // class MD5HMAC

} // namespace Apache.Qpid.Sasl