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