Merge pull request #225 from mistoll/master
[mono.git] / mcs / class / corlib / Test / System.Security.Cryptography / Rfc2898DeriveBytesTest.cs
1 //
2 // Rfc2898DeriveBytesTest.cs - NUnit Test Cases for Rfc2898DeriveBytes
3 //
4 // Author:
5 //      Sebastien Pouliot  <spouliot@ximian.com>
6 //
7 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
8 // Copyright (C) 2004,2008 Novell, Inc (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30 #if NET_2_0
31
32 using NUnit.Framework;
33
34 using System;
35 using System.Security.Cryptography;
36
37 namespace MonoTests.System.Security.Cryptography {
38
39         // References:
40         // a.   PKCS#5: Password-Based Cryptography Standard 
41         //      http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html
42         // b.   RFC 3211 - Password-based Encryption for CMS
43         //      http://www.faqs.org/rfcs/rfc3211.html
44
45         [TestFixture]
46         public class Rfc2898DeriveBytesTest {
47
48                 static private byte[] salt = { 0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0x12 };
49
50                 [Test]
51                 public void ConstructorPasswordSalt () 
52                 {
53                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", salt);
54                         Assert.AreEqual (1000, pkcs5.IterationCount, "IterationCount");
55                         Assert.AreEqual (salt, pkcs5.Salt, "Salt");
56                 }
57
58                 [Test]
59                 [ExpectedException (typeof (ArgumentNullException))]
60                 public void ConstructorPasswordNullSalt () 
61                 {
62                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes (null, salt);
63                 }
64
65                 [Test]
66                 [ExpectedException (typeof (ArgumentNullException))]
67                 public void ConstructorPasswordSaltNull () 
68                 {
69                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", null);
70                 }
71
72                 [Test]
73                 public void ConstructorPasswordSaltIterations () 
74                 {
75                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", salt, 5);
76                         Assert.AreEqual (5, pkcs5.IterationCount, "IterationCount");
77                         Assert.AreEqual (salt, pkcs5.Salt, "Salt");
78                 }
79
80                 [Test]
81                 [ExpectedException (typeof (ArgumentNullException))]
82                 public void ConstructorPasswordNullSaltIterations () 
83                 {
84                         string password = null;
85                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes (password, salt, 5);
86                 }
87
88                 [Test]
89                 [ExpectedException (typeof (ArgumentNullException))]
90                 public void ConstructorPasswordSaltNullIterations () 
91                 {
92                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", null, 5);
93                 }
94
95                 [Test]
96                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
97                 public void ConstructorPasswordSaltIterationsZero () 
98                 {
99                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", salt, 0);
100                 }
101
102                 [Test]
103                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
104                 public void ConstructorPasswordSaltIterationsNegative () 
105                 {
106                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", salt, Int32.MinValue);
107                 }
108
109                 [Test]
110                 public void ConstructorPasswordSaltLength () 
111                 {
112                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", 8);
113                         Assert.AreEqual (1000, pkcs5.IterationCount, "IterationCount");
114                         Assert.AreEqual (8, pkcs5.Salt.Length, "Salt");
115                 }
116
117                 [Test]
118                 [ExpectedException (typeof (ArgumentNullException))]
119                 public void ConstructorPasswordNullSaltLength () 
120                 {
121                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes (null, 8);
122                 }
123
124                 [Test]
125                 [ExpectedException (typeof (ArgumentException))]
126                 public void ConstructorPasswordSaltLengthZero () 
127                 {
128                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", 0);
129                 }
130
131                 [Test]
132                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
133                 public void ConstructorPasswordSaltLengthNegative () 
134                 {
135                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", Int32.MinValue);
136                 }
137
138                 [Test]
139                 public void ConstructorPasswordSaltLengthIterations () 
140                 {
141                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", 8, 5);
142                         Assert.AreEqual (5, pkcs5.IterationCount, "IterationCount");
143                         Assert.AreEqual (8, pkcs5.Salt.Length, "Salt");
144                 }
145
146                 [Test]
147                 [ExpectedException (typeof (ArgumentNullException))]
148                 public void ConstructorPasswordNullSaltLengthIterations () 
149                 {
150                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes (null, 8, 5);
151                 }
152
153                 [Test]
154                 [ExpectedException (typeof (ArgumentException))]
155                 public void ConstructorPasswordSaltLengthZeroIterations () 
156                 {
157                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", 0, 5);
158                 }
159
160                 [Test]
161                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
162                 public void ConstructorPasswordSaltLengthNegativeIterations () 
163                 {
164                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", Int32.MinValue, 5);
165                 }
166
167                 [Test]
168                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
169                 public void ConstructorPasswordSaltLengthIterationsZero () 
170                 {
171                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", 8, 0);
172                 }
173
174                 [Test]
175                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
176                 public void ConstructorPasswordSaltLengthIterationsNegative () 
177                 {
178                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", 8, Int32.MinValue);
179                 }
180
181                 [Test]
182                 public void IterationCount () 
183                 {
184                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", salt, 5);
185                         Assert.AreEqual (5, pkcs5.IterationCount, "IterationCount");
186                         pkcs5.IterationCount = Int32.MaxValue;
187                         Assert.AreEqual (Int32.MaxValue, pkcs5.IterationCount, "IterationCount");
188                 }
189
190                 [Test]
191                 public void SaltNew () 
192                 {
193                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", salt);
194                         Assert.AreEqual (salt, pkcs5.Salt, "Salt");
195                         byte[] newSalt = (byte[]) salt.Clone ();
196                         newSalt [0] = 0xFF;
197                         pkcs5.Salt = newSalt;
198                         Assert.AreEqual (newSalt, pkcs5.Salt, "Salt(new)");
199                 }
200
201                 [Test]
202                 public void SaltCantModifyInternal () 
203                 {
204                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", salt);
205                         Assert.AreEqual (salt, pkcs5.Salt, "Salt");
206                         byte[] modSalt = (byte[]) salt.Clone ();
207                         modSalt [0] = 0xFF;
208                         Assert.IsFalse ((BitConverter.ToString (pkcs5.Salt) == BitConverter.ToString (modSalt)), "Can't modify internal salt");
209                 }
210
211                 [Test]
212                 [ExpectedException (typeof (ArgumentNullException))]
213                 public void SaltNull () 
214                 {
215                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", salt);
216                         pkcs5.Salt = null;
217                 }
218
219                 [Test]
220                 [ExpectedException (typeof (ArgumentException))]
221                 public void SaltTooSmall () 
222                 {
223                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", salt);
224                         byte[] smallSalt = { 0x01, 0x02, 0x03, 0x04, 0x05 };
225                         pkcs5.Salt = smallSalt;
226                 }
227
228                 [Test]
229                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
230                 public void GetBytesZero ()
231                 {
232                         byte[] expected = { 0xd1, 0xda, 0xa7, 0x86, 0x15, 0xf2, 0x87, 0xe6 };
233                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", salt, 5);
234                         byte[] key = pkcs5.GetBytes (0);
235                         Assert.AreEqual (0, key.Length, "GetBytesZero");
236                 }
237
238                 [Test]
239                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
240                 public void GetBytesNegative () 
241                 {
242                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", salt, 5);
243                         byte[] key = pkcs5.GetBytes (Int32.MinValue);
244                 }
245
246                 [Test]
247                 public void GetBytes_Endian ()
248                 {
249                         string expected = "0B-40-39-04-B9-2B-F1-B9-C0-A0-64-E6-03-0A-5E-42-4B-88-1E-5E-94-8F-77-87-16-A6-C4-9E-E6-C7-6D-38";
250                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", salt, 5);
251                         // this will overflow F on multiple bytes (where endianess comes to play)
252                         byte[] key = pkcs5.GetBytes (32768);
253                         // just check the last 32 bytes
254                         string actual = BitConverter.ToString (key, key.Length - 32);
255                         Assert.AreEqual (expected, actual, "Endian");
256                 }
257
258                 [Test]
259                 public void RFC3211_TC1 () 
260                 {
261                         byte[] expected = { 0xd1, 0xda, 0xa7, 0x86, 0x15, 0xf2, 0x87, 0xe6 };
262                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", salt, 5);
263                         byte[] key = pkcs5.GetBytes (8);
264                         Assert.AreEqual (expected, key, "RFC3211_TC1");
265                 }
266
267                 [Test]
268                 public void RFC3211_TC2 () 
269                 {
270                         byte[] expected = { 0x6A, 0x89, 0x70, 0xBF, 0x68, 0xC9, 0x2C, 0xAE, 0xA8, 0x4A, 0x8D, 0xF2, 0x85, 0x10, 0x85, 0x86 };
271                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("All n-entities must communicate with other n-entities via n-1 entiteeheehees", salt, 500);
272                         byte[] key = pkcs5.GetBytes (16);
273                         Assert.AreEqual (expected, key, "RFC3211_TC2");
274                 }
275
276                 [Test]
277                 public void RFC3211_TC2_TwoBlocks () 
278                 {
279                         byte[] expected = { 0x6A, 0x89, 0x70, 0xBF, 0x68, 0xC9, 0x2C, 0xAE, 0xA8, 0x4A, 0x8D, 0xF2, 0x85, 0x10, 0x85, 0x86, 0x07, 0x12, 0x63, 0x80, 0xcc, 0x47, 0xab, 0x2d, 0xa6, 0xcc, 0xda, 0xfb, 0x26, 0x83, 0xdf, 0xe8 };
280                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("All n-entities must communicate with other n-entities via n-1 entiteeheehees", salt, 500);
281                         byte[] key = pkcs5.GetBytes (32);
282                         Assert.AreEqual (expected, key, "RFC3211_TC2_TwoBlocks");
283                 }
284
285                 [Test]
286                 public void RFC3211_TC2_Splitted_OneBlock () 
287                 {
288                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("All n-entities must communicate with other n-entities via n-1 entiteeheehees", salt, 500);
289                         byte[] key1 = pkcs5.GetBytes (8);
290                         byte[] expected_part1 = { 0x6A, 0x89, 0x70, 0xBF, 0x68, 0xC9, 0x2C, 0xAE };
291                         Assert.AreEqual (expected_part1, key1, "RFC3211_TC2_Splitted_OneBlock-1");
292                         byte[] expected_part2 = { 0xA8, 0x4A, 0x8D, 0xF2, 0x85, 0x10, 0x85, 0x86 };
293                         byte[] key2 = pkcs5.GetBytes (8);
294                         Assert.AreEqual (expected_part2, key2, "RFC3211_TC2_Splitted_OneBlock-2");
295                 }
296
297                 [Test]
298                 public void RFC3211_TC2_Splitted_TwoBlocks () 
299                 {
300                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("All n-entities must communicate with other n-entities via n-1 entiteeheehees", salt, 500);
301                         byte[] key1 = pkcs5.GetBytes (16);
302                         byte[] expected_part1 = { 0x6A, 0x89, 0x70, 0xBF, 0x68, 0xC9, 0x2C, 0xAE, 0xA8, 0x4A, 0x8D, 0xF2, 0x85, 0x10, 0x85, 0x86 };
303                         Assert.AreEqual (expected_part1, key1, "RFC3211_TC2_Splitted_TwoBlocks-1");
304                         byte[] expected_part2 = { 0x07, 0x12, 0x63, 0x80, 0xcc, 0x47, 0xab, 0x2d, 0xa6, 0xcc, 0xda, 0xfb, 0x26, 0x83, 0xdf, 0xe8 };
305                         byte[] key2 = pkcs5.GetBytes (16);
306                         Assert.AreEqual (expected_part2, key2, "RFC3211_TC2_Splitted_TwoBlocks-2");
307                 }
308
309                 [Test]
310                 public void RFC3211_TC2_Reset () 
311                 {
312                         byte[] expected = { 0x6A, 0x89, 0x70, 0xBF, 0x68, 0xC9, 0x2C, 0xAE };
313                         Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("All n-entities must communicate with other n-entities via n-1 entiteeheehees", salt, 500);
314                         byte[] key1 = pkcs5.GetBytes (8);
315                         Assert.AreEqual (expected, key1, "RFC3211_TC2_part1");
316                         pkcs5.Reset ();
317                         byte[] key2 = pkcs5.GetBytes (8);
318                         Assert.AreEqual (expected, key2, "RFC3211_TC2_part2");
319                 }
320
321                 private void CompareBuffers (byte [] big, byte [] a, byte [] b)
322                 {
323                         int n = 0;
324                         for (int i = 0; i < a.Length; i++) {
325                                 Assert.AreEqual (big [n], a [i], n.ToString ());
326                                 n++;
327                         }
328                         for (int i = 0; i < b.Length; i++) {
329                                 Assert.AreEqual (big [n], b [i], n.ToString ());
330                                 n++;
331                         }
332                 }
333
334                 [Test]
335                 public void SplitCalls_Reset ()
336                 {
337                         Rfc2898DeriveBytes keygen = new Rfc2898DeriveBytes ("password", salt, 12345);
338                         byte [] big = keygen.GetBytes (48);
339
340                         keygen.Reset ();
341                         byte [] a = keygen.GetBytes (16);
342                         byte [] b = keygen.GetBytes (32);
343
344                         CompareBuffers (big, a, b);
345                 }
346
347                 [Test]
348                 public void SplitCalls_TwoInstances ()
349                 {
350                         Rfc2898DeriveBytes keygen1 = new Rfc2898DeriveBytes ("password", salt, 12345);
351                         byte [] big = keygen1.GetBytes (48);
352
353                         Rfc2898DeriveBytes keygen2 = new Rfc2898DeriveBytes ("password", salt, 12345);
354                         byte [] a = keygen2.GetBytes (16);
355                         byte [] b = keygen2.GetBytes (32);
356
357                         CompareBuffers (big, a, b);
358                 }
359                 
360                 [Test]
361                 public void MultipleCalls_DoesntOverrunBuffer ()
362                 {
363                         Rfc2898DeriveBytes keygen = new Rfc2898DeriveBytes("Password", new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 });
364
365                         keygen.GetBytes(32);
366                         keygen.GetBytes(64);
367                 }
368         }
369 }
370
371 #endif