AES encryption and input string encoding - c#

Can someone explain me why these two pieces of code don't give the same result, and yet the StreamWriter in the 2nd example is using the UTF8 encoding:
var TokenEncryptKey = "D268197CF891452844441A143AAEAAEB";
var key = Encoding.UTF8.GetBytes(TokenEncryptKey);
var alg = new RijndaelManaged();
alg.Key = key;
alg.Mode = CipherMode.ECB;
var mem = new MemoryStream();
CryptoStream encryptStream = new CryptoStream(mem, alg.CreateEncryptor(), CryptoStreamMode.Write);
var validReservation = Encoding.UTF8.GetBytes("AAAAAAAAAAAAAAAAAAAAAAA");
encryptStream.Write(validReservation, 0, validReservation.Length);
encryptStream.Flush();
encryptStream.FlushFinalBlock();
Console.Out.WriteLine(Convert.ToBase64String(mem.GetBuffer(), 0, (int)mem.Length));
2nd Example
var TokenEncryptKey = "D268197CF891452844441A143AAEAAEB";
var key = Encoding.UTF8.GetBytes(TokenEncryptKey);
var alg = new RijndaelManaged();
alg.Key = key;
alg.Mode = CipherMode.ECB;
var mem = new MemoryStream();
CryptoStream encryptStream = new CryptoStream(mem, alg.CreateEncryptor(), CryptoStreamMode.Write);
StreamWriter sw = new StreamWriter(encryptStream, Encoding.UTF8);
sw.Write("AAAAAAAAAAAAAAAAAAAAAAA");
sw.Flush();
encryptStream.FlushFinalBlock();
Console.Out.WriteLine(Convert.ToBase64String(mem.GetBuffer(), 0, (int)mem.Length));

When you are using StreamWriter(encryptStream, Encoding.UTF8), this will add a Unicode BOM (byte order mark) of 3 bytes. To avoid that, use new StreamWriter(m, new UTF8Encoding()) instead.
Encoding.UTF8.GetBytes will not add the BOM even though the encoding is setup to do that - you can retrieve it if needed using GetPreamble instead.

Related

BlockSize must be 128 in this implementation

I'm using the following code to decrypt some strings I reicive but I'm getting the following error: BlockSize must be 128 in this implementation.
I would like to know if there is any way and how it would be possible to decrypt the strings I get without decreasing the size since I can't change my key and IV because the strings were encrypted with then.
private string Decrypt(string text)
{
var inputByteArray = Convert.FromBase64String(text);
var rm = new RijndaelManaged();
rm.BlockSize = 256;
rm.IV = Encoding.UTF8.GetBytes("11111111111111111111111111111111");
rm.KeySize = 256;
rm.Key = new SHA256Managed().ComputeHash(Encoding.UTF8.GetBytes("11111111-1111-1111-1111-111111111111"));
var decryptor = rm.CreateDecryptor();
var msDecrypt = new MemoryStream(inputByteArray);
var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
var srDecrypt = new StreamReader(csDecrypt);
return srDecrypt.ReadToEnd();
}
I'm using .netcore 5
to solve this problem i followed Topaco suggestion and used the BouncyCastle/C# library and that solved the error i was getting, below I leave the solution I used based on other forums.
public static string Decrypt(string cipherText)
{
var ivStringBytes = Encoding.UTF8.GetBytes("11111111111111111111111111111111");
var cipherTextBytes = Convert.FromBase64String(cipherText);
var keyBytes = new SHA256Managed().ComputeHash(Encoding.UTF8.GetBytes("11111111-1111-1111-1111-111111111111"));
var engine = new RijndaelEngine(256);
var blockCipher = new CbcBlockCipher(engine);
var cipher = new PaddedBufferedBlockCipher(blockCipher, new Pkcs7Padding());
var keyParam = new KeyParameter(keyBytes);
var keyParamWithIV = new ParametersWithIV(keyParam, ivStringBytes, 0, 32);
cipher.Init(false, keyParamWithIV);
var finalBytes = cipher.DoFinal(cipherTextBytes);
var final = Encoding.UTF8.GetString(finalBytes);
return final;
}
And this is the package that i used:
<PackageReference Include="BouncyCastle.NetCore" Version="1.8.10" />

