mirror of
https://git.teknik.io/Teknikode/Teknik.git
synced 2023-08-02 14:16:22 +02:00
Finalized new AES cipher wrapper and removed old instance.
This commit is contained in:
parent
72e5f4b62e
commit
cfa226fa6a
@ -168,7 +168,7 @@ namespace ServerMaint
|
||||
byte[] keyBytes = Encoding.UTF8.GetBytes(upload.Key);
|
||||
byte[] ivBytes = Encoding.UTF8.GetBytes(upload.IV);
|
||||
FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
|
||||
AESCryptoStream aesStream = new AESCryptoStream(fs, false, keyBytes, ivBytes, "CTR", "NoPadding");
|
||||
AESCryptoStream aesStream = new AESCryptoStream(fs, false, keyBytes, ivBytes);
|
||||
|
||||
// We have the data, let's scan it
|
||||
ClamScanResult scanResult = clam.SendAndScanFile(aesStream);
|
||||
|
@ -15,6 +15,7 @@ using Teknik.Filters;
|
||||
using Teknik.Utilities;
|
||||
using Teknik.Models;
|
||||
using Teknik.Attributes;
|
||||
using Teknik.Utilities.Cryptography;
|
||||
|
||||
namespace Teknik.Areas.Paste.Controllers
|
||||
{
|
||||
|
@ -6,6 +6,7 @@ using System.Web;
|
||||
using Teknik.Configuration;
|
||||
using Teknik.Utilities;
|
||||
using Teknik.Models;
|
||||
using Teknik.Utilities.Cryptography;
|
||||
|
||||
namespace Teknik.Areas.Paste
|
||||
{
|
||||
|
@ -294,7 +294,7 @@ namespace Teknik.Areas.Upload.Controllers
|
||||
|
||||
return new FileGenerateResult(url,
|
||||
contentType,
|
||||
(response) => ResponseHelper.StreamToOutput(response, true, new AESCryptoStream(fs, false, keyBytes, ivBytes, "CTR", "NoPadding"), (int)length, Config.UploadConfig.ChunkSize),
|
||||
(response) => ResponseHelper.StreamToOutput(response, true, new AESCryptoStream(fs, false, keyBytes, ivBytes), (int)length, Config.UploadConfig.ChunkSize),
|
||||
false);
|
||||
}
|
||||
else // Otherwise just send it
|
||||
|
@ -8,6 +8,7 @@ using Teknik.Models;
|
||||
using Teknik.Utilities;
|
||||
using System.Text;
|
||||
using Org.BouncyCastle.Utilities.Encoders;
|
||||
using Teknik.Utilities.Cryptography;
|
||||
|
||||
namespace Teknik.Areas.Upload
|
||||
{
|
||||
@ -54,7 +55,7 @@ namespace Teknik.Areas.Upload
|
||||
byte[] ivBytes = Encoding.UTF8.GetBytes(iv);
|
||||
|
||||
// Encrypt the file to disk
|
||||
AES.EncryptToFile(filePath, file, config.UploadConfig.ChunkSize, keyBytes, ivBytes, "CTR", "NoPadding");
|
||||
AES.EncryptToFile(filePath, file, config.UploadConfig.ChunkSize, keyBytes, ivBytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3,15 +3,8 @@ using SecurityDriven.Inferno.Hash;
|
||||
using SecurityDriven.Inferno.Mac;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Engines;
|
||||
using Org.BouncyCastle.Crypto.Modes;
|
||||
using Org.BouncyCastle.Crypto.Paddings;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities.Encoders;
|
||||
using Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
using Org.BouncyCastle.Utilities.IO;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.MemoryMappedFiles;
|
||||
@ -154,155 +147,6 @@ namespace Teknik.Utilities
|
||||
}
|
||||
}
|
||||
|
||||
public class AES
|
||||
{
|
||||
public static byte[] Decrypt(byte[] data, byte[] key, byte[] iv)
|
||||
{
|
||||
return Decrypt(data, key, iv, "CTR", "NoPadding");
|
||||
}
|
||||
public static byte[] Decrypt(byte[] data, string key, string iv)
|
||||
{
|
||||
byte[] keyBytes = Encoding.UTF8.GetBytes(key);
|
||||
byte[] ivBytes = Encoding.UTF8.GetBytes(iv);
|
||||
return Decrypt(data, keyBytes, ivBytes, "CTR", "NoPadding");
|
||||
}
|
||||
public static byte[] Decrypt(byte[] data, byte[] key, byte[] iv, string mode, string padding)
|
||||
{
|
||||
using (MemoryStream stream = new MemoryStream(data))
|
||||
{
|
||||
return ProcessCipher(false, stream, 1024, key, iv, mode, padding);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static byte[] Encrypt(byte[] data, byte[] key, byte[] iv)
|
||||
{
|
||||
return Encrypt(data, key, iv, "CTR", "NoPadding");
|
||||
}
|
||||
public static byte[] Encrypt(byte[] data, string key, string iv)
|
||||
{
|
||||
byte[] keyBytes = Encoding.UTF8.GetBytes(key);
|
||||
byte[] ivBytes = Encoding.UTF8.GetBytes(iv);
|
||||
return Encrypt(data, keyBytes, ivBytes, "CTR", "NoPadding");
|
||||
}
|
||||
public static byte[] Encrypt(byte[] data, byte[] key, byte[] iv, string mode, string padding)
|
||||
{
|
||||
using (MemoryStream stream = new MemoryStream(data))
|
||||
{
|
||||
return ProcessCipher(true, stream, 1024, key, iv, mode, padding);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] ProcessCipher(bool encrypt, Stream input, int chunkSize, byte[] key, byte[] iv, string mode, string padding)
|
||||
{
|
||||
// Create the cipher we are going to use
|
||||
IBufferedCipher cipher = CreateCipher(encrypt, key, iv, mode, padding);
|
||||
|
||||
// Make sure the input stream is at the beginning
|
||||
input.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
// Initialize variables
|
||||
byte[] output = new byte[input.Length];
|
||||
int cipherOffset = 0;
|
||||
int bytesRead = 0;
|
||||
|
||||
// Process the stream and save the bytes to the output
|
||||
do
|
||||
{
|
||||
int processedBytes = ProcessCipherBlock(cipher, input, 0, chunkSize, output, cipherOffset, out bytesRead);
|
||||
cipherOffset += processedBytes;
|
||||
}
|
||||
while (bytesRead > 0);
|
||||
|
||||
// Finalize processing of the cipher
|
||||
FinalizeCipherBlock(cipher, output, cipherOffset);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
public static void EncryptToFile(string filePath, Stream input, int chunkSize, byte[] key, byte[] iv, string mode, string padding)
|
||||
{
|
||||
IBufferedCipher cipher = CreateCipher(true, key, iv, mode, padding);
|
||||
|
||||
// Make sure the input stream is at the beginning
|
||||
input.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
using (FileStream fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
int processedBytes = 0;
|
||||
byte[] buffer = new byte[chunkSize];
|
||||
int bytesRead = 0;
|
||||
do
|
||||
{
|
||||
processedBytes = ProcessCipherBlock(cipher, input, 0, chunkSize, buffer, 0, out bytesRead);
|
||||
if (processedBytes > 0)
|
||||
{
|
||||
// We have bytes, lets write them to the file
|
||||
fileStream.Write(buffer, 0, processedBytes);
|
||||
|
||||
// Clear the buffer
|
||||
Array.Clear(buffer, 0, chunkSize);
|
||||
}
|
||||
}
|
||||
while (processedBytes > 0);
|
||||
|
||||
// Clear the buffer
|
||||
Array.Clear(buffer, 0, chunkSize);
|
||||
|
||||
// Finalize processing of the cipher
|
||||
processedBytes = FinalizeCipherBlock(cipher, buffer, 0);
|
||||
if (processedBytes > 0)
|
||||
{
|
||||
// We have bytes, lets write them to the file
|
||||
fileStream.Write(buffer, 0, processedBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IBufferedCipher CreateCipher(bool encrypt, byte[] key, byte[] iv, string mode, string padding)
|
||||
{
|
||||
IBufferedCipher cipher = CipherUtilities.GetCipher("AES/" + mode + "/" + padding);
|
||||
|
||||
cipher.Init(encrypt, new ParametersWithIV(ParameterUtilities.CreateKeyParameter("AES", key), iv));
|
||||
|
||||
return cipher;
|
||||
}
|
||||
|
||||
public static int ProcessCipherBlock(IBufferedCipher cipher, Stream input, int inputOffset, int chunkSize, byte[] output, int outputOffset, out int bytesRead)
|
||||
{
|
||||
// Initialize buffer
|
||||
byte[] buffer = new byte[chunkSize + inputOffset];
|
||||
|
||||
// Read the next block of data
|
||||
bytesRead = input.Read(buffer, 0, chunkSize + inputOffset);
|
||||
if (bytesRead > 0)
|
||||
{
|
||||
// process the cipher for the read block and add it to the output
|
||||
return cipher.ProcessBytes(buffer, inputOffset, bytesRead - inputOffset, output, outputOffset);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int FinalizeCipherBlock(IBufferedCipher cipher, byte[] output, int outputOffset)
|
||||
{
|
||||
// perform final action on cipher
|
||||
return cipher.DoFinal(output, outputOffset);
|
||||
}
|
||||
|
||||
public static byte[] CreateKey(string password, string iv, int keySize = 256)
|
||||
{
|
||||
byte[] ivBytes = Encoding.UTF8.GetBytes(iv);
|
||||
return CreateKey(password, ivBytes, keySize);
|
||||
}
|
||||
public static byte[] CreateKey(string password, byte[] iv, int keySize = 256)
|
||||
{
|
||||
const int Iterations = 300;
|
||||
var keyGenerator = new Rfc2898DeriveBytes(password, iv, Iterations);
|
||||
return keyGenerator.GetBytes(keySize / 8);
|
||||
}
|
||||
}
|
||||
|
||||
public static class PGP
|
||||
{
|
||||
public static bool IsPublicKey(string key)
|
||||
|
129
Utilities/Utilities/Cryptography/AES.cs
Normal file
129
Utilities/Utilities/Cryptography/AES.cs
Normal file
@ -0,0 +1,129 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Teknik.Utilities.Cryptography
|
||||
{
|
||||
|
||||
public class AES
|
||||
{
|
||||
public static byte[] Decrypt(byte[] data, string key, string iv)
|
||||
{
|
||||
byte[] keyBytes = Encoding.UTF8.GetBytes(key);
|
||||
byte[] ivBytes = Encoding.UTF8.GetBytes(iv);
|
||||
return Decrypt(data, keyBytes, ivBytes);
|
||||
}
|
||||
public static byte[] Decrypt(byte[] data, byte[] key, byte[] iv)
|
||||
{
|
||||
using (MemoryStream stream = new MemoryStream(data))
|
||||
{
|
||||
return ProcessCipher(false, stream, 1024, key, iv);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] Encrypt(byte[] data, string key, string iv)
|
||||
{
|
||||
byte[] keyBytes = Encoding.UTF8.GetBytes(key);
|
||||
byte[] ivBytes = Encoding.UTF8.GetBytes(iv);
|
||||
return Encrypt(data, keyBytes, ivBytes);
|
||||
}
|
||||
public static byte[] Encrypt(byte[] data, byte[] key, byte[] iv)
|
||||
{
|
||||
using (MemoryStream stream = new MemoryStream(data))
|
||||
{
|
||||
return ProcessCipher(true, stream, 1024, key, iv);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] ProcessCipher(bool encrypt, Stream input, int chunkSize, byte[] key, byte[] iv)
|
||||
{
|
||||
// Make sure the input stream is at the beginning
|
||||
input.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
AESCryptoStream cryptoStream = new AESCryptoStream(input, encrypt, key, iv);
|
||||
|
||||
// Initialize variables
|
||||
byte[] output = new byte[input.Length];
|
||||
|
||||
// Process the stream and save the bytes to the output
|
||||
int curByte = 0;
|
||||
int processedBytes = 0;
|
||||
byte[] buffer = new byte[chunkSize];
|
||||
int bytesRemaining = (int)input.Length;
|
||||
int bytesToRead = chunkSize;
|
||||
do
|
||||
{
|
||||
if (chunkSize > bytesRemaining)
|
||||
{
|
||||
bytesToRead = bytesRemaining;
|
||||
}
|
||||
|
||||
processedBytes = cryptoStream.Read(buffer, 0, bytesToRead);
|
||||
if (processedBytes > 0)
|
||||
{
|
||||
buffer.Take(processedBytes).ToArray().CopyTo(output, curByte);
|
||||
|
||||
// Clear the buffer
|
||||
Array.Clear(buffer, 0, chunkSize);
|
||||
}
|
||||
curByte += processedBytes;
|
||||
bytesRemaining -= processedBytes;
|
||||
}
|
||||
while (processedBytes > 0 && bytesRemaining > 0);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
public static void EncryptToFile(string filePath, Stream input, int chunkSize, byte[] key, byte[] iv)
|
||||
{
|
||||
// Make sure the input stream is at the beginning
|
||||
input.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
AESCryptoStream cryptoStream = new AESCryptoStream(input, true, key, iv);
|
||||
|
||||
using (FileStream fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
int curByte = 0;
|
||||
int processedBytes = 0;
|
||||
byte[] buffer = new byte[chunkSize];
|
||||
int bytesRemaining = (int)input.Length;
|
||||
int bytesToRead = chunkSize;
|
||||
do
|
||||
{
|
||||
if (chunkSize > bytesRemaining)
|
||||
{
|
||||
bytesToRead = bytesRemaining;
|
||||
}
|
||||
|
||||
processedBytes = cryptoStream.Read(buffer, 0, bytesToRead);
|
||||
if (processedBytes > 0)
|
||||
{
|
||||
fileStream.Write(buffer, 0, processedBytes);
|
||||
|
||||
// Clear the buffer
|
||||
Array.Clear(buffer, 0, chunkSize);
|
||||
}
|
||||
curByte += processedBytes;
|
||||
bytesRemaining -= processedBytes;
|
||||
}
|
||||
while (processedBytes > 0 && bytesRemaining > 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] CreateKey(string password, string iv, int keySize = 256)
|
||||
{
|
||||
byte[] ivBytes = Encoding.UTF8.GetBytes(iv);
|
||||
return CreateKey(password, ivBytes, keySize);
|
||||
}
|
||||
public static byte[] CreateKey(string password, byte[] iv, int keySize = 256)
|
||||
{
|
||||
const int Iterations = 300;
|
||||
var keyGenerator = new Rfc2898DeriveBytes(password, iv, Iterations);
|
||||
return keyGenerator.GetBytes(keySize / 8);
|
||||
}
|
||||
}
|
||||
}
|
@ -31,7 +31,8 @@ namespace Teknik.Utilities.Cryptography
|
||||
};
|
||||
|
||||
// Set the internal variables
|
||||
_Counter = counter;
|
||||
_Counter = new byte[counter.Length];
|
||||
counter.CopyTo(_Counter, 0);
|
||||
}
|
||||
|
||||
public override ICryptoTransform CreateEncryptor(byte[] key, byte[] iv)
|
||||
@ -103,8 +104,12 @@ namespace Teknik.Utilities.Cryptography
|
||||
counter.Length, symmetricAlgorithm.BlockSize / 8));
|
||||
|
||||
_SymmetricAlgorithm = symmetricAlgorithm;
|
||||
_IV = iv;
|
||||
_Counter = counter;
|
||||
|
||||
_IV = new byte[iv.Length];
|
||||
iv.CopyTo(_IV, 0);
|
||||
|
||||
_Counter = new byte[counter.Length];
|
||||
counter.CopyTo(_Counter, 0);
|
||||
|
||||
_CounterEncryptor = symmetricAlgorithm.CreateEncryptor(key, iv);
|
||||
|
||||
@ -114,6 +119,9 @@ namespace Teknik.Utilities.Cryptography
|
||||
|
||||
// Encrypt the counter
|
||||
EncryptCounter();
|
||||
|
||||
// Initial Increment
|
||||
IncrementCounter();
|
||||
}
|
||||
|
||||
public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
|
||||
@ -130,13 +138,13 @@ namespace Teknik.Utilities.Cryptography
|
||||
// Encrypt the counter if we have reached the end, or
|
||||
if (_CounterPosition >= _EncryptedCounter.Length)
|
||||
{
|
||||
// Encrypt the counter
|
||||
EncryptCounter();
|
||||
|
||||
//Reset current counter position
|
||||
_CounterPosition = 0;
|
||||
|
||||
// Increment the counter for the next run
|
||||
// Encrypt the counter
|
||||
EncryptCounter();
|
||||
|
||||
// Increment the counter for the next batch
|
||||
IncrementCounter();
|
||||
}
|
||||
|
||||
@ -162,7 +170,7 @@ namespace Teknik.Utilities.Cryptography
|
||||
public void ResetCounter()
|
||||
{
|
||||
Array.Clear(_Counter, 0, _Counter.Length);
|
||||
Array.Copy(_IV, 0, _Counter, 0, _IV.Length);
|
||||
_IV.CopyTo(_Counter, 0);
|
||||
_Iterations = 0;
|
||||
}
|
||||
|
||||
|
@ -77,82 +77,5 @@ namespace Teknik.Utilities
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void DecryptStreamToOutput(HttpResponseBase response, bool flush, Stream stream, int length, byte[] key, byte[] iv, string mode, string padding, int chunkSize)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (flush)
|
||||
{
|
||||
response.Flush();
|
||||
}
|
||||
IBufferedCipher cipher = AES.CreateCipher(false, key, iv, mode, padding);
|
||||
|
||||
int curByte = 0;
|
||||
int processedBytes = 0;
|
||||
byte[] buffer = new byte[chunkSize];
|
||||
int bytesRemaining = length;
|
||||
int bytesToRead = chunkSize;
|
||||
int bytesRead = 0;
|
||||
do
|
||||
{
|
||||
if (chunkSize > bytesRemaining)
|
||||
{
|
||||
bytesToRead = bytesRemaining;
|
||||
}
|
||||
processedBytes = AES.ProcessCipherBlock(cipher, stream, 0, bytesToRead, buffer, 0, out bytesRead);
|
||||
if (processedBytes > 0)
|
||||
{
|
||||
response.OutputStream.Write(buffer, 0, processedBytes);
|
||||
if (flush)
|
||||
{
|
||||
response.Flush();
|
||||
}
|
||||
|
||||
// Clear the buffer
|
||||
Array.Clear(buffer, 0, chunkSize);
|
||||
}
|
||||
curByte += bytesRead;
|
||||
bytesRemaining -= bytesRead;
|
||||
}
|
||||
while (bytesRemaining > 0);
|
||||
|
||||
// Clear the buffer
|
||||
Array.Clear(buffer, 0, chunkSize);
|
||||
|
||||
// Finalize processing of the cipher
|
||||
processedBytes = AES.FinalizeCipherBlock(cipher, buffer, 0);
|
||||
if (processedBytes > 0)
|
||||
{
|
||||
// We have bytes, lets write them to the output
|
||||
response.OutputStream.Write(buffer, 0, processedBytes);
|
||||
if (flush)
|
||||
{
|
||||
response.Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (HttpException httpEx)
|
||||
{
|
||||
// If we lost connection, that's fine
|
||||
if (httpEx.ErrorCode == -2147023667)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
//throw httpEx;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// dispose of file stream
|
||||
stream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,16 @@ namespace Teknik.Utilities
|
||||
private Stream _Inner;
|
||||
private CounterModeCryptoTransform _Cipher;
|
||||
|
||||
public AESCryptoStream(Stream stream, bool encrypt, byte[] key, byte[] iv, string mode, string padding)
|
||||
/// <summary>
|
||||
/// Performs Encryption or Decryption on a stream with the given Key and IV
|
||||
///
|
||||
/// Cipher is AES-256 in CTR mode with no padding
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="encrypt"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="iv"></param>
|
||||
public AESCryptoStream(Stream stream, bool encrypt, byte[] key, byte[] iv)
|
||||
{
|
||||
_Inner = stream;
|
||||
|
||||
@ -44,7 +53,7 @@ namespace Teknik.Utilities
|
||||
int bytesRead = _Inner.Read(readBuf, 0, count);
|
||||
if (bytesRead > 0)
|
||||
{
|
||||
// Process the
|
||||
// Process the read buffer
|
||||
processed = _Cipher.TransformBlock(readBuf, 0, bytesRead, buffer, 0);
|
||||
}
|
||||
|
||||
@ -68,10 +77,18 @@ namespace Teknik.Utilities
|
||||
{
|
||||
// Process the cipher
|
||||
byte[] output = new byte[count];
|
||||
//int processed = _Cipher.ProcessBytes(buffer, offset, count, output, 0);
|
||||
|
||||
// Process the buffer
|
||||
int processed = _Cipher.TransformBlock(buffer, 0, count, output, 0);
|
||||
|
||||
// Do we have more?
|
||||
if (processed < count)
|
||||
{
|
||||
// Finalize the cipher
|
||||
//AES.FinalizeCipherBlock(_Cipher, output, processed);
|
||||
byte[] finalBuf = _Cipher.TransformFinalBlock(buffer, processed, count);
|
||||
finalBuf.CopyTo(output, processed);
|
||||
processed += finalBuf.Length;
|
||||
}
|
||||
|
||||
_Inner.Write(output, 0, count);
|
||||
}
|
||||
@ -187,7 +204,7 @@ namespace Teknik.Utilities
|
||||
int counterPos = (int)(_Inner.Position % _Cipher.InputBlockSize);
|
||||
|
||||
// Are we out of sync with the cipher?
|
||||
if (_Cipher.Iterations != iterations || _Cipher.CounterPosition != counterPos)
|
||||
if (_Cipher.Iterations != iterations + 1 || _Cipher.CounterPosition != counterPos)
|
||||
{
|
||||
// Reset the current counter
|
||||
_Cipher.ResetCounter();
|
||||
|
@ -106,6 +106,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AccountType.cs" />
|
||||
<Compile Include="Cryptography\AES.cs" />
|
||||
<Compile Include="Cryptography\AesCounterMode.cs" />
|
||||
<Compile Include="CurrencyHelper.cs" />
|
||||
<Compile Include="CurrencyType.cs" />
|
||||
|
Loading…
Reference in New Issue
Block a user