#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.Collections.Generic; using System.Security.Cryptography; using System.IO; using System.Text; using CSharpTest.Net.Bases; namespace CSharpTest.Net.Crypto { /// /// Represents a random sequence of bytes used to combine with hash and encryption /// values to provide an extra level of security. /// public class Salt : Equatable { /// Size of a salt-key in bits public enum Size : int { /// 64-bit, 8-byte salt value b64 = 64, /// 128-bit, 16-byte salt value b128 = 128, /// 256-bit, 32-byte salt value b256 = 256, /// 512-bit, 64-byte salt value b512 = 512, /// 1024-bit, 128-byte salt value b1024 = 1024, } /// The size of the salt if unspecified public const Size DefaultSize = Size.b256; readonly static RandomNumberGenerator _rng = new RNGCryptoServiceProvider(); readonly byte[] _salt; /// Creates a new Salt of DefaultSize public Salt() : this(CreateBytes(DefaultSize), false) { } /// Creates a new Salt of the specified size public Salt(Size szBits) : this(CreateBytes(szBits), false) { } /// Creates a new Salt using the specified bytes internal Salt(byte[] salt, bool copy) { _salt = !copy ? salt : (byte[])salt.Clone(); } /// Creates salt from the provided bytes or a hash of the bytes /// An array of random bytes of 8, 16, 32, or 64 bytes long public static Salt FromBytes(byte[] bytes) { int len = Check.NotEmpty(bytes).Length; if (len != 8 && len != 16 && len != 32 && len != 64 && len != 128) bytes = SHA256.Create().ComputeHash(bytes); return new Salt(bytes, true); } /// Returns the size of the salt in bits public Size BitSize { get { return (Size)(_salt.Length * 8); } } /// returns the total length of the salt in bytes public int Length { get { return _salt.Length; } } /// Returns the salt as an array of bytes public byte[] ToArray() { return (byte[])_salt.Clone(); } /// Returns the base64 encoding of the salt public override string ToString() { return Convert.ToBase64String(_salt); } /// /// Recreates a salt value from a string /// public static Salt FromString(string input) { return new Salt(Convert.FromBase64String(input), false); } /// Copy the salt to the specified offset in the byte array public void CopyTo(byte[] array, int offset) { _salt.CopyTo(array, offset); } /// Returns the salt as a stream public Stream ToStream() { return new MemoryStream(_salt, 0, _salt.Length, false, false); } /// Returns the salt combined with a copy of the speicified data public SaltedData GetData(byte[] data) { return new SaltedData(this, data); } /// Returns the salt combined with a copy of the speicified data as a stream public SaltedData GetData(Stream data) { return new SaltedData(this, data); } /// Creates n bytes of data usable as a salt public static byte[] CreateBytes(Size szBits) { byte[] salt = new byte[(int)szBits / 8]; CreateBytes(salt); return salt; } /// Creates n bytes of data usable as a salt public static void CreateBytes(byte[] bits) { _rng.GetBytes(bits); } /// Returns true if the two Salts are using the same data public override bool Equals(Salt other) { return ((object)other) != null && this.Length == other.Length && BinaryComparer.Equals(_salt, other._salt); } /// /// Returns the hash code of the current salt /// protected override int HashCode { get { return BinaryComparer.GetHashCode(_salt); } } } }