Encryption Routine Not working, Can't figure out, subtle bug in it

All,
Please look at the code below. The encrypt, decrypt code doesn't work correctly.
When I pass in the string "Hello world" I get back "Hello wo". I always lose bytes and can't figure it out why. There has to be a reason for this, subtle bug?
private static void _TestEncryption2()
{
var testText = "Hello world";
var plainBytes = Encoding.Unicode.GetBytes(testText);
var cipher = Rijndael.Create();
cipher.Padding = PaddingMode.PKCS7;
//var _key = Convert.FromBase64String(KEY);
//var _IV = Convert.FromBase64String(IV);
var _key = cipher.Key;
var _IV = cipher.IV;
byte[] cipherBytes;
byte[] decryptedBytes;
var enc = cipher.CreateEncryptor(_key, _IV);
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, enc, CryptoStreamMode.Write))
{
cryptoStream.Write(plainBytes, 0, plainBytes.Length);
}
cipherBytes = memoryStream.ToArray();
}
var dec = cipher.CreateDecryptor(_key, _IV);
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, dec, CryptoStreamMode.Write))
{
cryptoStream.Write(cipherBytes, 0, cipherBytes.Length);
decryptedBytes = memoryStream.ToArray();
}
}
var decryptedText = Encoding.Unicode.GetString(decryptedBytes);
}
Dispose your second cryptoStream before doing memoryStream.ToArray():
var dec = cipher.CreateDecryptor(_key, _IV);
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, dec, CryptoStreamMode.Write))
{
cryptoStream.Write(cipherBytes, 0, cipherBytes.Length);
}
// Here
decryptedBytes = memoryStream.ToArray();
}
The problem is that the second CryptoStream hasn't been flushed before you read its output, and it's still holding onto that final block internally.
Your block size is 16 bytes, and you're using UTF-16 which uses 2 bytes per character, so the fact that you're getting the first block of 8 characters (16 bytes), but not the final block, makes sense here.
Also, Encoding.Unicode is UTF-16, which is a slightly odd choice in this day and age. Your default should be Encoding.UTF8.

I have the following code for encryption and decryption. I manage to encrypt the string but can not decrypt it back

