2 // PasswordDeriveBytes.cs: Handles PKCS#5 key derivation using password
5 // Sebastien Pouliot (sebastien@ximian.com)
7 // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
8 // Copyright (C) 2004-2007 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.
30 using System
.Globalization
;
31 using System
.Runtime
.InteropServices
;
34 namespace System
.Security
.Cryptography
{
37 // a. PKCS #5 - Password-Based Cryptography Standard
38 // http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html
39 // b. IETF RFC2898: PKCS #5: Password-Based Cryptography Specification Version 2.0
40 // http://www.rfc-editor.org/rfc/rfc2898.txt
43 public class PasswordDeriveBytes
: DeriveBytes
{
45 private string HashNameValue
;
46 private byte[] SaltValue
;
47 private int IterationsValue
;
49 private HashAlgorithm hash
;
51 private byte[] password
;
52 private byte[] initial
;
53 private byte[] output
;
55 private int hashnumber
;
57 public PasswordDeriveBytes (string strPassword
, byte[] rgbSalt
)
59 Prepare (strPassword
, rgbSalt
, "SHA1", 100);
62 public PasswordDeriveBytes (string strPassword
, byte[] rgbSalt
, CspParameters cspParams
)
64 Prepare (strPassword
, rgbSalt
, "SHA1", 100);
65 if (cspParams
!= null) {
66 throw new NotSupportedException (
67 Locale
.GetText ("CspParameters not supported by Mono for PasswordDeriveBytes."));
71 public PasswordDeriveBytes (string strPassword
, byte[] rgbSalt
, string strHashName
, int iterations
)
73 Prepare (strPassword
, rgbSalt
, strHashName
, iterations
);
76 public PasswordDeriveBytes (string strPassword
, byte[] rgbSalt
, string strHashName
, int iterations
, CspParameters cspParams
)
78 Prepare (strPassword
, rgbSalt
, strHashName
, iterations
);
79 if (cspParams
!= null) {
80 throw new NotSupportedException (
81 Locale
.GetText ("CspParameters not supported by Mono for PasswordDeriveBytes."));
85 public PasswordDeriveBytes (byte[] password
, byte[] salt
)
87 Prepare (password
, salt
, "SHA1", 100);
90 public PasswordDeriveBytes (byte[] password
, byte[] salt
, CspParameters cspParams
)
92 Prepare (password
, salt
, "SHA1", 100);
93 if (cspParams
!= null) {
94 throw new NotSupportedException (
95 Locale
.GetText ("CspParameters not supported by Mono for PasswordDeriveBytes."));
99 public PasswordDeriveBytes (byte[] password
, byte[] salt
, string hashName
, int iterations
)
101 Prepare (password
, salt
, hashName
, iterations
);
104 public PasswordDeriveBytes (byte[] password
, byte[] salt
, string hashName
, int iterations
, CspParameters cspParams
)
106 Prepare (password
, salt
, hashName
, iterations
);
107 if (cspParams
!= null) {
108 throw new NotSupportedException (
109 Locale
.GetText ("CspParameters not supported by Mono for PasswordDeriveBytes."));
113 ~
PasswordDeriveBytes ()
116 if (initial
!= null) {
117 Array
.Clear (initial
, 0, initial
.Length
);
120 // zeroize temporary password storage
121 Array
.Clear (password
, 0, password
.Length
);
124 private void Prepare (string strPassword
, byte[] rgbSalt
, string strHashName
, int iterations
)
126 if (strPassword
== null)
127 throw new ArgumentNullException ("strPassword");
129 byte[] pwd
= Encoding
.UTF8
.GetBytes (strPassword
);
130 Prepare (pwd
, rgbSalt
, strHashName
, iterations
);
131 Array
.Clear (pwd
, 0, pwd
.Length
);
134 private void Prepare (byte[] password
, byte[] rgbSalt
, string strHashName
, int iterations
)
136 if (password
== null)
137 throw new ArgumentNullException ("password");
139 this.password
= (byte[]) password
.Clone ();
143 HashName
= strHashName
;
144 IterationCount
= iterations
;
147 public string HashName
{
148 get { return HashNameValue; }
151 throw new ArgumentNullException ("HashName");
153 throw new CryptographicException (
154 Locale
.GetText ("Can't change this property at this stage"));
156 HashNameValue
= value;
160 public int IterationCount
{
161 get { return IterationsValue; }
164 throw new ArgumentOutOfRangeException ("> 0", "IterationCount");
166 throw new CryptographicException (
167 Locale
.GetText ("Can't change this property at this stage"));
169 IterationsValue
= value;
175 if (SaltValue
== null)
177 return (byte[]) SaltValue
.Clone ();
181 throw new CryptographicException (
182 Locale
.GetText ("Can't change this property at this stage"));
185 SaltValue
= (byte[]) value.Clone ();
191 public byte[] CryptDeriveKey (string algname
, string alghashname
, int keySize
, byte[] rgbIV
)
194 throw new CryptographicException (
195 Locale
.GetText ("Key Size can't be greater than 128 bits"));
197 throw new NotSupportedException (
198 Locale
.GetText ("CspParameters not supported by Mono"));
201 // note: Key is returned - we can't zeroize it ourselve :-(
202 [Obsolete ("see Rfc2898DeriveBytes for PKCS#5 v2 support")]
203 #pragma warning disable 809
204 public override byte[] GetBytes (int cb
)
206 #pragma warning restore 809
209 throw new IndexOutOfRangeException ("cb");
212 // it's now impossible to change the HashName, Salt
213 // and IterationCount
218 byte[] result
= new byte [cb
];
220 // the initial hash (in reset) + at least one iteration
221 int iter
= Math
.Max (1, IterationsValue
- 1);
223 // start with the PKCS5 key
224 if (output
== null) {
225 // calculate the PKCS5 key
228 // generate new key material
229 for (int i
= 0; i
< iter
- 1; i
++)
230 output
= hash
.ComputeHash (output
);
234 byte[] output2
= null;
235 if (hashnumber
== 0) {
236 // last iteration on output
237 output2
= hash
.ComputeHash (output
);
239 else if (hashnumber
< 1000) {
240 string n
= Convert
.ToString (hashnumber
);
241 output2
= new byte [output
.Length
+ n
.Length
];
242 for (int j
=0; j
< n
.Length
; j
++)
243 output2
[j
] = (byte)(n
[j
]);
244 Buffer
.BlockCopy (output
, 0, output2
, n
.Length
, output
.Length
);
245 // don't update output
246 output2
= hash
.ComputeHash (output2
);
249 throw new CryptographicException (
250 Locale
.GetText ("too long"));
253 int rem
= output2
.Length
- position
;
254 int l
= Math
.Min (cb
- cpos
, rem
);
255 Buffer
.BlockCopy (output2
, position
, result
, cpos
, l
);
258 while (position
>= output2
.Length
) {
259 position
-= output2
.Length
;
266 public override void Reset ()
272 hash
= HashAlgorithm
.Create (HashNameValue
);
273 if (SaltValue
!= null) {
274 hash
.TransformBlock (password
, 0, password
.Length
, password
, 0);
275 hash
.TransformFinalBlock (SaltValue
, 0, SaltValue
.Length
);
279 initial
= hash
.ComputeHash (password
);