C# Decrypting mp3 file using RijndaelManaged and CryptoStream - c#

I have decrypted and saved an mp3 file into a blob storage.
However, when I decrypt and download the file I cant play it. I used an Mp3 validation tool which says "unknown file format". I believe it is the decryption that does not work since it works to download an unencrypted Mp3 file. Below I first show the encryption code within its Azure webjob function. The I show the decryption method and the method using it. I have removed handling of keys and such or clarity.
Encrypt
public static void EncryptBlob(
[BlobTrigger("callstest/{name}")]
[Blob("callstest/{name}", FileAccess.Read)] Stream blobInput,
[Blob("encryptedcalls/{name}.vega", FileAccess.Write)] Stream blobOutput)
{
try
{
var password = "myKey123";
var ue = new UnicodeEncoding();
var key = ue.GetBytes(password);
var rmCrypto = new RijndaelManaged {Padding = PaddingMode.None};
using (var cs = new CryptoStream(blobOutput,
rmCrypto.CreateEncryptor(key, key),
CryptoStreamMode.Write))
{
int data;
while ((data = blobInput.ReadByte()) != -1)
cs.WriteByte((byte)data);
}
}
catch
{
Trace.TraceError("an error occured during encryption of the file-get the name?");
}
}
AdminController
public async Task<ActionResult> DownloadMp3FromUrl()
{
var file = await _recordingService.GetRecordingFromUrl();
var fileName = "filetest.mp3";
return File(file,"audio/mpeg", fileName);
}
Recording Service handler
public async Task<byte[]> GetRecordingFromUrl()
{
var container = _blobClient.GetContainerReference("encryptedcalls");
var blockBlob = container.GetBlockBlobReference("SearchFiles.mp3.vega");
try
{
var password = "myKey123";
var ue = new UnicodeEncoding();
var key = ue.GetBytes(password);
var rmCrypto = new RijndaelManaged { Padding = PaddingMode.None };
using (var stream = new MemoryStream())
{
blockBlob.FetchAttributes();
blockBlob.DownloadToStream(stream, null, null);
using (var cs = new CryptoStream(stream, rmCrypto.CreateDecryptor(key, key), CryptoStreamMode.Read))
{
int data;
while ((data = stream.ReadByte()) != -1)
cs.WriteByte((byte)data);
return stream.ToArray();
}
}
}
catch
{
Trace.TraceError("an error occured during encryption of the file-get the name?");
}
return null;
}

You're trying to write the decrypted data back into the source-stream in your Recording Service handler. This will never work. I'm amazed this doesn't throw an exception.
You need to set up your input stream, pass it into a decrypting CryptoStream, then write that to another output stream:
using (var inStream = new MemoryStream())
using (var outStream = new MemoryStream())
{
blockBlob.FetchAttributes();
blockBlob.DownloadToStream(inStream, null, null);
using (var cryptoStream = new CryptoStream(
inStream, rmCrypto.CreateDecryptor(key, key), CryptoStreamMode.Read))
{
cryptoStream.CopyTo(outStream);
return outStream.ToArray();
}
}
As an aside, the implementation as you've presented it here is full of security issues:
Don't use a non-padded cipher. You can leak information this way.
Don't generate your key from a password. Use a cryptographically secure RNG to generate your keys.
If you must use a string as your key's password, use Rfc2898DeriveBytes to generate a cryptographically secure random key from the password.
Absolutely do not use your symmetric key as your IV. This is really, really bad practice. The IV is used to randomize the cipher's output - it is not a secret in the same way as the key, and should be unique to each 'message' (or file) being encrypted.

Related

CryptoStream behaves differently on local and aws