Here the code for encryption
Did I code it correctly? or I need to make a change? I am using visual studio 2013 and framework 4.5.
cipherData = textBox_Plain_text.Text;
plainbytes = Encoding.Unicode.GetBytes(cipherData);
plainKey = Encoding.Unicode.GetBytes("0123456789abcded");
desObj.Key = plainKey;
desObj.Mode = CipherMode.CBC;
desObj.Padding = PaddingMode.PKCS7;
System.IO.MemoryStream ms = new System.IO.MemoryStream();
CryptoStream cs = new CryptoStream(ms, desObj.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(plainbytes, 0, plainbytes.Length);
cs.Close();
cipherbytes = ms.ToArray();
ms.Close();
textBox_Encrypted_text.Text = Encoding.ASCII.GetString(cipherbytes);
Here the code for decryption. After I try to decrypt it, only first letter show up
System.IO.MemoryStream ms1 = new System.IO.MemoryStream(cipherbytes);
CryptoStream cs1 = new CryptoStream(ms1, desObj.CreateDecryptor(), CryptoStreamMode.Read);
cs1.Read(cipherbytes, 0, cipherbytes.Length);
plainbytes2 = ms1.ToArray();
cs1.Close();
ms1.Close();
textBox_Decrypted_text.Text = Encoding.ASCII.GetString(plainbytes2);
Here the result

Encrypt/Decrypt a serialized file

Hey all I am trying to serialize a list of strings to a file, and then encrypt it.
Currently its just not working.
An unhandled exception of type 'System.Runtime.Serialization.SerializationException' occurred in mscorlib.dll
Additional information: Binary stream '199' does not contain a valid BinaryHeader. Possible causes are invalid stream or object version change between serialization and deserialization.
Then I need to decrypt and deseralize it. Heres what I have so far:
Encrypting and seralizing:
public void EncryptFile(FileInfo targetFile, string password, List<string> lines)
{
int SaltSize = 8;
var keyGenerator = new Rfc2898DeriveBytes(password, SaltSize);
var rijndael = Rijndael.Create();
// BlockSize, KeySize in bit --> divide by 8
rijndael.IV = keyGenerator.GetBytes(rijndael.BlockSize / 8);
rijndael.Key = keyGenerator.GetBytes(rijndael.KeySize / 8);
using (var fileStream = targetFile.Create())
{
// write random salt
fileStream.Write(keyGenerator.Salt, 0, SaltSize);
using (var cryptoStream = new CryptoStream(fileStream, rijndael.CreateEncryptor(), CryptoStreamMode.Write))
{
var bformatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
bformatter.Serialize(fileStream, lines);
}
}
}
And un-seralizing and decrypting:
int SaltSize = 8;
Dictionary<string, string> settings = new Dictionary<string, string>();
var fileStream = File.Open(SettingsFile, FileMode.Open);
var salt = new byte[SaltSize];
fileStream.Read(salt, 0, SaltSize);
// initialize algorithm with salt
var keyGenerator = new Rfc2898DeriveBytes("Y8LwUKQVJkqRz2ZAKsAMtFWY", salt);
var rijndael = Rijndael.Create();
rijndael.IV = keyGenerator.GetBytes(rijndael.BlockSize / 8);
rijndael.Key = keyGenerator.GetBytes(rijndael.KeySize / 8);
// decrypt
using (var cryptoStream = new CryptoStream(fileStream, rijndael.CreateDecryptor(), CryptoStreamMode.Read))
{
var bformatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
List<string> settingsList = (List<string>)bformatter.Deserialize(cryptoStream);
foreach (string setting in settingsList)
{
string[] bothWords = setting.Split(',');
settings.Add(bothWords[0], bothWords[1]);
}
}
The problem I see is that you aren't actually encrypting your data. The way I like to picture the encryption process is imagining a CryptoStream as a magical "portal" that encrypts/decrypts data. In order to encrypt or decrypt, you need to push or pull data through the "portal" from one side to the other.
A simple change to your encrypting code should do the trick:
Before
using (var fileStream = targetFile.Create())
{
// write random salt
fileStream.Write(keyGenerator.Salt, 0, SaltSize);
using (var cryptoStream = new CryptoStream(fileStream, rijndael.CreateEncryptor(), CryptoStreamMode.Write))
{
var bformatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
bformatter.Serialize(fileStream, lines);
}
}
After
using (var fileStream = targetFile.Create())
{
// write random salt
fileStream.Write(keyGenerator.Salt, 0, SaltSize);
using (var cryptoStream = new CryptoStream(fileStream, rijndael.CreateEncryptor(), CryptoStreamMode.Write))
{
var bformatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
bformatter.Serialize(cryptoStream, lines); //changed the input stream to 'cryptoStream'
cryptoStream.FlushFinalBlock(); //added a call to FlushFinalBlock
}
}
You can kinda imagine the relationships here between everything. The fileStream is behind the cryptoStream. The Serialize method is "pushing" the data from lines, through the cryptoStream (the "portal"), and into the fileStream.
As an aside, disposing of your IDisposable objects is fairly important. Make sure to either call Dispose() on them or (better yet) put them into a using statement. The Rfc2898DeriveBytes and Rijndael objects you are using aren't being disposed of.

Is there a .NET encryption library that implements AES 256 encryption as a Stream?

I'd like to be able to encrypt / decrypt data as it's streamed to/from disk.
I know I could write my own Stream and implement the encryption there, but I'd rather not risk doing it wrong. Is there a library that works in a similar way to the following code?
byte[] encryptionKey = ;
byte[] initVector = ;
var fileStream = new FileStream(filePath, FileMode.CreateNew, FileAccess.Write);
var encryptionStream = new AesEncryptionStream(fileStream, initVector, encryptionKey);
var gzStream = new GZipStream(encryptionStream, CompressionMode.Compress);
var writer = new BinaryWriter(gzStream);
You're looking for the RijndaelManaged and CryptoStream classes:
var aes = new RijndaelManaged { Key = ..., IV = ... };
using (var encryptor = aes.CreateEncryptor())
using (var cryptoStream = new CryptoStream(gzStream, encryptor, CryptoStreamMode.Write))
using (var writer = new BinaryWriter(cryptoStream)) {
...
}

Categories