3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // <OWNER>Microsoft</OWNER>
10 // PasswordDerivedBytes.cs
13 namespace System.Security.Cryptography {
15 using System.Runtime.CompilerServices;
16 using System.Runtime.InteropServices;
17 using System.Runtime.Versioning;
18 using System.Security.Cryptography.X509Certificates;
20 using System.Globalization;
21 using System.Diagnostics.Contracts;
23 [System.Runtime.InteropServices.ComVisible(true)]
24 public class PasswordDeriveBytes : DeriveBytes {
25 private int _extraCount;
27 private int _iterations;
28 private byte[] _baseValue;
29 private byte[] _extra;
31 private string _hashName;
32 private byte[] _password;
33 private HashAlgorithm _hash;
35 private CspParameters _cspParams;
37 [System.Security.SecurityCritical] // auto-generated
38 private SafeProvHandle _safeProvHandle = null;
39 private SafeProvHandle ProvHandle {
40 [System.Security.SecurityCritical] // auto-generated
42 if (_safeProvHandle == null) {
44 if (_safeProvHandle == null) {
45 SafeProvHandle safeProvHandle = Utils.AcquireProvHandle(_cspParams);
46 System.Threading.Thread.MemoryBarrier();
47 _safeProvHandle = safeProvHandle;
51 return _safeProvHandle;
56 // public constructors
59 public PasswordDeriveBytes (String strPassword, byte[] rgbSalt) : this (strPassword, rgbSalt, new CspParameters()) {}
61 public PasswordDeriveBytes (byte[] password, byte[] salt) : this (password, salt, new CspParameters()) {}
63 public PasswordDeriveBytes (string strPassword, byte[] rgbSalt, string strHashName, int iterations) :
64 this (strPassword, rgbSalt, strHashName, iterations, new CspParameters()) {}
66 public PasswordDeriveBytes (byte[] password, byte[] salt, string hashName, int iterations) :
67 this (password, salt, hashName, iterations, new CspParameters()) {}
69 public PasswordDeriveBytes (string strPassword, byte[] rgbSalt, CspParameters cspParams) :
70 this (strPassword, rgbSalt, "SHA1", 100, cspParams) {}
72 public PasswordDeriveBytes (byte[] password, byte[] salt, CspParameters cspParams) :
73 this (password, salt, "SHA1", 100, cspParams) {}
75 public PasswordDeriveBytes (string strPassword, byte[] rgbSalt, String strHashName, int iterations, CspParameters cspParams) :
76 this ((new UTF8Encoding(false)).GetBytes(strPassword), rgbSalt, strHashName, iterations, cspParams) {}
78 // This method needs to be safe critical, because in debug builds the C# compiler will include null
79 // initialization of the _safeProvHandle field in the method. Since SafeProvHandle is critical, a
80 // transparent reference triggers an error using PasswordDeriveBytes.
81 [SecuritySafeCritical]
82 public PasswordDeriveBytes (byte[] password, byte[] salt, String hashName, int iterations, CspParameters cspParams) {
83 this.IterationCount = iterations;
85 this.HashName = hashName;
88 _cspParams = cspParams;
96 public String HashName {
97 get { return _hashName; }
99 if (_baseValue != null)
100 throw new CryptographicException(Environment.GetResourceString("Cryptography_PasswordDerivedBytes_ValuesFixed", "HashName"));
102 _hash = (HashAlgorithm) CryptoConfig.CreateFromName(_hashName);
106 public int IterationCount {
107 get { return _iterations; }
110 throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
111 Contract.EndContractBlock();
112 if (_baseValue != null)
113 throw new CryptographicException(Environment.GetResourceString("Cryptography_PasswordDerivedBytes_ValuesFixed", "IterationCount"));
122 return (byte[]) _salt.Clone();
125 if (_baseValue != null)
126 throw new CryptographicException(Environment.GetResourceString("Cryptography_PasswordDerivedBytes_ValuesFixed", "Salt"));
130 _salt = (byte[]) value.Clone();
138 [System.Security.SecuritySafeCritical] // auto-generated
139 [Obsolete("Rfc2898DeriveBytes replaces PasswordDeriveBytes for deriving key material from a password and is preferred in new applications.")]
140 // disable csharp compiler warning #0809: obsolete member overrides non-obsolete member
141 #pragma warning disable 0809
142 public override byte[] GetBytes(int cb) {
145 throw new IndexOutOfRangeException ("cb");
150 byte[] rgbOut = new byte[cb];
152 if (_baseValue == null) {
155 else if (_extra != null) {
156 ib = _extra.Length - _extraCount;
158 Buffer.InternalBlockCopy(_extra, _extraCount, rgbOut, 0, cb);
168 // Note: The second parameter should really be _extraCount instead
169 // However, changing this would constitute a breaking change compared
170 // to what has shipped in V1.x.
173 Buffer.InternalBlockCopy(_extra, ib, rgbOut, 0, ib);
178 rgb = ComputeBytes(cb-ib);
179 Buffer.InternalBlockCopy(rgb, 0, rgbOut, ib, cb-ib);
180 if (rgb.Length + ib > cb) {
186 #pragma warning restore 0809
188 public override void Reset() {
194 protected override void Dispose(bool disposing) {
195 base.Dispose(disposing);
202 if (_baseValue != null) {
203 Array.Clear(_baseValue, 0, _baseValue.Length);
205 if (_extra != null) {
206 Array.Clear(_extra, 0, _extra.Length);
208 if (_password != null) {
209 Array.Clear(_password, 0, _password.Length);
212 Array.Clear(_salt, 0, _salt.Length);
217 [System.Security.SecuritySafeCritical] // auto-generated
218 public byte[] CryptDeriveKey(string algname, string alghashname, int keySize, byte[] rgbIV)
221 throw new CryptographicException(Environment.GetResourceString("Cryptography_InvalidKeySize"));
223 throw new NotSupportedException ("CspParameters are not supported by Mono");
225 int algidhash = X509Utils.NameOrOidToAlgId(alghashname, OidGroup.HashAlgorithm);
227 throw new CryptographicException(Environment.GetResourceString("Cryptography_PasswordDerivedBytes_InvalidAlgorithm"));
228 int algid = X509Utils.NameOrOidToAlgId(algname, OidGroup.AllGroups);
230 throw new CryptographicException(Environment.GetResourceString("Cryptography_PasswordDerivedBytes_InvalidAlgorithm"));
232 // Validate the rgbIV array
234 throw new CryptographicException(Environment.GetResourceString("Cryptography_PasswordDerivedBytes_InvalidIV"));
237 DeriveKey(ProvHandle, algid, algidhash,
238 _password, _password.Length, keySize << 16, rgbIV, rgbIV.Length,
239 JitHelpers.GetObjectHandleOnStack(ref key));
248 [System.Security.SecurityCritical] // auto-generated
249 [ResourceExposure(ResourceScope.None)]
250 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
251 private static extern void DeriveKey(SafeProvHandle hProv, int algid, int algidHash,
252 byte[] password, int cbPassword, int dwFlags, byte[] IV, int cbIV,
253 ObjectHandleOnStack retKey);
255 private byte[] ComputeBaseValue() {
257 _hash.TransformBlock(_password, 0, _password.Length, _password, 0);
259 _hash.TransformBlock(_salt, 0, _salt.Length, _salt, 0);
260 _hash.TransformFinalBlock(EmptyArray<Byte>.Value, 0, 0);
261 _baseValue = _hash.Hash;
264 for (int i=1; i<(_iterations-1); i++) {
265 _hash.ComputeHash(_baseValue);
266 _baseValue = _hash.Hash;
271 [System.Security.SecurityCritical] // auto-generated
272 private byte[] ComputeBytes(int cb) {
278 cbHash = _hash.HashSize / 8;
279 rgb = new byte[((cb+cbHash-1)/cbHash)*cbHash];
281 using (CryptoStream cs = new CryptoStream(Stream.Null, _hash, CryptoStreamMode.Write)) {
283 cs.Write(_baseValue, 0, _baseValue.Length);
287 Buffer.InternalBlockCopy(_hash.Hash, 0, rgb, ib, cbHash);
292 using (CryptoStream cs = new CryptoStream(Stream.Null, _hash, CryptoStreamMode.Write)) {
294 cs.Write(_baseValue, 0, _baseValue.Length);
298 Buffer.InternalBlockCopy(_hash.Hash, 0, rgb, ib, cbHash);
305 void HashPrefix(CryptoStream cs) {
307 byte[] rgb = {(byte)'0', (byte)'0', (byte)'0'};
310 throw new CryptographicException(Environment.GetResourceString("Cryptography_PasswordDerivedBytes_TooManyBytes"));
312 if (_prefix >= 100) {
313 rgb[0] += (byte) (_prefix /100);
317 rgb[cb] += (byte) ((_prefix % 100) / 10);
321 rgb[cb] += (byte) (_prefix % 10);
323 cs.Write(rgb, 0, cb);