#region Copyright 2010-2014 by Roger Knapp, Licensed under the Apache License, Version 2.0
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.IO;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using System.Security;
using System.Runtime.InteropServices;
namespace CSharpTest.Net.Crypto
{
///
/// Stores an encrypted version of the supplied password in memory so that it
/// can be provided as clear-text to external systems.
///
public class Password : PasswordKey, IEquatable
{
/// Returns the encoding used for passwords
public static Encoding Encoding { get { return Encoding.BigEndianUnicode; } }
readonly byte[] _passphrase;
/// Creates the password from the given bytes and salt
public Password(bool clear, byte[] bytes)
: base(false, Check.ArraySize(bytes, 1, int.MaxValue))
{
// _passkey = LocalHostKey.CurrentUser.WithSalt(new Salt());
_passphrase = Passkey.Encrypt(bytes);
if (clear) Array.Clear(bytes, 0, bytes.Length);
}
/// Creates the password from the given data and salt
public Password(string data)
: this(true, Password.Encoding.GetBytes(data))
{ }
/// Creates the password from the given data and salt
public Password(SecureString data)
: this(true, SecureStringUtils.ToByteArray(data, Password.Encoding))
{ }
///
/// Allows overriding the encryption/decryption support for the in-memory password
///
protected virtual IEncryptDecrypt Passkey { get { return RtlProcessKey.Encryptor; } }
/// Removes the memory representation of this password and key
[System.Diagnostics.DebuggerNonUserCode]
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
Array.Clear(_passphrase, 0, _passphrase.Length);
}
/// Returns a salted hash for the password
public PasswordHash CreateHash() { return CreateHash(new Salt()); }
/// Returns a salted hash for the password
public PasswordHash CreateHash(Salt salt)
{
return new PasswordHash(this, salt);
}
/// Returns a stream from which the password can be read
public Stream ReadBytes()
{ return Passkey.Decrypt(new MemoryStream(_passphrase, 0, _passphrase.Length, false, false)); }
/// Returns a stream from which the password can be read
public TextReader ReadText()
{ return new UnicodeReader(ReadBytes(), Password.Encoding); }
/// Returns a System.Security.SecureString from the password
public SecureString ToSecureString()
{
using (Stream io = ReadBytes())
return SecureStringUtils.Create(io, Password.Encoding);
}
/// Returns true if the other object is equal to this one
public override bool Equals(object obj)
{
return Comparer.Equals(this, obj as Password);
}
/// Returns true if the other object is equal to this one
public bool Equals(Password other)
{
if (((object)other) == null) return false;
using (Stream a = ReadBytes())
using (Stream b = other.ReadBytes())
{
int nexta = 0, nextb = 0;
while (nexta != -1 && nextb != -1 && nexta == nextb)
{
nexta = a.ReadByte();
nextb = b.ReadByte();
}
return (nexta == nextb);
}
}
/// Extracts the correct hash code
public override int GetHashCode()
{
using (Stream a = ReadBytes())
return Hash.MD5(a).GetHashCode();
}
/// Compares the two objects for non-reference equality
public static bool Equals(Password x, Password y)
{
return Comparer.Equals(x, y);
}
/// Compares the two objects for non-reference equality
public static int GetHashCode(Password obj)
{
return Comparer.GetHashCode(obj);
}
/// Compares the two objects for non-reference equality
public static bool operator ==(Password x, Password y)
{
return Comparer.Equals(x, y);
}
/// Compares the two objects for non-reference equality
public static bool operator !=(Password x, Password y)
{
return !Comparer.Equals(x, y);
}
/// return a non-reference equality comparer for this class
public static readonly EqualityComparer Comparer = new EqualityComparer();
/// Implements the equality comparer
[System.Diagnostics.DebuggerNonUserCode]
public sealed class EqualityComparer : EqualityComparer, IEqualityComparer
{
/// Compares the two objects for non-reference equality
public override bool Equals(Password x, Password y)
{
if (((object)x) == null) return ((object)y) == null;
if (((object)y) == null) return false;
return x.Equals(y);
}
/// Extracts the correct hash code
public override int GetHashCode(Password obj)
{
return ((object)obj) == null ? 0 : obj.GetHashCode();
}
}
}
}