I have encryption decryption code which is perfectly working fine in local. From local system using code first approach I created database in aws which created successfully with seeds values in which I have decrypted the password.
Now, I have published the .net6 application in aws ec2 instance. On logging it is giving error of incorrect credentials.
I have logged the username and passwords and rechecked the scenario. The issue I have found is the encryption is changed.
I have updated the password and successfully logged in. But now the problem is with roles. I have applied checks on encrypted role ids which are not maching now.
Can anyone please help me here on this issue please?
`
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace Common
{
public static class EncyptionDcryption
{
static string key = "85OIbnI9";
static string vector = "eH90BDl0";
////////////////////////////////////////////////////////////////////////////////
// Decryption
////////////////////////////////////////////////////////////////////////////////
public static string GetDecryptedText(string txt)
{
txt = txt.Replace(' ', '+');
DESCryptoServiceProvider key = new DESCryptoServiceProvider();
key.Key = ASCIIEncoding.ASCII.GetBytes(key); // decryption key
key.IV = ASCIIEncoding.ASCII.GetBytes(vector);// initialization vector
int length = txt.Length;
byte[] buffer = new byte[length];
buffer = Convert.FromBase64String(txt);
string decText = Decrypt(buffer, key);
return decText;
}
public static string Decrypt(byte[] CypherText, SymmetricAlgorithm key)
{
// Create a memory stream to the passed buffer.
MemoryStream ms = new MemoryStream(CypherText);
// Create a CryptoStream using the memory stream and the
// CSP DES key.
CryptoStream encStream = new CryptoStream(ms, key.CreateDecryptor(), CryptoStreamMode.Read);
// Create a StreamReader for reading the stream.
StreamReader sr = new StreamReader(encStream);
// Read the stream as a string.
string val = sr.ReadLine();
// Close the streams.
sr.Close();
encStream.Close();
ms.Close();
return val;
}
////////////////////////////////////////////////////////////////////////////////
// Encryption
////////////////////////////////////////////////////////////////////////////////
public static byte[] Encrypt(string PlainText, SymmetricAlgorithm key)
{
// Create a memory stream.
MemoryStream ms = new MemoryStream();
// Create a CryptoStream using the memory stream and the
// CSP DES key.
CryptoStream encStream = new CryptoStream(ms, key.CreateEncryptor(), CryptoStreamMode.Write);
// Create a StreamWriter to write a string
// to the stream.
StreamWriter sw = new StreamWriter(encStream);
// Write the plaintext to the stream.
sw.WriteLine(PlainText);
// Close the StreamWriter and CryptoStream.
sw.Close();
encStream.Close();
// Get an array of bytes that represents
// the memory stream.
byte[] buffer = ms.ToArray();
// Close the memory stream.
ms.Close();
// Return the encrypted byte array.
return buffer;
}
public static string GetEncryptedText(string txt)
{
DESCryptoServiceProvider key = new DESCryptoServiceProvider();
key.Key = ASCIIEncoding.ASCII.GetBytes(key); // decryption key
key.IV = ASCIIEncoding.ASCII.GetBytes(vector);// initialization vector
// Encrypt a string to a byte array.
byte[] buffer = Encrypt(txt, key);
string encText;
encText = Convert.ToBase64String(buffer);
return encText;
}
}
}
`
Why it behaves differently on server and local? But no clue.

Decryption providing a padding error

I'm trying to save a serialized object to an encrypted file. This isn't production quality and I am aware of the security risks with the way that I am doing this, but ignoring those I will have a key in a resource (data.Settings.key) that wont change and I have a salt that is also a constant.
My encryption seems to work, but decryption returns me an Exception saying that padding is invalid and cannot be closed when I try to close my CryptoStream.
private static byte[] decrypt(byte[] bytes)
{
var decryptor = algorithm.CreateDecryptor();
using (var sMemoryStream = new MemoryStream())
using (var sCryptoStream = new CryptoStream(sMemoryStream, decryptor, CryptoStreamMode.Write))
{
sCryptoStream.Write(bytes, 0, bytes.Length);
sCryptoStream.Close();
return sMemoryStream.ToArray();
}
}
The algorithm variable is the same one that the encrypt method uses and is built by this method which is called in the classes constructor:
private static SymmetricAlgorithm GetAlgorithm()
{
var algorithm = Rijndael.Create();
// Create key from salt and password in config
var rdb = new Rfc2898DeriveBytes(data.Settings.key, new byte[] {
0x44,0x61,0x79,0x6e,0x65,0x44,0x6f,0x75,0x67,0x61,0x6e
});
algorithm.Padding = PaddingMode.PKCS7;
// Set key and IV from rdb
algorithm.Key = rdb.GetBytes(32);
algorithm.IV = rdb.GetBytes(16);
return algorithm;
}
I've tried changing the padding mode in the algorithm but I can't understand why it's fine with this padding when encrypting, but now when decrypting.
If it helps here is the method that calls the decrypt method:
private static User OpenFile(String sUserName)
{
Console.WriteLine("Opening file...");
using (Stream sFileStream = new FileStream(data.Settings.dir + "data\\accounts\\" + sUserName + ".dat",
FileMode.Open, FileAccess.Read, FileShare.None))
using (Stream sMemoryStream = new MemoryStream())
{
// Read from File to memory stream
sFileStream.CopyTo(sMemoryStream);
// Decrypt data and store in new memory stream
byte[] bytes = new byte[sMemoryStream.Length];
Console.WriteLine("\tb:" + bytes.Length);
bytes = decrypt(bytes);
Console.WriteLine("\ta:" + bytes.Length);
Stream stream = new MemoryStream(bytes);
Console.WriteLine("\ts:" + bytes.Length);
// Deserialise memory stream and return as User object
User user = (User)bfFormatter.Deserialize(stream);
stream.Close();
return user;
}
}

C# Encryption using RijndaelManaged - Save file in base64 format

Scenario - I have multiple files on my server and as per policy we can keep only encrypted files. We are doing some data migration, for this we have to move these files on to cloud and as per documentations Base64 is the best way to transfer encrypted data over network. I am new in encryption and stuck between this. Let me know if this help you.
How to save file in base64 format?
================================================================
I am new in Encryption and got below code from net and trying to encrypting files using RijndaelManaged and the following code is working fine
public static void EncryptFile(string inputFile, string outputFile)
{
try
{
string password = #"myKey123"; // Your Key Here
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(password);
string cryptFile = outputFile;
FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create);
RijndaelManaged RMCrypto = new RijndaelManaged();
CryptoStream cs = new CryptoStream(fsCrypt,
RMCrypto.CreateEncryptor(key, key),
CryptoStreamMode.Write);
FileStream fsIn = new FileStream(inputFile, FileMode.Open);
int data;
while ((data = fsIn.ReadByte()) != -1)
cs.WriteByte((byte)data);
fsIn.Close();
cs.Close();
fsCrypt.Close();
}
catch
{
}
}
When I try to decrypt using Convert.FromBase64String, it returns an error
public static string DecryptFile(string inputFile)
{
var myRijndael = new RijndaelManaged { Key = _key, IV = _key, Padding = PaddingMode.PKCS7 };
_decryptor = myRijndael.CreateDecryptor(myRijndael.Key, myRijndael.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(Convert.FromBase64String(inputFile)))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, _decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
return srDecrypt.ReadToEnd();
}
}
}
}
Please help me to solve this issue

C# RijndaelManaged to Python equivalent

I have the following C# code (code is inherited and can't compile it). This is used to decrypt and unzip a saved file.
using System.Security.Cryptography;
using System.Text;
using ICSharpCode.SharpZipLib.Zip;
//Not the real key but same amount of chars
private const string kEncyptionKey = "01234567";
public string DecryptAndDecompressText (string strFileName)
{
// Decryption ///
FileStream fin = null;
try
{
fin = new FileStream(strFileName, FileMode.Open, FileAccess.Read);
}
catch (System.IO.FileNotFoundException)
{
return "";
}
MemoryStream memoryToDecompress = new MemoryStream();
UnicodeEncoding UE = new UnicodeEncoding();
RijndaelManaged RMCrypto = new RijndaelManaged();
// This is the encryption key for our file
byte[] key = UE.GetBytes(kEncyptionKey);
// Decrypt the data to a stream
CryptoStream cs = new CryptoStream( memoryToDecompress,
RMCrypto.CreateDecryptor(key, key),
CryptoStreamMode.Write);
byte [] fileBuffer = new byte[fin.Length];
fin.Read(fileBuffer, 0, fileBuffer.Length);
cs.Write(fileBuffer, 0, fileBuffer.Length);
fin.Close();
// Reset the index of the Memory Stream
memoryToDecompress.Position = 0;
// Let the GC clean this up, we still need the memory stream
//cs.Close();
// Decompress the File
ZipInputStream s;
s = new ZipInputStream(memoryToDecompress);
ZipEntry theEntry;
try
{
theEntry = s.GetNextEntry();
}
catch (System.Exception)
{
// Could not open the file...
return "";
}
}
I'm trying to create a python program to do the same. This is what I've got:
from Crypto.Cipher import AES
KEY = '01234567'.encode('utf-16be')
_f = open('<file>', 'r')
_content = _f.read()
_cipher = AES.new(KEY, AES.MODE_CBC, KEY)
_dcontent = _cipher.decrypt(_content)
with open('extract.zip', 'w') as newfile:
newfile.write(_dcontent)
_f.close()
I'm writing the result to the disk since I expect it to be a zip file (which contains one file). However I can't open the file with Archive Manager.
Any suggestions are welcome!
You have to use the same key. System.Text.UnicodeEncoding is the UTF-16le encoding which also has an equivalent in python:
KEY = '01234567'.encode('utf-16le')
You have to read and write the files in binary mode if you're on Windows:
_f = open('<file>', 'rb')
...
open('extract.zip', 'wb')
You should use the proper zip file library. I am guessing that is something format specific that is failing on your write statement. Using this library should avoid such drawbacks. The open function can take a password as optional in case it is protected.

