Created
April 28, 2018 12:25
-
-
Save floko84/86d2c8c6ea60f647d5b2ab1e17024056 to your computer and use it in GitHub Desktop.
C# password-based encryption helper class.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.IO; | |
using System.Linq; | |
using System.Security.Cryptography; | |
public class PasswordCryptoServiceProvider : IDisposable | |
{ | |
protected const string Base58Chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; | |
private readonly SymmetricAlgorithm algorithm; | |
private bool disposed = false; | |
public PasswordCryptoServiceProvider() | |
: this("AES") | |
{ } | |
public PasswordCryptoServiceProvider(string alorithmName) | |
: this(SymmetricAlgorithm.Create(alorithmName)) | |
{ } | |
public PasswordCryptoServiceProvider(SymmetricAlgorithm algorithm) | |
{ | |
if (null == algorithm) | |
{ | |
throw new ArgumentNullException(nameof(algorithm)); | |
} | |
this.algorithm = algorithm; | |
this.GenerateKey(); | |
} | |
public string Key { get; set; } | |
public byte[] Encrypt(byte[] data) | |
{ | |
if (this.disposed) | |
{ | |
throw new ObjectDisposedException(this.GetType().FullName); | |
} | |
// generate a new IV each time the Encrypt is called | |
this.algorithm.GenerateIV(); | |
var iv = this.algorithm.IV; | |
using (var rgb = new Rfc2898DeriveBytes(this.Key, iv)) | |
{ | |
this.algorithm.Key = rgb.GetBytes(this.algorithm.KeySize / 8); | |
using (var ms = new MemoryStream()) | |
{ | |
using (var cs = new CryptoStream(ms, this.algorithm.CreateEncryptor(), CryptoStreamMode.Write)) | |
{ | |
cs.Write(data, 0, data.Length); | |
cs.FlushFinalBlock(); | |
} | |
var encryptedData = ms.ToArray(); | |
return iv.Concat(encryptedData).ToArray(); | |
} | |
} | |
} | |
public byte[] Decrypt(byte[] encryptedData) | |
{ | |
if (this.disposed) | |
{ | |
throw new ObjectDisposedException(this.GetType().FullName); | |
} | |
// extract parts of the encoded data | |
var iv = new byte[this.algorithm.BlockSize / 8]; | |
var data = new byte[encryptedData.Length - iv.Length]; | |
Array.Copy(encryptedData, 0, iv, 0, iv.Length); | |
Array.Copy(encryptedData, iv.Length, data, 0, data.Length); | |
using (var rgb = new Rfc2898DeriveBytes(this.Key, iv)) | |
{ | |
this.algorithm.Key = rgb.GetBytes(this.algorithm.KeySize / 8); | |
this.algorithm.IV = iv; | |
using (var ms = new MemoryStream()) | |
{ | |
using (var cs = new CryptoStream(ms, this.algorithm.CreateDecryptor(), CryptoStreamMode.Write)) | |
{ | |
cs.Write(data, 0, data.Length); | |
cs.FlushFinalBlock(); | |
} | |
return ms.ToArray(); | |
} | |
} | |
} | |
public void GenerateKey() | |
{ | |
this.GenerateKey(this.algorithm.KeySize / 8); | |
} | |
public void GenerateKey(int length) | |
{ | |
var base58Chars = PasswordCryptoServiceProvider.Base58Chars.ToCharArray(); | |
using (var rng = new RNGCryptoServiceProvider()) | |
{ | |
var seed = new byte[4]; | |
rng.GetBytes(seed); | |
var rnd = new Random(BitConverter.ToInt32(seed, 0)); | |
this.Key = new string(Enumerable.Range(0, length).Select(x => base58Chars[rnd.Next(base58Chars.Length)]).ToArray()); | |
} | |
} | |
public void Dispose() | |
{ | |
this.Dispose(true); | |
GC.SuppressFinalize(this); | |
} | |
protected virtual void Dispose(bool disposing) | |
{ | |
if (this.disposed) | |
{ | |
return; | |
} | |
if (disposing) | |
{ | |
this.algorithm.Dispose(); | |
} | |
this.disposed = true; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment