1 //
2 // PasswordDeriveTest.cs - NUnit Test Cases for PasswordDerive
3 //
4 // Author:
5 //	Sebastien Pouliot (sebastien@ximian.com)
6 //
7 // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
8 // Copyright (C) 2004,2007 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 using NUnit.Framework;
31 using System;
32 using System.Security.Cryptography;
33 
34 namespace MonoTests.System.Security.Cryptography {
35 
36 // References:
37 // a.	PKCS#5: Password-Based Cryptography Standard
38 //	http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html
39 
40 [TestFixture]
41 public class PasswordDeriveBytesTest {
42 
43 	static byte[] salt = { 0xDE, 0xAD, 0xC0, 0xDE };
44 	static string ssalt = "DE-AD-C0-DE";
45 
46 	// Constructors
47 
48 	[Test]
49 	[ExpectedException (typeof (ArgumentNullException))]
Ctor_PasswordNullSalt()50 	public void Ctor_PasswordNullSalt ()
51 	{
52 		string pwd = null;
53 		PasswordDeriveBytes pdb = new PasswordDeriveBytes (pwd, salt);
54 	}
55 
56 	[Test]
Ctor_PasswordSaltNull()57 	public void Ctor_PasswordSaltNull ()
58 	{
59 		PasswordDeriveBytes pdb = new PasswordDeriveBytes ("s3kr3t", null);
60 		Assert.AreEqual ("SHA1", pdb.HashName, "HashName");
61 		Assert.AreEqual (100, pdb.IterationCount, "IterationCount");
62 		Assert.IsNull (pdb.Salt, "Salt");
63 	}
64 
65 	[Test]
Ctor_PasswordSalt()66 	public void Ctor_PasswordSalt ()
67 	{
68 		PasswordDeriveBytes pdb = new PasswordDeriveBytes ("s3kr3t", salt);
69 		Assert.AreEqual ("SHA1", pdb.HashName, "HashName");
70 		Assert.AreEqual (100, pdb.IterationCount, "IterationCount");
71 		Assert.AreEqual (ssalt, BitConverter.ToString (pdb.Salt), "Salt");
72 	}
73 
74 	[Test]
75 	[ExpectedException (typeof (ArgumentNullException))]
Ctor_PasswordNullSaltCspParameters()76 	public void Ctor_PasswordNullSaltCspParameters ()
77 	{
78 		string pwd = null;
79 		PasswordDeriveBytes pdb = new PasswordDeriveBytes (pwd, salt, new CspParameters ());
80 	}
81 
82 #if !MOBILE
83 	[Test]
84 	[Category ("NotWorking")] // CspParameters aren't supported by Mono (requires CryptoAPI)
Ctor_PasswordSaltNullCspParameters()85 	public void Ctor_PasswordSaltNullCspParameters ()
86 	{
87 		PasswordDeriveBytes pdb = new PasswordDeriveBytes ("s3kr3t", null, new CspParameters ());
88 		Assert.AreEqual ("SHA1", pdb.HashName, "HashName");
89 		Assert.AreEqual (100, pdb.IterationCount, "IterationCount");
90 		Assert.IsNull (pdb.Salt, "Salt");
91 	}
92 #endif
93 
94 	[Test]
Ctor_PasswordSaltCspParametersNull()95 	public void Ctor_PasswordSaltCspParametersNull ()
96 	{
97 		PasswordDeriveBytes pdb = new PasswordDeriveBytes ("s3kr3t", salt, null);
98 		Assert.AreEqual ("SHA1", pdb.HashName, "HashName");
99 		Assert.AreEqual (100, pdb.IterationCount, "IterationCount");
100 		Assert.AreEqual (ssalt, BitConverter.ToString (pdb.Salt), "Salt");
101 	}
102 
103 #if !MOBILE
104 	[Test]
105 	[Category ("NotWorking")] // CspParameters aren't supported by Mono (requires CryptoAPI)
Ctor_PasswordSaltCspParameters()106 	public void Ctor_PasswordSaltCspParameters ()
107 	{
108 		PasswordDeriveBytes pdb = new PasswordDeriveBytes ("s3kr3t", salt, new CspParameters ());
109 		Assert.AreEqual ("SHA1", pdb.HashName, "HashName");
110 		Assert.AreEqual (100, pdb.IterationCount, "IterationCount");
111 		Assert.AreEqual (ssalt, BitConverter.ToString (pdb.Salt), "Salt");
112 	}
113 #endif
114 
115 	[Test]
116 	[ExpectedException (typeof (ArgumentNullException))]
Ctor_PasswordNullSaltHashIteration()117 	public void Ctor_PasswordNullSaltHashIteration ()
118 	{
119 		string pwd = null;
120 		PasswordDeriveBytes pdb = new PasswordDeriveBytes (pwd, salt, "SHA1", 1);
121 	}
122 
123 	[Test]
Ctor_PasswordSaltNullHashIteration()124 	public void Ctor_PasswordSaltNullHashIteration ()
125 	{
126 		PasswordDeriveBytes pdb = new PasswordDeriveBytes ("s3kr3t", null, "SHA1", 1);
127 		Assert.AreEqual ("SHA1", pdb.HashName, "HashName");
128 		Assert.AreEqual (1, pdb.IterationCount, "IterationCount");
129 		Assert.IsNull (pdb.Salt, "Salt");
130 	}
131 
132 	[Test]
133 	[ExpectedException (typeof (ArgumentNullException))]
Ctor_PasswordSaltHashNullIteration()134 	public void Ctor_PasswordSaltHashNullIteration ()
135 	{
136 		PasswordDeriveBytes pdb = new PasswordDeriveBytes ("s3kr3t", salt, null, 1);
137 	}
138 
139 	[Test]
140 	[ExpectedException (typeof (ArgumentOutOfRangeException))]
Ctor_PasswordSaltHashIterationNegative()141 	public void Ctor_PasswordSaltHashIterationNegative ()
142 	{
143 		PasswordDeriveBytes pdb = new PasswordDeriveBytes ("s3kr3t", salt, "SHA1", -1);
144 	}
145 
146 	[Test]
147 	[ExpectedException (typeof (ArgumentOutOfRangeException))]
Ctor_PasswordSaltHashIterationZero()148 	public void Ctor_PasswordSaltHashIterationZero ()
149 	{
150 		PasswordDeriveBytes pdb = new PasswordDeriveBytes ("s3kr3t", salt, "SHA1", 0);
151 	}
152 
153 	[Test]
Ctor_PasswordSaltHashIterationMaxValue()154 	public void Ctor_PasswordSaltHashIterationMaxValue ()
155 	{
156 		PasswordDeriveBytes pdb = new PasswordDeriveBytes ("s3kr3t", salt, "SHA1", Int32.MaxValue);
157 		Assert.AreEqual ("SHA1", pdb.HashName, "HashName");
158 		Assert.AreEqual (Int32.MaxValue, pdb.IterationCount, "IterationCount");
159 		Assert.AreEqual (ssalt, BitConverter.ToString (pdb.Salt), "Salt");
160 	}
161 
162 	[Test]
Ctor_PasswordSaltHashIteration()163 	public void Ctor_PasswordSaltHashIteration ()
164 	{
165 		PasswordDeriveBytes pdb = new PasswordDeriveBytes ("s3kr3t", salt, "SHA1", 1);
166 		Assert.AreEqual ("SHA1", pdb.HashName, "HashName");
167 		Assert.AreEqual (1, pdb.IterationCount, "IterationCount");
168 		Assert.AreEqual (ssalt, BitConverter.ToString (pdb.Salt), "Salt");
169 	}
170 
171 	[Test]
172 	[ExpectedException (typeof (ArgumentNullException))]
Ctor_PasswordNullSaltHashIterationCspParameters()173 	public void Ctor_PasswordNullSaltHashIterationCspParameters ()
174 	{
175 		string pwd = null;
176 		PasswordDeriveBytes pdb = new PasswordDeriveBytes (pwd, salt, "SHA1", 1, new CspParameters ());
177 	}
178 
179 #if !MOBILE
180 	[Test]
181 	[Category ("NotWorking")] // CspParameters aren't supported by Mono (requires CryptoAPI)
Ctor_PasswordSaltNullHashIterationCspParameters()182 	public void Ctor_PasswordSaltNullHashIterationCspParameters ()
183 	{
184 		PasswordDeriveBytes pdb = new PasswordDeriveBytes ("s3kr3t", null, "SHA1", 1, new CspParameters ());
185 		Assert.AreEqual ("SHA1", pdb.HashName, "HashName");
186 		Assert.AreEqual (1, pdb.IterationCount, "IterationCount");
187 		Assert.IsNull (pdb.Salt, "Salt");
188 	}
189 #endif
190 
191 	[Test]
192 	[ExpectedException (typeof (ArgumentNullException))]
Ctor_PasswordSaltHashNullIterationCspParameters()193 	public void Ctor_PasswordSaltHashNullIterationCspParameters ()
194 	{
195 		PasswordDeriveBytes pdb = new PasswordDeriveBytes ("s3kr3t", salt, null, 1, new CspParameters ());
196 	}
197 
198 	[Test]
199 	[ExpectedException (typeof (ArgumentOutOfRangeException))]
Ctor_PasswordSaltHashIterationNegativeCspParameters()200 	public void Ctor_PasswordSaltHashIterationNegativeCspParameters ()
201 	{
202 		PasswordDeriveBytes pdb = new PasswordDeriveBytes ("s3kr3t", salt, "SHA1", -1, new CspParameters ());
203 	}
204 
205 	[Test]
206 	[ExpectedException (typeof (ArgumentOutOfRangeException))]
Ctor_PasswordSaltHashIterationZeroCspParameters()207 	public void Ctor_PasswordSaltHashIterationZeroCspParameters ()
208 	{
209 		PasswordDeriveBytes pdb = new PasswordDeriveBytes ("s3kr3t", salt, "SHA1", 0, new CspParameters ());
210 	}
211 
212 #if !MOBILE
213 	[Test]
214 	[Category ("NotWorking")] // CspParameters aren't supported by Mono (requires CryptoAPI)
Ctor_PasswordSaltHashIterationMaxValueCspParameters()215 	public void Ctor_PasswordSaltHashIterationMaxValueCspParameters ()
216 	{
217 		PasswordDeriveBytes pdb = new PasswordDeriveBytes ("s3kr3t", salt, "SHA1", Int32.MaxValue, new CspParameters ());
218 		Assert.AreEqual ("SHA1", pdb.HashName, "HashName");
219 		Assert.AreEqual (Int32.MaxValue, pdb.IterationCount, "IterationCount");
220 		Assert.AreEqual (ssalt, BitConverter.ToString (pdb.Salt), "Salt");
221 	}
222 #endif
223 
224 	[Test]
Ctor_PasswordSaltHashIterationCspParametersNull()225 	public void Ctor_PasswordSaltHashIterationCspParametersNull ()
226 	{
227 		PasswordDeriveBytes pdb = new PasswordDeriveBytes ("s3kr3t", salt, "SHA1", 1, null);
228 		Assert.AreEqual ("SHA1", pdb.HashName, "HashName");
229 		Assert.AreEqual (1, pdb.IterationCount, "IterationCount");
230 		Assert.AreEqual (ssalt, BitConverter.ToString (pdb.Salt), "Salt");
231 	}
232 
233 #if !MOBILE
234 	[Test]
235 	[Category ("NotWorking")] // CspParameters aren't supported by Mono (requires CryptoAPI)
Ctor_PasswordSaltHashIterationCspParameters()236 	public void Ctor_PasswordSaltHashIterationCspParameters ()
237 	{
238 		PasswordDeriveBytes pdb = new PasswordDeriveBytes ("s3kr3t", salt, "SHA1", 1, new CspParameters ());
239 		Assert.AreEqual ("SHA1", pdb.HashName, "HashName");
240 		Assert.AreEqual (1, pdb.IterationCount, "IterationCount");
241 		Assert.AreEqual (ssalt, BitConverter.ToString (pdb.Salt), "Salt");
242 	}
243 #endif
244 
245 	// Properties
246 
247 	[Test]
248 	[ExpectedException (typeof (ArgumentNullException))]
Property_HashName_Null()249 	public void Property_HashName_Null ()
250 	{
251 		PasswordDeriveBytes pdb = new PasswordDeriveBytes ("s3kr3t", salt, "SHA1", 1);
252 		Assert.AreEqual ("SHA1", pdb.HashName, "HashName");
253 		pdb.HashName = null;
254 	}
255 
256 	[Test]
Property_Salt()257 	public void Property_Salt ()
258 	{
259 		PasswordDeriveBytes pdb = new PasswordDeriveBytes ("s3kr3t", salt);
260 		Assert.AreEqual (ssalt, BitConverter.ToString (pdb.Salt), "Salt");
261 		pdb.Salt = null;
262 		Assert.IsNull (pdb.Salt, "Salt");
263 	}
264 
265 	[Test]
Property_Salt_Modify()266 	public void Property_Salt_Modify ()
267 	{
268 		PasswordDeriveBytes pdb = new PasswordDeriveBytes ("s3kr3t", salt);
269 		Assert.AreEqual (ssalt, BitConverter.ToString (pdb.Salt), "Salt");
270 		pdb.Salt [0] = 0xFF;
271 		// modification rejected (the property returned a copy of the salt)
272 		Assert.AreEqual (ssalt, BitConverter.ToString (pdb.Salt), "Salt");
273 	}
274 
275 	// 1.0/1.1 compatibility
276 
277 
278 	// Old tests
279 
ToInt32LE(byte [] bytes, int offset)280 	static int ToInt32LE(byte [] bytes, int offset)
281 	{
282 		return (bytes[offset + 3] << 24) | (bytes[offset + 2] << 16) | (bytes[offset + 1] << 8) | bytes[offset];
283 	}
284 
285 	// generate the key up to HashSize and reset between operations
ShortRun(string msg, PasswordDeriveBytes pd, byte[] finalKey)286 	public void ShortRun(string msg, PasswordDeriveBytes pd, byte[] finalKey)
287 	{
288 		for (int i=0; i < finalKey.Length; i++) {
289 			int j = 0;
290 			bool compare = true;
291 			byte[] key = pd.GetBytes (i+1);
292 			for (; j < i; j++) {
293 				if (finalKey [j] != key[j]) {
294 					compare = false;
295 					break;
296 				}
297 			}
298 			Assert.IsTrue (compare, msg + " #" + j);
299 			pd.Reset ();
300 		}
301 	}
302 
303 	// generate a key at least 1000 bytes and don't reset between operations
LongRun(string msg, PasswordDeriveBytes pd, byte[] finalKey)304 	public void LongRun(string msg, PasswordDeriveBytes pd, byte[] finalKey)
305 	{
306 		int bloc = finalKey.Length;
307 		int iter = (int) ((1000 + bloc - 1) / bloc);
308 		byte[] pass = null;
309 		for (int i=0; i < iter; i++) {
310 			pass = pd.GetBytes (bloc);
311 		}
312 		Assert.AreEqual (pass, finalKey, msg);
313 	}
314 
Run(string password, byte[] salt, string hashname, int iterations, int getbytes, int lastFourBytes)315 	public void Run (string password, byte[] salt, string hashname, int iterations, int getbytes, int lastFourBytes)
316 	{
317 		PasswordDeriveBytes pd = new PasswordDeriveBytes (password, salt, hashname, iterations);
318 		byte[] key = pd.GetBytes (getbytes);
319 		string msg = "[pwd=" + password;
320 		msg += ", salt=" + ((salt == null) ? "null" : salt.Length.ToString ());
321 		msg += ", hash=" + hashname;
322 		msg += ", iter=" + iterations;
323 		msg += ", get=" + getbytes + "]";
324 		Assert.AreEqual (lastFourBytes, ToInt32LE (key, key.Length - 4), msg);
325 	}
326 
327 	[Test]
328 	[ExpectedException (typeof (IndexOutOfRangeException))]
TooShort()329 	public void TooShort ()
330 	{
331 		PasswordDeriveBytes pd = new PasswordDeriveBytes ("password", null, "SHA1", 1);
332 		byte[] key = pd.GetBytes (0);
333 	}
334 
TooLong(string hashName, int size, int lastFourBytes)335 	public void TooLong (string hashName, int size, int lastFourBytes)
336 	{
337 		PasswordDeriveBytes pd = new PasswordDeriveBytes ("toolong", null, hashName, 1);
338 
339 		// this should work (we check the last four devired bytes to be sure)
340 		byte[] key = pd.GetBytes (size);
341 		Assert.AreEqual (lastFourBytes, ToInt32LE (key, size - 4), "Last 4 bytes");
342 
343 		// but we can't get another byte from it!
344 		try {
345 			key = pd.GetBytes (1);
346 			Assert.Fail ("Expected CryptographicException but got none");
347 		}
348 		catch (CryptographicException) {
349 			// LAMESPEC: no limit is documented
350 		}
351 		catch (Exception e) {
352 			Assert.Fail ("Expected CryptographicException but got " + e.ToString ());
353 		}
354 	}
355 
356 	[Test]
TooLong()357 	public void TooLong ()
358 	{
359 		// 1000 times hash length is the maximum
360 		TooLong ("MD5",    16000, 1135777886);
361 		TooLong ("SHA1",   20000, -1167918035);
362 		TooLong ("SHA256", 32000, -358766048);
363 		TooLong ("SHA384", 48000, 1426370534);
364 		TooLong ("SHA512", 64000, -1763233543);
365 	}
366 
367 	[Test]
OneIteration()368 	public void OneIteration ()
369 	{
370 		// (1) size of hash, (2) size of 2 hash
371 		Run ("password", salt, "MD5",    1, 16, 986357363);
372 		Run ("monomono", null, "MD5",    1, 32, -1092059875);
373 		Run ("password", salt, "SHA1",   1, 20, -1251929751);
374 		Run ("monomono", null, "SHA1",   1, 40, -1148594972);
375 		Run ("password", salt, "SHA256", 1, 32, -1106908309);
376 		Run ("monomono", null, "SHA256", 1, 64, 1243724695);
377 		Run ("password", salt, "SHA384", 1, 48, 1338639872);
378 		Run ("monomono", null, "SHA384", 1, 96, -1974067932);
379 		Run ("password", salt, "SHA512", 1, 64, 998927776);
380 		Run ("monomono", null, "SHA512", 1, 128, -1082987985);
381 	}
382 
383 	[Test]
Salt()384 	public void Salt ()
385 	{
386 		Run ("password", salt, "MD5",  10, 10, -1174247292);
387 		Run ("monomono", salt, "SHA1", 20, 20, 622814236);
388 		Run ("password", salt, "MD5",  30, 30, 1491759020);
389 		Run ("monomono", salt, "SHA1", 40, 40, 1186751819);
390 		Run ("password", salt, "MD5",  50, 50, -1416348895);
391 		Run ("monomono", salt, "SHA1", 60, 60, -1167799882);
392 		Run ("password", salt, "MD5",  70, 70, -695745351);
393 		Run ("monomono", salt, "SHA1", 80, 80, 598766793);
394 		Run ("password", salt, "MD5",  90, 90, -906351079);
395 		Run ("monomono", salt, "SHA1", 100, 100, 1247157997);
396 	}
397 
398 	[Test]
NoSalt()399 	public void NoSalt ()
400 	{
401 		Run ("password", null, "MD5",  10, 10, -385488886);
402 		Run ("password", null, "SHA1", 20, 20, -385953596);
403 		Run ("password", null, "MD5",  30, 30, -669295228);
404 		Run ("password", null, "SHA1", 40, 40, -1921654064);
405 		Run ("password", null, "MD5",  50, 50, -1664099354);
406 		Run ("monomono", null, "SHA1", 60, 60, -1988511363);
407 		Run ("monomono", null, "MD5",  70, 70, -1326415479);
408 		Run ("monomono", null, "SHA1", 80, 80, 158880373);
409 		Run ("monomono", null, "MD5",  90, 90,  532527918);
410 		Run ("monomono", null, "SHA1", 100, 100, 769250758);
411 	}
412 
413 	[Test]
MD5()414 	public void MD5 ()
415 	{
416 		const string hashName = "MD5";
417 		// getbytes less than hash size
418 		Run ("password", null, hashName, 10, 10, -385488886);
419 		// getbytes equal to hash size
420 		Run ("password", salt, hashName, 20, 16, -470982134);
421 		// getbytes more than hash size
422 		Run ("password", null, hashName, 30, 30, -669295228);
423 		Run ("password", salt, hashName, 40, 40, 892279589);
424 		Run ("password", null, hashName, 50, 50, -1664099354);
425 		Run ("monomono", salt, hashName, 60, 60, -2050574033);
426 		Run ("monomono", null, hashName, 70, 70, -1326415479);
427 		Run ("monomono", salt, hashName, 80, 80, 2047895994);
428 		Run ("monomono", null, hashName, 90, 90, 532527918);
429 		Run ("monomono", salt, hashName, 100, 100, 1522243696);
430 	}
431 
432 	[Test]
SHA1()433 	public void SHA1 ()
434 	{
435 		const string hashName = "SHA1";
436 		// getbytes less than hash size
437 		Run ("password", null, hashName, 10, 10, -852142057);
438 		// getbytes equal to hash size
439 		Run ("password", salt, hashName, 20, 20, -1096621819);
440 		// getbytes more than hash size
441 		Run ("password", null, hashName, 30, 30, 1748347042);
442 		Run ("password", salt, hashName, 40, 40, 900690664);
443 		Run ("password", null, hashName, 50, 50, 2125027038);
444 		Run ("monomono", salt, hashName, 60, 60, -1167799882);
445 		Run ("monomono", null, hashName, 70, 70, -1967623713);
446 		Run ("monomono", salt, hashName, 80, 80, 598766793);
447 		Run ("monomono", null, hashName, 90, 90, -1754629926);
448 		Run ("monomono", salt, hashName, 100, 100, 1247157997);
449 	}
450 
451 	[Test]
SHA256()452 	public void SHA256 ()
453 	{
454 		const string hashName = "SHA256";
455 		// getbytes less than hash size
456 		Run ("password", null, hashName, 10, 10, -1636557322);
457 		Run ("password", salt, hashName, 20, 20, -1403130075);
458 		// getbytes equal to hash size
459 		Run ("password", null, hashName, 30, 32, -1013167039);
460 		// getbytes more than hash size
461 		Run ("password", salt, hashName, 40, 40, 379553148);
462 		Run ("password", null, hashName, 50, 50, 1031928292);
463 		Run ("monomono", salt, hashName, 60, 60, 1933836953);
464 		Run ("monomono", null, hashName, 70, 70, -956782587);
465 		Run ("monomono", salt, hashName, 80, 80, 1239391711);
466 		Run ("monomono", null, hashName, 90, 90, -872090432);
467 		Run ("monomono", salt, hashName, 100, 100, -591569127);
468 	}
469 
470 	[Test]
SHA384()471 	public void SHA384 ()
472 	{
473 		const string hashName = "SHA384";
474 		// getbytes less than hash size
475 		Run ("password", null, hashName, 10, 10, 323393534);
476 		Run ("password", salt, hashName, 20, 20, -2034683704);
477 		Run ("password", null, hashName, 30, 32, 167978389);
478 		Run ("password", salt, hashName, 40, 40, 2123410525);
479 		// getbytes equal to hash size
480 		Run ("password", null, hashName, 50, 48, -47538843);
481 		// getbytes more than hash size
482 		Run ("monomono", salt, hashName, 60, 60, -118610774);
483 		Run ("monomono", null, hashName, 70, 70, 772360425);
484 		Run ("monomono", salt, hashName, 80, 80, -1018881215);
485 		Run ("monomono", null, hashName, 90, 90, -1585583772);
486 		Run ("monomono", salt, hashName, 100, 100, -821501990);
487 	}
488 
489 	[Test]
SHA512()490 	public void SHA512 ()
491 	{
492 		const string hashName = "SHA512";
493 		// getbytes less than hash size
494 		Run ("password", null, hashName, 10, 10, 708870265);
495 		Run ("password", salt, hashName, 20, 20, 23889227);
496 		Run ("password", null, hashName, 30, 32, 1718904507);
497 		Run ("password", salt, hashName, 40, 40, 979228711);
498 		Run ("password", null, hashName, 50, 48, 1554003653);
499 		// getbytes equal to hash size
500 		Run ("monomono", salt, hashName, 60, 64, 1251099126);
501 		// getbytes more than hash size
502 		Run ("monomono", null, hashName, 70, 70, 1021441810);
503 		Run ("monomono", salt, hashName, 80, 80, 640059310);
504 		Run ("monomono", null, hashName, 90, 90, 1178147201);
505 		Run ("monomono", salt, hashName, 100, 100, 206423887);
506 	}
507 
508 	// get one block after the other
509 	[Test]
OneByOne()510 	public void OneByOne ()
511 	{
512 		byte[] key = { 0x91, 0xDA, 0xF9, 0x9D, 0x7C, 0xA9, 0xB4, 0x42, 0xB8, 0xD9, 0x45, 0xAB, 0x69, 0xEE, 0x12, 0xBC, 0x48, 0xDD, 0x38, 0x74 };
513 		PasswordDeriveBytes pd = new PasswordDeriveBytes ("password", salt, "SHA1", 1);
514 		string msg = "PKCS#5-Long password salt SHA1 (1)";
515 
516 		int bloc = key.Length;
517 		int iter = (int) ((1000 + bloc - 1) / bloc);
518 		byte[] pass = null;
519 		for (int i=0; i < iter; i++) {
520 			pass = pd.GetBytes (bloc);
521 		}
522 		Assert.AreEqual (pass, key, msg);
523 	}
524 
525 	[Test]
SHA1SaltShortRun()526 	public void SHA1SaltShortRun ()
527 	{
528 		byte[] key = { 0x0B, 0x61, 0x93, 0x96, 0x3A, 0xFF, 0x0D, 0xFC, 0xF6, 0x3D, 0xA3, 0xDB, 0x34, 0xC2, 0x99, 0x71, 0x69, 0x11, 0x61, 0xB5 };
529 		PasswordDeriveBytes pd = new PasswordDeriveBytes ("password", salt, "SHA1", 1);
530 		string msg = "PKCS#5 password salt SHA1 (1)";
531 		ShortRun (msg, pd, key);
532 	}
533 
534 	[Test]
SHA1SaltLongRun()535 	public void SHA1SaltLongRun ()
536 	{
537 		byte[] key = { 0x91, 0xDA, 0xF9, 0x9D, 0x7C, 0xA9, 0xB4, 0x42, 0xB8, 0xD9, 0x45, 0xAB, 0x69, 0xEE, 0x12, 0xBC, 0x48, 0xDD, 0x38, 0x74 };
538 		PasswordDeriveBytes pd = new PasswordDeriveBytes ("password", salt, "SHA1", 1);
539 		string msg = "PKCS#5-Long password salt SHA1 (1)";
540 		LongRun (msg, pd, key);
541 	}
542 
543 	[Test]
SHA1NoSaltShortRun()544 	public void SHA1NoSaltShortRun ()
545 	{
546 		byte[] key = { 0x74, 0x61, 0x03, 0x6C, 0xA1, 0xFE, 0x85, 0x3E, 0xD9, 0x3F, 0x03, 0x06, 0x58, 0x45, 0xDE, 0x36, 0x52, 0xEF, 0x4B, 0x68 };
547 		PasswordDeriveBytes pd = new PasswordDeriveBytes ("mono", null, "SHA1", 10);
548 		string msg = "PKCS#5 mono null SHA1 (10)";
549 		ShortRun (msg, pd, key);
550 	}
551 
552 	[Test]
SHA1NoSaltLongRun()553 	public void SHA1NoSaltLongRun ()
554 	{
555 		byte[] key = { 0x3A, 0xF8, 0x33, 0x88, 0x39, 0x61, 0x29, 0x75, 0x5C, 0x17, 0xD2, 0x9E, 0x8A, 0x78, 0xEB, 0xBD, 0x89, 0x1E, 0x4C, 0x67 };
556 		PasswordDeriveBytes pd = new PasswordDeriveBytes ("mono", null, "SHA1", 10);
557 		string msg = "PKCS#5-Long mono null SHA1 (10)";
558 		LongRun (msg, pd, key);
559 	}
560 
561 	[Test]
MD5SaltShortRun()562 	public void MD5SaltShortRun ()
563 	{
564 		byte[] key = { 0xA5, 0x4D, 0x4E, 0xDD, 0x3A, 0x59, 0xAC, 0x98, 0x08, 0xDA, 0xE7, 0xF2, 0x85, 0x2F, 0x7F, 0xF2 };
565 		PasswordDeriveBytes pd = new PasswordDeriveBytes ("mono", salt, "MD5", 100);
566 		string msg = "PKCS#5 mono salt MD5 (100)";
567 		ShortRun (msg, pd, key);
568 	}
569 
570 	[Test]
MD5SaltLongRun()571 	public void MD5SaltLongRun ()
572 	{
573 		byte[] key = { 0x92, 0x51, 0x4D, 0x10, 0xE1, 0x5F, 0xA8, 0x44, 0xEF, 0xFC, 0x0F, 0x1F, 0x6F, 0x3E, 0x40, 0x36 };
574 		PasswordDeriveBytes pd = new PasswordDeriveBytes ("mono", salt, "MD5", 100);
575 		string msg = "PKCS#5-Long mono salt MD5 (100)";
576 		LongRun (msg, pd, key);
577 	}
578 
579 	[Test]
MD5NoSaltShortRun()580 	public void MD5NoSaltShortRun ()
581 	{
582 		byte[] key = { 0x39, 0xEB, 0x82, 0x84, 0xCF, 0x1A, 0x3B, 0x3C, 0xA1, 0xF2, 0x68, 0xAF, 0xBF, 0xAC, 0x41, 0xA6 };
583 		PasswordDeriveBytes pd = new PasswordDeriveBytes ("password", null, "MD5", 1000);
584 		string msg = "PKCS#5 password null MD5 (1000)";
585 		ShortRun (msg, pd, key);
586 	}
587 
588 	[Test]
MD5NoSaltLongRun()589 	public void MD5NoSaltLongRun ()
590 	{
591 		byte[] key = { 0x49, 0x3C, 0x00, 0x69, 0xB4, 0x55, 0x21, 0xA4, 0xC9, 0x69, 0x2E, 0xFF, 0xAA, 0xED, 0x4C, 0x72 };
592 		PasswordDeriveBytes pd = new PasswordDeriveBytes ("password", null, "MD5", 1000);
593 		string msg = "PKCS#5-Long password null MD5 (1000)";
594 		LongRun (msg, pd, key);
595 	}
596 
597 	[Test]
Properties()598 	public void Properties ()
599 	{
600 		// create object...
601 		PasswordDeriveBytes pd = new PasswordDeriveBytes ("password", null, "MD5", 1000);
602 		Assert.AreEqual ("MD5", pd.HashName, "HashName-MD5");
603 		Assert.AreEqual (1000, pd.IterationCount, "IterationCount-1000");
604 		// ...then change all its properties...
605 		pd.HashName = "SHA1";
606 		Assert.AreEqual ("SHA1", pd.HashName, "HashName-SHA1");
607 		pd.Salt = salt;
608 		Assert.AreEqual (ssalt, BitConverter.ToString (pd.Salt), "Salt");
609 		pd.IterationCount = 1;
610 		Assert.AreEqual (1, pd.IterationCount, "IterationCount-1");
611 		byte[] expectedKey = { 0x0b, 0x61, 0x93, 0x96 };
612 		// ... before using it
613 		Assert.AreEqual (expectedKey, pd.GetBytes (4), "PKCS#5 test properties");
614 		// it should work but if we try to set any properties after GetBytes
615 		// they should all throw an exception
616 		try {
617 			pd.HashName = "SHA256";
618 			Assert.Fail ("PKCS#5 can't set HashName after GetBytes - expected CryptographicException but got none");
619 		}
620 		catch (CryptographicException) {
621 			// do nothing, this is what we expect
622 		}
623 		catch (Exception e) {
624 			Assert.Fail ("PKCS#5 can't set HashName after GetBytes - expected CryptographicException but got " + e.ToString ());
625 		}
626 		try {
627 			pd.Salt = expectedKey;
628 			Assert.Fail ("PKCS#5 can't set Salt after GetBytes - expected CryptographicException but got none");
629 		}
630 		catch (CryptographicException) {
631 			// do nothing, this is what we expect
632 		}
633 		catch (Exception e) {
634 			Assert.Fail ("PKCS#5 can't set Salt after GetBytes - expected CryptographicException but got " + e.ToString ());
635 		}
636 		try {
637 			pd.IterationCount = 10;
638 			Assert.Fail ("PKCS#5 can't set IterationCount after GetBytes - expected CryptographicException but got none");
639 		}
640 		catch (CryptographicException) {
641 			// do nothing, this is what we expect
642 		}
643 		catch (Exception e) {
644 			Assert.Fail ("PKCS#5 can't set IterationCount after GetBytes - expected CryptographicException but got " + e.ToString ());
645 		}
646 
647 		pd.Reset ();
648 		// finally a useful reset :)
649 		pd.HashName = "SHA256";
650 		pd.Salt = expectedKey;
651 		pd.IterationCount = 10;
652 	}
653 
654 	// FIXME: should we treat this as a bug or as a feature ?
655 	[Test]
StrangeBehaviour()656 	public void StrangeBehaviour ()
657 	{
658 		// create object with a salt...
659 		PasswordDeriveBytes pd = new PasswordDeriveBytes ("password", salt, "MD5", 1000);
660 		// ...then change the salt to null
661 		pd.Salt = null;
662 	}
663 
664 	[Test]
665 	[ExpectedException (typeof (CryptographicException))]
CryptDeriveKey_TooLongKey()666 	public void CryptDeriveKey_TooLongKey ()
667 	{
668 		PasswordDeriveBytes pd = new PasswordDeriveBytes ("password", null, "MD5", 1000);
669 		pd.CryptDeriveKey ("AlgName", "MD5", -256, new byte [8]);
670 	}
671 
672 #if !MOBILE
673 	[Test]
674 	[Category ("NotWorking")] // bug #79499
LongMultipleGetBytes()675 	public void LongMultipleGetBytes ()
676 	{
677 		// based on http://bugzilla.ximian.com/show_bug.cgi?id=79499
678 		PasswordDeriveBytes pd = new PasswordDeriveBytes ("mono", new byte[20]);
679 		string key = BitConverter.ToString (pd.GetBytes (32));
680 		Assert.AreEqual ("88-0A-AE-0A-41-61-02-78-FD-E2-70-9F-25-13-14-28-1F-C7-D9-72-9A-AE-CA-3F-BD-31-B4-F0-BD-8E-5B-98", key, "key");
681 		string iv = BitConverter.ToString (pd.GetBytes (16));
682 		Assert.AreEqual ("FD-E2-70-9F-25-13-14-28-4D-3F-9B-F8-EE-AA-95-ED", iv, "iv");
683 		pd.Reset ();
684 		// bytes from 32-40 are different from calling GetBytes separately
685 		Assert.AreEqual (key + "-F6-55-6C-3E-54-8B-F3-73-4D-3F-9B-F8-EE-AA-95-ED", BitConverter.ToString (pd.GetBytes (48)), "same");
686 	}
687 #endif
688 }
689 
690 }
691