IndieGame/client/Assets/Plugins/Easy Save 3/Scripts/ES3Crypto.cs

208 lines
7.4 KiB
C#
Raw Normal View History

2024-10-11 10:12:15 +08:00
#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