Browse Source

Finalized new AES cipher wrapper and removed old instance.

tags/3.0.0
Teknikode 2 years ago
parent
commit
cfa226fa6a

+ 1
- 1
ServerMaint/Program.cs View File

@@ -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);

+ 1
- 0
Teknik/Areas/Paste/Controllers/PasteController.cs View File

@@ -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
{

+ 1
- 0
Teknik/Areas/Paste/PasteHelper.cs View File

@@ -6,6 +6,7 @@ using System.Web;
using Teknik.Configuration;
using Teknik.Utilities;
using Teknik.Models;
using Teknik.Utilities.Cryptography;

namespace Teknik.Areas.Paste
{

+ 1
- 1
Teknik/Areas/Upload/Controllers/UploadController.cs View File

@@ -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

+ 2
- 1
Teknik/Areas/Upload/Uploader.cs View File

@@ -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
{

+ 0
- 156
Utilities/Utilities/Crypto.cs View File

@@ -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
- 0
Utilities/Utilities/Cryptography/AES.cs View 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);
}
}
}

+ 16
- 8
Utilities/Utilities/Cryptography/AesCounterMode.cs View File

@@ -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;
}


+ 0
- 77
Utilities/Utilities/ResponseHelper.cs View File

@@ -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();
}
}
}
}

+ 24
- 7
Utilities/Utilities/StreamHelper.cs View File

@@ -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,11 +77,19 @@ namespace Teknik.Utilities
{
// Process the cipher
byte[] output = new byte[count];
//int processed = _Cipher.ProcessBytes(buffer, offset, count, output, 0);

// Finalize the cipher
//AES.FinalizeCipherBlock(_Cipher, output, processed);
// Process the buffer
int processed = _Cipher.TransformBlock(buffer, 0, count, output, 0);

// Do we have more?
if (processed < count)
{
// Finalize the cipher
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();

+ 1
- 0
Utilities/Utilities/Utilities.csproj View File

@@ -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…
Cancel
Save