Encrypt an existing zip file

I have an existing zip file, I want to use AESManaged class to encrypt it, but I don't find where I can set the password to the zip file in that class. After researching, I found some libaries such as 'DotNetZip' can complete the task. But my file is already a .zip, I needn't to compress again, I only want to encrypt it. Anyone can help me to use AESManaged class to ahieve the purpose?
Thanks
I don't know if this is what your are looking for but I created a code that encrypts any file.
Here's the code for the encrypter:
private void EncryptFile(string inputFile, string outputFile)
{
string password = #"yourPWhere";
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = CreateKey(password);
string cryptFile = outputFile;
FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create);
RijndaelManaged RMCrypto = new RijndaelManaged();
IV = CreateIV(password_mTxtBx.Text);
CryptoStream cs = new CryptoStream(fsCrypt,
RMCrypto.CreateEncryptor(key,IV),
CryptoStreamMode.Write);
FileStream fsIn = new FileStream(inputFile, FileMode.Open);
int data;
while ((data = fsIn.ReadByte()) != -1)
cs.WriteByte((byte)data);
fsIn.Close();
cs.Close();
fsCrypt.Close();
}
Here's the code for the decrypter:
private void DecryptFile(string inputFile, string outputFile)
{
string password = #"yourPWhere";
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = CreateKey(password);
FileStream fsCrypt = new FileStream(inputFile, FileMode.Open);
RijndaelManaged RMCrypto = new RijndaelManaged();
IV = CreateIV(password_mTxtBx.Text);
CryptoStream cs = new CryptoStream(fsCrypt,
RMCrypto.CreateDecryptor(key, IV),
CryptoStreamMode.Read);
FileStream fsOut = new FileStream(outputFile.Remove(outputFile.Length - 4), FileMode.Create);
int data;
while ((data = cs.ReadByte()) != -1)
fsOut.WriteByte((byte)data);
fsOut.Close();
cs.Close();
fsCrypt.Close();
}
I saw a similar code on codeproject a few months ago. So it's not directly my work.
Credits go to the author.
Updated with password-based key derivation (PBKDF2):
private static int saltLengthLimit = 32;
private static byte[] GetSalt(int maximumSaltLength)
{
var salt = new byte[maximumSaltLength];
using (var random = new RNGCryptoServiceProvider())
{
random.GetNonZeroBytes(salt);
}
return salt;
}
public static byte[] CreateKey(string password)
{
var salt = GetSalt(10);
int iterationCount = 20000; // Nowadays you should use at least 10.000 iterations
using (var rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt, iterationCount))
return rfc2898DeriveBytes.GetBytes(16);
}
Creator for the IV (created from Password):
public byte[] CreateIV(string password)
{
var salt = GetSalt(9);
const int Iterations = 325;
using (var rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt, Iterations))
return rfc2898DeriveBytes.GetBytes(16);
}
The byte length of the key is in my case 128bit(!) = 16 bytes (128/8), but you can use any other length supported by Rijndael (Key: 128, 192, 256 bit = 16, 24, 32 bytes).
The IV is always 16 bytes!
If you want to use a password in your original zip file when uncompressing, then you will need to re-compress the files and add a password when doing so.
This link from the dotnetzip library documentation shows an easy way to zip with password encryption using that library.
Additional note about security:
Don't use the zip 2.0 encryption method if you care at all about encryption security as it is quite flawed. Instead use the AES 256-bit encryption.
Here is some example code(pulled directly from the link above) showing an implementation of the AES 256-bit encryption using the dotnetzip library with default level compression:
using (ZipFile zip = new ZipFile())
{
zip.AddFile("ReadMe.txt"); // no password for this one
zip.Password= "Cool.Hand.Luke!";
zip.Encryption= EncryptionAlgorithm.WinZipAes256;
zip.AddFile("Rawdata-2008-12-18.csv");
zip.Save("Backup-AES-Encrypted.zip");
}
Edit: added clarification about original zip file
Edit 2: added code
You can use DotNetZip (Ionic zip) as you mentioned, which supports setting password, providing zero level of compression:
using (ZipFile zip = new ZipFile())
{
zip.CompressionLevel = Ionic.Zlib.CompressionLevel.None;
zip.AddFile(#"MyMusic\Messiah-01.mp3");
zip.Save(ZipFileToCreate);
}
So there's no overhead (compressing already compressed file) you just setting the password.

Categories

Resources