#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(); } } } }