2 // Rfc2898DeriveBytesTest.cs - NUnit Test Cases for Rfc2898DeriveBytes
5 // Sebastien Pouliot <spouliot@ximian.com>
7 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
8 // Copyright (C) 2004,2008 Novell, Inc (http://www.novell.com)
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:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
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.
32 using NUnit.Framework;
35 using System.Security.Cryptography;
37 namespace MonoTests.System.Security.Cryptography {
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
46 public class Rfc2898DeriveBytesTest {
48 static private byte[] salt = { 0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0x12 };
51 public void ConstructorPasswordSalt ()
53 Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", salt);
54 Assert.AreEqual (1000, pkcs5.IterationCount, "IterationCount");
55 Assert.AreEqual (salt, pkcs5.Salt, "Salt");
59 [ExpectedException (typeof (ArgumentNullException))]
60 public void ConstructorPasswordNullSalt ()
62 Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes (null, salt);
66 [ExpectedException (typeof (ArgumentNullException))]
67 public void ConstructorPasswordSaltNull ()
69 Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", null);
73 public void ConstructorPasswordSaltIterations ()
75 Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", salt, 5);
76 Assert.AreEqual (5, pkcs5.IterationCount, "IterationCount");
77 Assert.AreEqual (salt, pkcs5.Salt, "Salt");
81 [ExpectedException (typeof (ArgumentNullException))]
82 public void ConstructorPasswordNullSaltIterations ()
84 string password = null;
85 Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes (password, salt, 5);
89 [ExpectedException (typeof (ArgumentNullException))]
90 public void ConstructorPasswordSaltNullIterations ()
92 Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", null, 5);
96 [ExpectedException (typeof (ArgumentOutOfRangeException))]
97 public void ConstructorPasswordSaltIterationsZero ()
99 Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", salt, 0);
103 [ExpectedException (typeof (ArgumentOutOfRangeException))]
104 public void ConstructorPasswordSaltIterationsNegative ()
106 Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", salt, Int32.MinValue);
110 public void ConstructorPasswordSaltLength ()
112 Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", 8);
113 Assert.AreEqual (1000, pkcs5.IterationCount, "IterationCount");
114 Assert.AreEqual (8, pkcs5.Salt.Length, "Salt");
118 [ExpectedException (typeof (ArgumentNullException))]
119 public void ConstructorPasswordNullSaltLength ()
121 Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes (null, 8);
125 [ExpectedException (typeof (ArgumentException))]
126 public void ConstructorPasswordSaltLengthZero ()
128 Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", 0);
132 [ExpectedException (typeof (ArgumentOutOfRangeException))]
133 public void ConstructorPasswordSaltLengthNegative ()
135 Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", Int32.MinValue);
139 public void ConstructorPasswordSaltLengthIterations ()
141 Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", 8, 5);
142 Assert.AreEqual (5, pkcs5.IterationCount, "IterationCount");
143 Assert.AreEqual (8, pkcs5.Salt.Length, "Salt");
147 [ExpectedException (typeof (ArgumentNullException))]
148 public void ConstructorPasswordNullSaltLengthIterations ()
150 Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes (null, 8, 5);
154 [ExpectedException (typeof (ArgumentException))]
155 public void ConstructorPasswordSaltLengthZeroIterations ()
157 Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", 0, 5);
161 [ExpectedException (typeof (ArgumentOutOfRangeException))]
162 public void ConstructorPasswordSaltLengthNegativeIterations ()
164 Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", Int32.MinValue, 5);
168 [ExpectedException (typeof (ArgumentOutOfRangeException))]
169 public void ConstructorPasswordSaltLengthIterationsZero ()
171 Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", 8, 0);
175 [ExpectedException (typeof (ArgumentOutOfRangeException))]
176 public void ConstructorPasswordSaltLengthIterationsNegative ()
178 Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", 8, Int32.MinValue);
182 public void IterationCount ()
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");
191 public void SaltNew ()
193 Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", salt);
194 Assert.AreEqual (salt, pkcs5.Salt, "Salt");
195 byte[] newSalt = (byte[]) salt.Clone ();
197 pkcs5.Salt = newSalt;
198 Assert.AreEqual (newSalt, pkcs5.Salt, "Salt(new)");
202 public void SaltCantModifyInternal ()
204 Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", salt);
205 Assert.AreEqual (salt, pkcs5.Salt, "Salt");
206 byte[] modSalt = (byte[]) salt.Clone ();
208 Assert.IsFalse ((BitConverter.ToString (pkcs5.Salt) == BitConverter.ToString (modSalt)), "Can't modify internal salt");
212 [ExpectedException (typeof (ArgumentNullException))]
213 public void SaltNull ()
215 Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", salt);
220 [ExpectedException (typeof (ArgumentException))]
221 public void SaltTooSmall ()
223 Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", salt);
224 byte[] smallSalt = { 0x01, 0x02, 0x03, 0x04, 0x05 };
225 pkcs5.Salt = smallSalt;
229 [ExpectedException (typeof (ArgumentOutOfRangeException))]
230 public void GetBytesZero ()
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");
239 [ExpectedException (typeof (ArgumentOutOfRangeException))]
240 public void GetBytesNegative ()
242 Rfc2898DeriveBytes pkcs5 = new Rfc2898DeriveBytes ("password", salt, 5);
243 byte[] key = pkcs5.GetBytes (Int32.MinValue);
247 public void GetBytes_Endian ()
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");
259 public void RFC3211_TC1 ()
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");
268 public void RFC3211_TC2 ()
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");
277 public void RFC3211_TC2_TwoBlocks ()
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");
286 public void RFC3211_TC2_Splitted_OneBlock ()
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");
298 public void RFC3211_TC2_Splitted_TwoBlocks ()
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");
310 public void RFC3211_TC2_Reset ()
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");
317 byte[] key2 = pkcs5.GetBytes (8);
318 Assert.AreEqual (expected, key2, "RFC3211_TC2_part2");
321 private void CompareBuffers (byte [] big, byte [] a, byte [] b)
324 for (int i = 0; i < a.Length; i++) {
325 Assert.AreEqual (big [n], a [i], n.ToString ());
328 for (int i = 0; i < b.Length; i++) {
329 Assert.AreEqual (big [n], b [i], n.ToString ());
335 public void SplitCalls_Reset ()
337 Rfc2898DeriveBytes keygen = new Rfc2898DeriveBytes ("password", salt, 12345);
338 byte [] big = keygen.GetBytes (48);
341 byte [] a = keygen.GetBytes (16);
342 byte [] b = keygen.GetBytes (32);
344 CompareBuffers (big, a, b);
348 public void SplitCalls_TwoInstances ()
350 Rfc2898DeriveBytes keygen1 = new Rfc2898DeriveBytes ("password", salt, 12345);
351 byte [] big = keygen1.GetBytes (48);
353 Rfc2898DeriveBytes keygen2 = new Rfc2898DeriveBytes ("password", salt, 12345);
354 byte [] a = keygen2.GetBytes (16);
355 byte [] b = keygen2.GetBytes (32);
357 CompareBuffers (big, a, b);
361 public void MultipleCalls_DoesntOverrunBuffer ()
363 Rfc2898DeriveBytes keygen = new Rfc2898DeriveBytes("Password", new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 });