This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[mono.git] / mcs / class / Mono.Security / Mono.Security.Protocol.Tls / SslHandshakeHash.cs
1
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining
4 // a copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to
8 // permit persons to whom the Software is furnished to do so, subject to
9 // the following conditions:
10 // 
11 // The above copyright notice and this permission notice shall be
12 // included in all copies or substantial portions of the Software.
13 // 
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 //
22 /* Transport Security Layer (TLS)
23  * Copyright (c) 2003-2004 Carlos Guzman Alvarez
24  * 
25  * Permission is hereby granted, free of charge, to any person 
26  * obtaining a copy of this software and associated documentation 
27  * files (the "Software"), to deal in the Software without restriction, 
28  * including without limitation the rights to use, copy, modify, merge, 
29  * publish, distribute, sublicense, and/or sell copies of the Software, 
30  * and to permit persons to whom the Software is furnished to do so, 
31  * subject to the following conditions:
32  * 
33  * The above copyright notice and this permission notice shall be included 
34  * in all copies or substantial portions of the Software.
35  * 
36  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
37  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
38  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
39  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
40  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
41  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
42  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
43  * DEALINGS IN THE SOFTWARE.
44  */
45
46 using System;
47 using System.Security.Cryptography;
48
49 namespace Mono.Security.Protocol.Tls
50 {
51         internal class SslHandshakeHash : System.Security.Cryptography.HashAlgorithm
52         {
53                 #region Fields
54
55                 private HashAlgorithm   md5;
56                 private HashAlgorithm   sha;
57                 private bool                    hashing;
58                 private byte[]                  secret;
59                 private byte[]                  innerPadMD5;
60                 private byte[]                  outerPadMD5;
61                 private byte[]                  innerPadSHA;
62                 private byte[]                  outerPadSHA;
63
64                 #endregion
65
66                 #region Constructors
67
68                 public SslHandshakeHash(byte[] secret)
69                 {
70                         // Create md5 and sha1 hashes
71                         this.md5 = HashAlgorithm.Create("MD5");
72                         this.sha = HashAlgorithm.Create("SHA1");
73                         
74                         // Set HashSizeValue
75                         this.HashSizeValue = md5.HashSize + sha.HashSize;
76
77                         // Update secret
78                         this.secret = secret;
79
80                         this.Initialize();
81                 }
82
83                 #endregion
84
85                 #region Methods
86
87                 public override void Initialize()
88                 {
89                         this.md5.Initialize();
90                         this.sha.Initialize();
91                         this.initializePad();
92                         this.hashing = false;
93                 }
94
95                 protected override byte[] HashFinal()
96                 {
97                         if (!this.hashing)
98                         {
99                                 this.hashing = true;
100                         }
101
102                         // Finalize the md5 hash
103                         this.md5.TransformBlock(this.secret, 0, this.secret.Length, this.secret, 0);
104                         this.md5.TransformFinalBlock(this.innerPadMD5, 0, this.innerPadMD5.Length);
105
106                         byte[] firstResultMD5 = this.md5.Hash;
107
108                         this.md5.Initialize();
109                         this.md5.TransformBlock(this.secret, 0, this.secret.Length, this.secret, 0);
110                         this.md5.TransformBlock(this.outerPadMD5, 0, this.outerPadMD5.Length, this.outerPadMD5, 0);
111                         this.md5.TransformFinalBlock(firstResultMD5, 0, firstResultMD5.Length);
112                         
113                         // Finalize the sha1 hash
114                         this.sha.TransformBlock(this.secret, 0, this.secret.Length, this.secret, 0);
115                         this.sha.TransformFinalBlock(this.innerPadSHA, 0, this.innerPadSHA.Length);
116
117                         byte[] firstResultSHA = this.sha.Hash;
118                         
119                         this.sha.Initialize();
120                         this.sha.TransformBlock(this.secret, 0, this.secret.Length, this.secret, 0);
121                         this.sha.TransformBlock(this.outerPadSHA, 0, this.outerPadSHA.Length, this.outerPadSHA, 0);
122                         this.sha.TransformFinalBlock(firstResultSHA, 0, firstResultSHA.Length);
123
124                         this.Initialize();
125
126                         byte[] result = new byte[36];
127
128                         Buffer.BlockCopy(this.md5.Hash, 0, result, 0, 16);
129                         Buffer.BlockCopy(this.sha.Hash, 0, result, 16, 20);
130
131                         return result;
132                 }
133
134                 protected override void HashCore(byte[] array, int ibStart, int cbSize)
135                 {
136                         if (!this.hashing)
137                         {
138                                 this.hashing = true;
139                         }
140
141                         this.md5.TransformBlock(array, ibStart, cbSize, array, ibStart);
142                         this.sha.TransformBlock(array, ibStart, cbSize, array, ibStart);
143                 }
144
145                 public byte[] CreateSignature(RSA rsa) 
146                 {
147                         if (rsa == null)
148                         {
149                                 throw new CryptographicUnexpectedOperationException ("missing key");
150                         }
151
152                         RSASslSignatureFormatter f = new RSASslSignatureFormatter(rsa);
153                         f.SetHashAlgorithm("SslHash");
154
155                         return f.CreateSignature(this.Hash);
156                 }
157
158                 public bool VerifySignature(RSA rsa, byte[] rgbSignature) 
159                 {
160                         if (rsa == null)
161                         {
162                                 throw new CryptographicUnexpectedOperationException ("missing key");
163                         }
164                         if (rgbSignature == null)
165                         {
166                                 throw new ArgumentNullException ("rgbSignature");
167                         }
168
169                         RSASslSignatureDeformatter d = new RSASslSignatureDeformatter(rsa);
170                         d.SetHashAlgorithm("SslHash");
171
172                         return d.VerifySignature(this.Hash, rgbSignature);
173                 }
174
175                 #endregion
176
177                 #region Private Methods
178
179                 private void initializePad()
180                 {
181                         // Fill md5 arrays
182                         this.innerPadMD5 = new byte[48];
183                         this.outerPadMD5 = new byte[48];
184
185                         /* Pad the key for inner and outer digest */
186                         for (int i = 0; i < 48; ++i) 
187                         {
188                                 this.innerPadMD5[i] = 0x36;
189                                 this.outerPadMD5[i] = 0x5C;
190                         }
191
192                         // Fill sha arrays
193                         this.innerPadSHA = new byte[40];
194                         this.outerPadSHA = new byte[40];
195
196                         /* Pad the key for inner and outer digest */
197                         for (int i = 0; i < 40; ++i) 
198                         {
199                                 this.innerPadSHA[i] = 0x36;
200                                 this.outerPadSHA[i] = 0x5C;
201                         }
202                 }
203
204                 #endregion
205         }
206 }