Browse Source

Finalized new AES cipher wrapper and removed old instance.

pull/111/head
Teknikode 6 years ago
parent
commit
cfa226fa6a
  1. 2
      ServerMaint/Program.cs
  2. 1
      Teknik/Areas/Paste/Controllers/PasteController.cs
  3. 1
      Teknik/Areas/Paste/PasteHelper.cs
  4. 2
      Teknik/Areas/Upload/Controllers/UploadController.cs
  5. 3
      Teknik/Areas/Upload/Uploader.cs
  6. 156
      Utilities/Utilities/Crypto.cs
  7. 129
      Utilities/Utilities/Cryptography/AES.cs
  8. 24
      Utilities/Utilities/Cryptography/AesCounterMode.cs
  9. 77
      Utilities/Utilities/ResponseHelper.cs
  10. 31
      Utilities/Utilities/StreamHelper.cs
  11. 1
      Utilities/Utilities/Utilities.csproj

2
ServerMaint/Program.cs

@ -168,7 +168,7 @@ namespace ServerMaint @@ -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
Teknik/Areas/Paste/Controllers/PasteController.cs

@ -15,6 +15,7 @@ using Teknik.Filters; @@ -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
Teknik/Areas/Paste/PasteHelper.cs

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

2
Teknik/Areas/Upload/Controllers/UploadController.cs

@ -294,7 +294,7 @@ namespace Teknik.Areas.Upload.Controllers @@ -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

3
Teknik/Areas/Upload/Uploader.cs

@ -8,6 +8,7 @@ using Teknik.Models; @@ -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 @@ -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
{

156
Utilities/Utilities/Crypto.cs

@ -3,15 +3,8 @@ using SecurityDriven.Inferno.Hash; @@ -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 @@ -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

@ -0,0 +1,129 @@ @@ -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);
}
}
}

24
Utilities/Utilities/Cryptography/AesCounterMode.cs

@ -31,7 +31,8 @@ namespace Teknik.Utilities.Cryptography @@ -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 @@ -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 @@ -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 @@ -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 @@ -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
Utilities/Utilities/ResponseHelper.cs

@ -77,82 +77,5 @@ namespace Teknik.Utilities @@ -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();
}
}
}
}

31
Utilities/Utilities/StreamHelper.cs

@ -14,7 +14,16 @@ namespace Teknik.Utilities @@ -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 @@ -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 @@ -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 @@ -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
Utilities/Utilities/Utilities.csproj

@ -106,6 +106,7 @@ @@ -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