mirror of
https://git.teknik.io/Teknikode/Teknik.git
synced 2023-08-02 14:16:22 +02:00
Started making changes to how the file upload encrypt/decrypt works to better optimize memory usage.
This commit is contained in:
parent
2d8c743bac
commit
8d561dd5b8
@ -44,31 +44,25 @@ namespace Teknik.Areas.API.Controllers
|
|||||||
if (model.file.ContentLength <= Config.UploadConfig.MaxUploadSize)
|
if (model.file.ContentLength <= Config.UploadConfig.MaxUploadSize)
|
||||||
{
|
{
|
||||||
// convert file to bytes
|
// convert file to bytes
|
||||||
byte[] fileData = null;
|
|
||||||
string fileExt = Path.GetExtension(model.file.FileName);
|
string fileExt = Path.GetExtension(model.file.FileName);
|
||||||
int contentLength = model.file.ContentLength;
|
int contentLength = model.file.ContentLength;
|
||||||
using (var binaryReader = new BinaryReader(model.file.InputStream))
|
|
||||||
{
|
|
||||||
fileData = binaryReader.ReadBytes(model.file.ContentLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scan the file to detect a virus
|
// Scan the file to detect a virus
|
||||||
if (Config.UploadConfig.VirusScanEnable)
|
if (Config.UploadConfig.VirusScanEnable)
|
||||||
{
|
{
|
||||||
byte[] scanData = fileData;
|
|
||||||
// If it was encrypted client side, decrypt it
|
// If it was encrypted client side, decrypt it
|
||||||
if (!model.encrypt && model.key != null)
|
//if (!model.encrypt && model.key != null)
|
||||||
{
|
//{
|
||||||
// If the IV is set, and Key is set, then decrypt it
|
// // If the IV is set, and Key is set, then decrypt it
|
||||||
if (!string.IsNullOrEmpty(model.key) && !string.IsNullOrEmpty(model.iv))
|
// if (!string.IsNullOrEmpty(model.key) && !string.IsNullOrEmpty(model.iv))
|
||||||
{
|
// {
|
||||||
// Decrypt the data
|
// // Decrypt the data
|
||||||
scanData = AES.Decrypt(scanData, model.key, model.iv);
|
// scanData = AES.Decrypt(scanData, model.key, model.iv);
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
ClamClient clam = new ClamClient(Config.UploadConfig.ClamServer, Config.UploadConfig.ClamPort);
|
ClamClient clam = new ClamClient(Config.UploadConfig.ClamServer, Config.UploadConfig.ClamPort);
|
||||||
clam.MaxStreamSize = Config.UploadConfig.MaxUploadSize;
|
clam.MaxStreamSize = Config.UploadConfig.MaxUploadSize;
|
||||||
ClamScanResult scanResult = clam.SendAndScanFile(scanData);
|
ClamScanResult scanResult = clam.SendAndScanFile(model.file.InputStream);
|
||||||
|
|
||||||
switch (scanResult.Result)
|
switch (scanResult.Result)
|
||||||
{
|
{
|
||||||
@ -95,29 +89,8 @@ namespace Teknik.Areas.API.Controllers
|
|||||||
if (model.blockSize <= 0)
|
if (model.blockSize <= 0)
|
||||||
model.blockSize = Config.UploadConfig.BlockSize;
|
model.blockSize = Config.UploadConfig.BlockSize;
|
||||||
|
|
||||||
byte[] data = null;
|
|
||||||
// If they want us to encrypt the file first, do that here
|
|
||||||
if (model.encrypt)
|
|
||||||
{
|
|
||||||
// Generate key and iv if empty
|
|
||||||
if (string.IsNullOrEmpty(model.key))
|
|
||||||
{
|
|
||||||
model.key = StringHelper.RandomString(model.keySize / 8);
|
|
||||||
}
|
|
||||||
if (string.IsNullOrEmpty(model.iv))
|
|
||||||
{
|
|
||||||
model.iv = StringHelper.RandomString(model.blockSize / 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
data = AES.Encrypt(fileData, model.key, model.iv);
|
|
||||||
if (data == null || data.Length <= 0)
|
|
||||||
{
|
|
||||||
return Json(new { error = new { message = "Unable to encrypt file" } });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the file data
|
// Save the file data
|
||||||
Upload.Models.Upload upload = Uploader.SaveFile(db, Config, (model.encrypt) ? data : fileData, model.contentType, contentLength, fileExt, model.iv, (model.saveKey) ? model.key : null, model.keySize, model.blockSize);
|
Upload.Models.Upload upload = Uploader.SaveFile(db, Config, model.file.InputStream, model.contentType, contentLength, model.encrypt, fileExt, model.iv, model.key, model.saveKey, model.keySize, model.blockSize);
|
||||||
|
|
||||||
if (upload != null)
|
if (upload != null)
|
||||||
{
|
{
|
||||||
|
@ -60,30 +60,24 @@ namespace Teknik.Areas.Upload.Controllers
|
|||||||
if (data.ContentLength <= Config.UploadConfig.MaxUploadSize)
|
if (data.ContentLength <= Config.UploadConfig.MaxUploadSize)
|
||||||
{
|
{
|
||||||
// convert file to bytes
|
// convert file to bytes
|
||||||
byte[] fileData = null;
|
|
||||||
int contentLength = data.ContentLength;
|
int contentLength = data.ContentLength;
|
||||||
using (var binaryReader = new BinaryReader(data.InputStream))
|
|
||||||
{
|
|
||||||
fileData = binaryReader.ReadBytes(data.ContentLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scan the file to detect a virus
|
// Scan the file to detect a virus
|
||||||
if (Config.UploadConfig.VirusScanEnable)
|
if (Config.UploadConfig.VirusScanEnable)
|
||||||
{
|
{
|
||||||
byte[] scanData = fileData;
|
|
||||||
// If it was encrypted client side, decrypt it
|
// If it was encrypted client side, decrypt it
|
||||||
if (!encrypt && key != null)
|
//if (!encrypt && key != null)
|
||||||
{
|
//{
|
||||||
// If the IV is set, and Key is set, then decrypt it
|
// // If the IV is set, and Key is set, then decrypt it
|
||||||
if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(iv))
|
// if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(iv))
|
||||||
{
|
// {
|
||||||
// Decrypt the data
|
// // Decrypt the data
|
||||||
scanData = AES.Decrypt(scanData, key, iv);
|
// scanData = AES.Decrypt(scanData, key, iv);
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
ClamClient clam = new ClamClient(Config.UploadConfig.ClamServer, Config.UploadConfig.ClamPort);
|
ClamClient clam = new ClamClient(Config.UploadConfig.ClamServer, Config.UploadConfig.ClamPort);
|
||||||
clam.MaxStreamSize = Config.UploadConfig.MaxUploadSize;
|
clam.MaxStreamSize = Config.UploadConfig.MaxUploadSize;
|
||||||
ClamScanResult scanResult = clam.SendAndScanFile(scanData);
|
ClamScanResult scanResult = clam.SendAndScanFile(data.InputStream);
|
||||||
|
|
||||||
switch (scanResult.Result)
|
switch (scanResult.Result)
|
||||||
{
|
{
|
||||||
@ -97,23 +91,8 @@ namespace Teknik.Areas.Upload.Controllers
|
|||||||
return Json(new { error = new { message = string.Format("Unknown result while scanning the file upload for viruses. {0}", scanResult.RawResult) } });
|
return Json(new { error = new { message = string.Format("Unknown result while scanning the file upload for viruses. {0}", scanResult.RawResult) } });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if they want us to encrypt it, we do so here
|
Models.Upload upload = Uploader.SaveFile(db, Config, data.InputStream, fileType, contentLength, encrypt, fileExt, iv, key, saveKey, keySize, blockSize);
|
||||||
if (encrypt)
|
|
||||||
{
|
|
||||||
// Generate key and iv if empty
|
|
||||||
if (string.IsNullOrEmpty(key))
|
|
||||||
{
|
|
||||||
key = StringHelper.RandomString(keySize / 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
fileData = AES.Encrypt(fileData, key, iv);
|
|
||||||
if (fileData == null || fileData.Length <= 0)
|
|
||||||
{
|
|
||||||
return Json(new { error = new { message = "Unable to encrypt file" } });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Models.Upload upload = Uploader.SaveFile(db, Config, fileData, fileType, contentLength, fileExt, iv, (saveKey) ? key : null, keySize, blockSize);
|
|
||||||
if (upload != null)
|
if (upload != null)
|
||||||
{
|
{
|
||||||
if (User.Identity.IsAuthenticated)
|
if (User.Identity.IsAuthenticated)
|
||||||
|
@ -6,31 +6,32 @@ using System.IO;
|
|||||||
using Teknik.Configuration;
|
using Teknik.Configuration;
|
||||||
using Teknik.Models;
|
using Teknik.Models;
|
||||||
using Teknik.Utilities;
|
using Teknik.Utilities;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace Teknik.Areas.Upload
|
namespace Teknik.Areas.Upload
|
||||||
{
|
{
|
||||||
public static class Uploader
|
public static class Uploader
|
||||||
{
|
{
|
||||||
public static Models.Upload SaveFile(TeknikEntities db, Config config, byte[] file, string contentType, int contentLength)
|
public static Models.Upload SaveFile(TeknikEntities db, Config config, System.IO.Stream file, string contentType, int contentLength, bool encrypt)
|
||||||
{
|
{
|
||||||
return SaveFile(db, config, file, contentType, contentLength, string.Empty, null, null, 256, 128);
|
return SaveFile(db, config, file, contentType, contentLength, encrypt, string.Empty, null, null, false, 256, 128);
|
||||||
}
|
}
|
||||||
public static Models.Upload SaveFile(TeknikEntities db, Config config, byte[] file, string contentType, int contentLength, string defaultExtension)
|
public static Models.Upload SaveFile(TeknikEntities db, Config config, System.IO.Stream file, string contentType, int contentLength, bool encrypt, string defaultExtension)
|
||||||
{
|
{
|
||||||
return SaveFile(db, config, file, contentType, contentLength, defaultExtension, null, null, 256, 128);
|
return SaveFile(db, config, file, contentType, contentLength, encrypt, defaultExtension, null, null, false, 256, 128);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Models.Upload SaveFile(TeknikEntities db, Config config, byte[] file, string contentType, int contentLength, string defaultExtension, string iv)
|
public static Models.Upload SaveFile(TeknikEntities db, Config config, System.IO.Stream file, string contentType, int contentLength, bool encrypt, string defaultExtension, string iv)
|
||||||
{
|
{
|
||||||
return SaveFile(db, config, file, contentType, contentLength, defaultExtension, iv, null, 256, 128);
|
return SaveFile(db, config, file, contentType, contentLength, encrypt, defaultExtension, iv, null, false, 256, 128);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Models.Upload SaveFile(TeknikEntities db, Config config, byte[] file, string contentType, int contentLength, string defaultExtension, string iv, string key)
|
public static Models.Upload SaveFile(TeknikEntities db, Config config, System.IO.Stream file, string contentType, int contentLength, bool encrypt, string defaultExtension, string iv, string key, bool saveKey)
|
||||||
{
|
{
|
||||||
return SaveFile(db, config, file, contentType, contentLength, defaultExtension, iv, key, 256, 128);
|
return SaveFile(db, config, file, contentType, contentLength, encrypt, defaultExtension, iv, key, saveKey, 256, 128);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Models.Upload SaveFile(TeknikEntities db, Config config, byte[] file, string contentType, int contentLength, string defaultExtension, string iv, string key, int keySize, int blockSize)
|
public static Models.Upload SaveFile(TeknikEntities db, Config config, System.IO.Stream file, string contentType, int contentLength, bool encrypt, string defaultExtension, string iv, string key, bool saveKey, int keySize, int blockSize)
|
||||||
{
|
{
|
||||||
if (!Directory.Exists(config.UploadConfig.UploadDirectory))
|
if (!Directory.Exists(config.UploadConfig.UploadDirectory))
|
||||||
{
|
{
|
||||||
@ -42,7 +43,33 @@ namespace Teknik.Areas.Upload
|
|||||||
string fileName = Path.GetFileName(filePath);
|
string fileName = Path.GetFileName(filePath);
|
||||||
|
|
||||||
// once we have the filename, lets save the file
|
// once we have the filename, lets save the file
|
||||||
File.WriteAllBytes(filePath, file);
|
if (encrypt)
|
||||||
|
{
|
||||||
|
// Generate key and iv if empty
|
||||||
|
if (string.IsNullOrEmpty(key))
|
||||||
|
{
|
||||||
|
key = StringHelper.RandomString(keySize / 8);
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(iv))
|
||||||
|
{
|
||||||
|
iv = StringHelper.RandomString(blockSize / 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] keyBytes = Encoding.UTF8.GetBytes(key);
|
||||||
|
byte[] ivBytes = Encoding.UTF8.GetBytes(iv);
|
||||||
|
|
||||||
|
// Encrypt the file to disk
|
||||||
|
AES.EncryptToFile(filePath, file, config.UploadConfig.ChunkSize, keyBytes, ivBytes, "CTR", "NoPadding");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Just write the stream to the file
|
||||||
|
using (FileStream fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
|
||||||
|
{
|
||||||
|
file.Seek(0, SeekOrigin.Begin);
|
||||||
|
file.CopyTo(fileStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Generate a unique url
|
// Generate a unique url
|
||||||
string extension = (config.UploadConfig.IncludeExtension) ? FileHelper.GetDefaultExtension(contentType, defaultExtension) : string.Empty;
|
string extension = (config.UploadConfig.IncludeExtension) ? FileHelper.GetDefaultExtension(contentType, defaultExtension) : string.Empty;
|
||||||
@ -59,7 +86,7 @@ namespace Teknik.Areas.Upload
|
|||||||
upload.FileName = fileName;
|
upload.FileName = fileName;
|
||||||
upload.ContentType = (!string.IsNullOrEmpty(contentType)) ? contentType : "application/octet-stream";
|
upload.ContentType = (!string.IsNullOrEmpty(contentType)) ? contentType : "application/octet-stream";
|
||||||
upload.ContentLength = contentLength;
|
upload.ContentLength = contentLength;
|
||||||
upload.Key = key;
|
upload.Key = (saveKey) ? key : null;
|
||||||
upload.IV = iv;
|
upload.IV = iv;
|
||||||
upload.KeySize = keySize;
|
upload.KeySize = keySize;
|
||||||
upload.BlockSize = blockSize;
|
upload.BlockSize = blockSize;
|
||||||
|
@ -155,19 +155,12 @@ namespace Teknik.Utilities
|
|||||||
byte[] ivBytes = Encoding.UTF8.GetBytes(iv);
|
byte[] ivBytes = Encoding.UTF8.GetBytes(iv);
|
||||||
return Decrypt(data, keyBytes, ivBytes, "CTR", "NoPadding");
|
return Decrypt(data, keyBytes, ivBytes, "CTR", "NoPadding");
|
||||||
}
|
}
|
||||||
public static byte[] DecryptCBC(byte[] data, string key, string iv)
|
|
||||||
{
|
|
||||||
byte[] keyBytes = Encoding.UTF8.GetBytes(key);
|
|
||||||
byte[] ivBytes = Encoding.UTF8.GetBytes(iv);
|
|
||||||
return Decrypt(data, keyBytes, ivBytes, "CBC", "PKCS5PADDING");
|
|
||||||
}
|
|
||||||
public static byte[] Decrypt(byte[] data, byte[] key, byte[] iv, string mode, string padding)
|
public static byte[] Decrypt(byte[] data, byte[] key, byte[] iv, string mode, string padding)
|
||||||
{
|
{
|
||||||
IBufferedCipher cipher = CipherUtilities.GetCipher("AES/" + mode + "/" + padding);
|
using (MemoryStream stream = new MemoryStream(data))
|
||||||
|
{
|
||||||
cipher.Init(false, new ParametersWithIV(ParameterUtilities.CreateKeyParameter("AES", key), iv));
|
return ProcessCipher(false, stream, 1024, key, iv, mode, padding);
|
||||||
|
}
|
||||||
return cipher.DoFinal(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -181,19 +174,96 @@ namespace Teknik.Utilities
|
|||||||
byte[] ivBytes = Encoding.UTF8.GetBytes(iv);
|
byte[] ivBytes = Encoding.UTF8.GetBytes(iv);
|
||||||
return Encrypt(data, keyBytes, ivBytes, "CTR", "NoPadding");
|
return Encrypt(data, keyBytes, ivBytes, "CTR", "NoPadding");
|
||||||
}
|
}
|
||||||
public static byte[] EncryptCBC(byte[] data, string key, string iv)
|
|
||||||
{
|
|
||||||
byte[] keyBytes = Encoding.UTF8.GetBytes(key);
|
|
||||||
byte[] ivBytes = Encoding.UTF8.GetBytes(iv);
|
|
||||||
return Encrypt(data, keyBytes, ivBytes, "CBC", "PKCS5PADDING");
|
|
||||||
}
|
|
||||||
public static byte[] Encrypt(byte[] data, byte[] key, byte[] iv, string mode, string padding)
|
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 blockSize, 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));
|
||||||
|
|
||||||
|
// 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 processedBytes = 0;
|
||||||
|
|
||||||
|
// Process the stream and save the bytes to the output
|
||||||
|
do
|
||||||
|
{
|
||||||
|
processedBytes = ProcessCipherBlock(cipher, input, blockSize, output, cipherOffset);
|
||||||
|
cipherOffset += processedBytes;
|
||||||
|
}
|
||||||
|
while (processedBytes > 0);
|
||||||
|
|
||||||
|
// Finalize processing of the cipher
|
||||||
|
cipher.DoFinal(output, cipherOffset);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void EncryptToFile(string filePath, Stream input, int blockSize, byte[] key, byte[] iv, string mode, string padding)
|
||||||
{
|
{
|
||||||
IBufferedCipher cipher = CipherUtilities.GetCipher("AES/" + mode + "/" + padding);
|
IBufferedCipher cipher = CipherUtilities.GetCipher("AES/" + mode + "/" + padding);
|
||||||
|
|
||||||
cipher.Init(true, new ParametersWithIV(ParameterUtilities.CreateKeyParameter("AES", key), iv));
|
cipher.Init(true, new ParametersWithIV(ParameterUtilities.CreateKeyParameter("AES", key), iv));
|
||||||
|
|
||||||
return cipher.DoFinal(data);
|
// 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[blockSize];
|
||||||
|
do
|
||||||
|
{
|
||||||
|
processedBytes = ProcessCipherBlock(cipher, input, blockSize, buffer, 0);
|
||||||
|
if (processedBytes > 0)
|
||||||
|
{
|
||||||
|
// We have bytes, lets write them to the file
|
||||||
|
fileStream.Write(buffer, 0, processedBytes);
|
||||||
|
|
||||||
|
// Clear the buffer
|
||||||
|
Array.Clear(buffer, 0, blockSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (processedBytes > 0);
|
||||||
|
|
||||||
|
// Clear the buffer
|
||||||
|
Array.Clear(buffer, 0, blockSize);
|
||||||
|
|
||||||
|
// Do the final output
|
||||||
|
processedBytes = cipher.DoFinal(buffer, 0);
|
||||||
|
if (processedBytes > 0)
|
||||||
|
{
|
||||||
|
// We have bytes, lets write them to the file
|
||||||
|
fileStream.Write(buffer, 0, processedBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int ProcessCipherBlock(IBufferedCipher cipher, Stream input, int blockSize, byte[] output, int outputOffset)
|
||||||
|
{
|
||||||
|
// Initialize buffer
|
||||||
|
byte[] buffer = new byte[blockSize];
|
||||||
|
|
||||||
|
// Read the next block of data
|
||||||
|
int bytesRead = input.Read(buffer, 0, blockSize);
|
||||||
|
if (bytesRead > 0)
|
||||||
|
{
|
||||||
|
// process the cipher for the read block and add it to the output
|
||||||
|
return cipher.ProcessBytes(buffer, 0, bytesRead, output, outputOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] CreateKey(string password, string iv, int keySize = 256)
|
public static byte[] CreateKey(string password, string iv, int keySize = 256)
|
||||||
|
Loading…
Reference in New Issue
Block a user