208 lines
7.4 KiB
C#
208 lines
7.4 KiB
C#
|
#if !DISABLE_ENCRYPTION
|
|||
|
using System.IO;
|
|||
|
using System.Security.Cryptography;
|
|||
|
#if NETFX_CORE
|
|||
|
using Windows.Security.Cryptography;
|
|||
|
using Windows.Security.Cryptography.Core;
|
|||
|
using Windows.Storage.Streams;
|
|||
|
using System.Runtime.InteropServices.WindowsRuntime;
|
|||
|
#endif
|
|||
|
|
|||
|
namespace ES3Internal
|
|||
|
{
|
|||
|
public static class ES3Hash
|
|||
|
{
|
|||
|
#if NETFX_CORE
|
|||
|
public static string SHA1Hash(string input)
|
|||
|
{
|
|||
|
return System.Text.Encoding.UTF8.GetString(UnityEngine.Windows.Crypto.ComputeSHA1Hash(System.Text.Encoding.UTF8.GetBytes(input)));
|
|||
|
}
|
|||
|
#else
|
|||
|
public static string SHA1Hash(string input)
|
|||
|
{
|
|||
|
using (SHA1Managed sha1 = new SHA1Managed())
|
|||
|
return System.Text.Encoding.UTF8.GetString(sha1.ComputeHash(System.Text.Encoding.UTF8.GetBytes(input)));
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
public abstract class EncryptionAlgorithm
|
|||
|
{
|
|||
|
public abstract byte[] Encrypt(byte[] bytes, string password, int bufferSize);
|
|||
|
public abstract byte[] Decrypt(byte[] bytes, string password, int bufferSize);
|
|||
|
public abstract void Encrypt(Stream input, Stream output, string password, int bufferSize);
|
|||
|
public abstract void Decrypt(Stream input, Stream output, string password, int bufferSize);
|
|||
|
|
|||
|
protected static void CopyStream(Stream input, Stream output, int bufferSize)
|
|||
|
{
|
|||
|
byte[] buffer = new byte[bufferSize];
|
|||
|
int read;
|
|||
|
while ((read = input.Read(buffer, 0, bufferSize)) > 0)
|
|||
|
output.Write(buffer, 0, read);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public class AESEncryptionAlgorithm : EncryptionAlgorithm
|
|||
|
{
|
|||
|
private const int ivSize = 16;
|
|||
|
private const int keySize = 16;
|
|||
|
private const int pwIterations = 100;
|
|||
|
|
|||
|
public override byte[] Encrypt(byte[] bytes, string password, int bufferSize)
|
|||
|
{
|
|||
|
using (var input = new MemoryStream(bytes))
|
|||
|
{
|
|||
|
using (var output = new MemoryStream())
|
|||
|
{
|
|||
|
Encrypt(input, output, password, bufferSize);
|
|||
|
return output.ToArray();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public override byte[] Decrypt(byte[] bytes, string password, int bufferSize)
|
|||
|
{
|
|||
|
using (var input = new MemoryStream(bytes))
|
|||
|
{
|
|||
|
using (var output = new MemoryStream())
|
|||
|
{
|
|||
|
Decrypt(input, output, password, bufferSize);
|
|||
|
return output.ToArray();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public override void Encrypt(Stream input, Stream output, string password, int bufferSize)
|
|||
|
{
|
|||
|
input.Position = 0;
|
|||
|
|
|||
|
#if NETFX_CORE
|
|||
|
// Generate an IV and write it to the output.
|
|||
|
var iv = CryptographicBuffer.GenerateRandom(ivSize);
|
|||
|
output.Write(iv.ToArray(), 0, ivSize);
|
|||
|
|
|||
|
var pwBuffer = CryptographicBuffer.ConvertStringToBinary(password, BinaryStringEncoding.Utf8);
|
|||
|
var keyDerivationProvider = KeyDerivationAlgorithmProvider.OpenAlgorithm("PBKDF2_SHA1");
|
|||
|
KeyDerivationParameters pbkdf2Parms = KeyDerivationParameters.BuildForPbkdf2(iv, pwIterations);
|
|||
|
// Create a key based on original key and derivation parmaters
|
|||
|
CryptographicKey keyOriginal = keyDerivationProvider.CreateKey(pwBuffer);
|
|||
|
IBuffer keyMaterial = CryptographicEngine.DeriveKeyMaterial(keyOriginal, pbkdf2Parms, keySize);
|
|||
|
|
|||
|
var provider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbcPkcs7);
|
|||
|
var key = provider.CreateSymmetricKey(keyMaterial);
|
|||
|
|
|||
|
// Get the input stream as an IBuffer.
|
|||
|
IBuffer msg;
|
|||
|
using(var ms = new MemoryStream())
|
|||
|
{
|
|||
|
input.CopyTo(ms);
|
|||
|
msg = ms.ToArray().AsBuffer();
|
|||
|
}
|
|||
|
|
|||
|
var buffEncrypt = CryptographicEngine.Encrypt(key, msg, iv);
|
|||
|
|
|||
|
|
|||
|
output.Write(buffEncrypt.ToArray(), 0, (int)buffEncrypt.Length);
|
|||
|
output.Dispose();
|
|||
|
#else
|
|||
|
using (var alg = Aes.Create())
|
|||
|
{
|
|||
|
alg.Mode = CipherMode.CBC;
|
|||
|
alg.Padding = PaddingMode.PKCS7;
|
|||
|
alg.GenerateIV();
|
|||
|
var key = new Rfc2898DeriveBytes(password, alg.IV, pwIterations);
|
|||
|
alg.Key = key.GetBytes(keySize);
|
|||
|
// Write the IV to the output stream.
|
|||
|
output.Write(alg.IV, 0, ivSize);
|
|||
|
using(var encryptor = alg.CreateEncryptor())
|
|||
|
using(var cs = new CryptoStream(output, encryptor, CryptoStreamMode.Write))
|
|||
|
CopyStream(input, cs, bufferSize);
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
public override void Decrypt(Stream input, Stream output, string password, int bufferSize)
|
|||
|
{
|
|||
|
#if NETFX_CORE
|
|||
|
var thisIV = new byte[ivSize];
|
|||
|
input.Read(thisIV, 0, ivSize);
|
|||
|
var iv = thisIV.AsBuffer();
|
|||
|
|
|||
|
var pwBuffer = CryptographicBuffer.ConvertStringToBinary(password, BinaryStringEncoding.Utf8);
|
|||
|
|
|||
|
var keyDerivationProvider = KeyDerivationAlgorithmProvider.OpenAlgorithm("PBKDF2_SHA1");
|
|||
|
KeyDerivationParameters pbkdf2Parms = KeyDerivationParameters.BuildForPbkdf2(iv, pwIterations);
|
|||
|
// Create a key based on original key and derivation parameters.
|
|||
|
CryptographicKey keyOriginal = keyDerivationProvider.CreateKey(pwBuffer);
|
|||
|
IBuffer keyMaterial = CryptographicEngine.DeriveKeyMaterial(keyOriginal, pbkdf2Parms, keySize);
|
|||
|
|
|||
|
var provider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbcPkcs7);
|
|||
|
var key = provider.CreateSymmetricKey(keyMaterial);
|
|||
|
|
|||
|
// Get the input stream as an IBuffer.
|
|||
|
IBuffer msg;
|
|||
|
using(var ms = new MemoryStream())
|
|||
|
{
|
|||
|
input.CopyTo(ms);
|
|||
|
msg = ms.ToArray().AsBuffer();
|
|||
|
}
|
|||
|
|
|||
|
var buffDecrypt = CryptographicEngine.Decrypt(key, msg, iv);
|
|||
|
|
|||
|
output.Write(buffDecrypt.ToArray(), 0, (int)buffDecrypt.Length);
|
|||
|
#else
|
|||
|
using (var alg = Aes.Create())
|
|||
|
{
|
|||
|
var thisIV = new byte[ivSize];
|
|||
|
input.Read(thisIV, 0, ivSize);
|
|||
|
alg.IV = thisIV;
|
|||
|
|
|||
|
var key = new Rfc2898DeriveBytes(password, alg.IV, pwIterations);
|
|||
|
alg.Key = key.GetBytes(keySize);
|
|||
|
|
|||
|
using(var decryptor = alg.CreateDecryptor())
|
|||
|
using(var cryptoStream = new CryptoStream(input, decryptor, CryptoStreamMode.Read))
|
|||
|
CopyStream(cryptoStream, output, bufferSize);
|
|||
|
|
|||
|
}
|
|||
|
#endif
|
|||
|
output.Position = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public class UnbufferedCryptoStream : MemoryStream
|
|||
|
{
|
|||
|
private readonly Stream stream;
|
|||
|
private readonly bool isReadStream;
|
|||
|
private string password;
|
|||
|
private int bufferSize;
|
|||
|
private EncryptionAlgorithm alg;
|
|||
|
private bool disposed = false;
|
|||
|
|
|||
|
public UnbufferedCryptoStream(Stream stream, bool isReadStream, string password, int bufferSize, EncryptionAlgorithm alg) : base()
|
|||
|
{
|
|||
|
this.stream = stream;
|
|||
|
this.isReadStream = isReadStream;
|
|||
|
this.password = password;
|
|||
|
this.bufferSize = bufferSize;
|
|||
|
this.alg = alg;
|
|||
|
|
|||
|
|
|||
|
if (isReadStream)
|
|||
|
alg.Decrypt(stream, this, password, bufferSize);
|
|||
|
}
|
|||
|
|
|||
|
protected override void Dispose(bool disposing)
|
|||
|
{
|
|||
|
if (disposed)
|
|||
|
return;
|
|||
|
disposed = true;
|
|||
|
|
|||
|
if (!isReadStream)
|
|||
|
alg.Encrypt(this, stream, password, bufferSize);
|
|||
|
stream.Dispose();
|
|||
|
base.Dispose(disposing);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|