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