The program never prints out "test" unless I set a breakpoint on it and step over myself. I don't understand what's happening. Appreciate any help.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
string testKey = "lkirwf897+22#bbtrm8814z5qq=498j5";
string testIv = "741952hheeyy66#cs!9hjv887mxx7#8y";
string testValue = "random";
string encryptedText = EncryptRJ256(testKey, testIv, testValue);
string decryptedText = DecryptRJ256(testKey, testIv, encryptedText);
Console.WriteLine("encrypted: " + encryptedText);
Console.WriteLine("decrypted: " + decryptedText);
Console.WriteLine("test");
}
public static string DecryptRJ256(string key, string iv, string text)
{
string sEncryptedString = text;
RijndaelManaged myRijndael = new RijndaelManaged();
myRijndael.Padding = PaddingMode.Zeros;
myRijndael.Mode = CipherMode.CBC;
myRijndael.KeySize = 256;
myRijndael.BlockSize = 256;
byte[] keyByte = System.Text.Encoding.ASCII.GetBytes(key);
byte[] IVByte = System.Text.Encoding.ASCII.GetBytes(iv);
ICryptoTransform decryptor = myRijndael.CreateDecryptor(keyByte, IVByte);
byte[] sEncrypted = Convert.FromBase64String(sEncryptedString);
byte[] fromEncrypt = new byte[sEncrypted.Length + 1];
MemoryStream msDecrypt = new MemoryStream(sEncrypted);
CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);
return Encoding.ASCII.GetString(fromEncrypt);
}
public static string EncryptRJ256(string key, string iv, string text)
{
string sToEncrypt = text;
RijndaelManaged myRijndael = new RijndaelManaged();
myRijndael.Padding = PaddingMode.Zeros;
myRijndael.Mode = CipherMode.CBC;
myRijndael.KeySize = 256;
myRijndael.BlockSize = 256;
byte[] keyByte = Encoding.ASCII.GetBytes(key);
byte[] IVByte = Encoding.ASCII.GetBytes(iv);
ICryptoTransform encryptor = myRijndael.CreateEncryptor(keyByte, IVByte);
MemoryStream msEncrypt = new MemoryStream();
CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
byte[] toEncrypt = System.Text.Encoding.ASCII.GetBytes(sToEncrypt);
csEncrypt.Write(toEncrypt, 0, toEncrypt.Length);
csEncrypt.FlushFinalBlock();
byte[] encrypted = msEncrypt.ToArray();
return Convert.ToBase64String(encrypted);
}
}
edit:
Tried Debug.WriteLine
Debug.WriteLine("encrypted: " + encryptedText);
Debug.WriteLine("decrypted: " + decryptedText);
Debug.WriteLine("test");
Output:
encrypted: T4hdAcpP5MROmKLeziLvl7couD0o+6EuB/Kx29RPm9w=
decrypted: randomtest
Not sure why it's not printing the line terminator.
myRijndael.Padding = PaddingMode.Zeros;
myRijndael.BlockSize = 256;
This is the source of the problem, the data you encrypt gets padded with zeros to get a block size that's a multiple of 32 bytes (32 x 8 = 256). You get those binary zeros back in the decrypted value. Tricky about them is that the debugger cannot display them. Which is okayish, you expect the value to roundtrip through ASCII, you can remove the zeros again after decrypting. The decrypting code needs some work too, you assume too much about the size of the decrypted data. Fix:
MemoryStream fromEncrypt = new MemoryStream();
MemoryStream msDecrypt = new MemoryStream(sEncrypted);
CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
byte[] buffer = new byte[4096];
for (; ; ) {
int len = csDecrypt.Read(buffer, 0, buffer.Length);
if (len == 0) break;
fromEncrypt.Write(buffer, 0, len);
}
var result = Encoding.ASCII.GetString(fromEncrypt.GetBuffer(), 0, (int)fromEncrypt.Length);
return result.Trim('\0');
You ought to dispose the streams btw, use the using statement.
There is one issue in your encryption/decryption code: Since you are using PaddingMode.Zeros, after the decryption, you are not able to say where the original data ended, and you receive “random” followed by zero bytes. If you would switch to e.g. PaddingMode.PKCS7, and properly use the return value of the CryptoStream.Read call, you would receive just the original text, i.e. “random”:
var decryptedSize = csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);
return Encoding.ASCII.GetString(fromEncrypt, 0, decryptedSize);
Even though I think it shouldn’t be a problem to write NUL bytes to the console, I’d definitely try to remove them first, especially when seeing such strange behavior.
While this works for me using Mono on Linux, I do observe that decryptedText is 33 characters long - it consists of the characters 'r', 'a', 'n', 'd', 'o', 'm' followed 27 NUL characters. (I previously speculated that the padding bytes might be uninitialized, but looking at the code it looks like it is well-defined.) I would speculate that the console output window in Visual Studio interprets a NUL character as the end of output and thus stops printing anything else after that - including both the line terminator from WriteLine and the "test" string. I don't have Visual Studio here to test it, but I think you should be able to verify or disprove that easily enough.
Related
When I decrypt an encrypted username using AES encryption it shows a bunch of "\0\0\0" at the end of the decrypted username. Is there a way to not add these when encrypting?
The example code of the encryption and decryption:
string ky = xx_Convert.Base64ToString("RllhSzNjM09PZFAwT2RYMkdxOFI2cG9HYjVmWVIybnQ=");
string iv = xx_Convert.Base64ToString("Y2pZQmJsdVlqdlBYM0RtcXVleDJkNGNTa0FIYjhYQ2Y=");
string username = "test#mail.com";
string encriptedUsername = xx_Crypto.EncryptAES(ky, iv, username);
string encriptedPassword = xx_Crypto.EncryptAES(ky, iv, "password");
string decryptedUsername = xx_Crypto.DecryptAES(ky, iv, encriptedUsername);
string decryptedPassword = xx_Crypto.DecryptAES(ky, iv, encriptedPassword);
This gives the following result for decryptedUsername when inspecting the variable: "test#mail.com\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
This is likely a result of the Padding property of the encryption function.
In the Encryption function the Padding is set to Padding = PaddingMode.Zeros but when I remove this line it still pads the result but with other invisible characters.
Encryption function:
public static string EncryptAES(string keyString, string ivString, string
text)
{
RijndaelManaged myRijndael = new RijndaelManaged()
{
Padding = PaddingMode.Zeros,
Mode = CipherMode.CBC,
KeySize = 256,
BlockSize = 256
};
byte[] key = Encoding.UTF8.GetBytes(keyString);
byte[] IV = Encoding.UTF8.GetBytes(ivString);
ICryptoTransform encryptor = myRijndael.CreateEncryptor(key, IV);
byte[] encrypted = null;
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor,
CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(text);
}
encrypted = msEncrypt.ToArray();
}
}
return (Convert.ToBase64String(encrypted));
}
Edit: As requested here is the Decryption function:
public static string DecryptAES(string keyString, string ivString, string text)
{
var myRijndael = new RijndaelManaged()
{
Padding = PaddingMode.Zeros,
Mode = CipherMode.CBC,
KeySize = 256,
BlockSize = 256
};
byte[] key = Encoding.UTF8.GetBytes(keyString);
byte[] IV = Encoding.UTF8.GetBytes(ivString);
ICryptoTransform decryptor = myRijndael.CreateDecryptor(key, IV);
byte[] sEncrypted = Convert.FromBase64String(text);
byte[] fromEncrypt = new byte[sEncrypted.Length];
MemoryStream msDecrypt = new MemoryStream(sEncrypted);
CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);
return (Encoding.UTF8.GetString(fromEncrypt));
}
So is it possible to prevent this in the encryption function?
P.S: I did not use the same keys as in the original code
So is it possible to prevent this in the encryption function?
Yes, just use:
read = csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);
return (Encoding.UTF8.GetString(fromEncrypt, 0, read));
You are currently encoding the entire buffer. The padding bytes are removed but the bytes in the buffer are preset to zero during initialization when you created the buffer.
Note that zero padding isn't used much because if your plaintext ends with one or more zero bytes, those bytes may be removed. So some messages cannot be decrypted successfully this way (and cryptographers want to encrypt arbitrary messages, not just strings).
I am attempting to decrypt a file to ONLY the process memory. I do not want the actual file to be sent to plain text as it will be storing sensitive data. I do not want the raw text sitting on the system at all.
I am currently testing with a eula file in C:\ BUT get the same issue no matter what file I use.
I am using AES with salting. Decrypting the file does work as right now I am dumping the decrypted data to the text document but when I am attempting to compile the decrpytedBytes into a string, it only outputs 3 characters that are non-existent in that order anywhere inside of the document.
https://i.imgur.com/WAQ2njB.png
Those 2 characters show up while using System.Text.Encoding.UTF8.GetString(bytesDecrypted, 0, bytesDecrypted.Length) to compile the byte array to a string.
I have attempted just a basic .ToString() but that returned System.Byte[] and nothing more
https://i.imgur.com/Gg5Et72.png
While using var str = System.Text.Encoding.Default.GetString(bytesDecrypted) it only outputs ÿþ*
https://i.imgur.com/94hMuB3.png
Here is the code I am using for encryption and decryption
public static byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
{
byte[] encryptedBytes = null;
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
cs.Close();
}
encryptedBytes = ms.ToArray();
}
}
return encryptedBytes;
}
public static byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
byte[] decryptedBytes = null;
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
}
decryptedBytes = ms.ToArray();
}
}
return decryptedBytes;
}
public void EncryptFile(string file, string fileEncrypted, string password)
{
byte[] bytesToBeEncrypted = File.ReadAllBytes(file);
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
byte[] bytesEncrypted = AES_Encrypt(bytesToBeEncrypted, passwordBytes);
File.WriteAllBytes(fileEncrypted, bytesEncrypted);
listBox1.Items.Add("Enrypted the file");
}
public void DecryptFile(string fileEncrypted, string file, string password)
{
byte[] bytesToBeDecrypted = File.ReadAllBytes(fileEncrypted);
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
byte[] bytesDecrypted = AES_Decrypt(bytesToBeDecrypted, passwordBytes);
listBox1.Items.Add("Attempting Decryption");
File.WriteAllBytes(file, bytesDecrypted);
var str = System.Text.Encoding.Default.GetString(bytesDecrypted);
richTextBox1.Text = str;
}
If you have any idea/clues on how I could manage to get this working I would greatly appreciate it!
You used the incorrect encoding to to decode your decrypted byte array. The encoding of the original text file is most likely Unicode/UTF-16. Thus, use the Encoding.Unicode encoding to decode the decrypted byte array back to text:
var str = System.Text.Encoding.Unicode.GetString(bytesDecrypted);
Some background information
So, what made me think that the encoding of the original text file is UTF-16/Unicode?
This information from the question gives a crucial hint:
While using var str = System.Text.Encoding.Default.GetString(bytesDecrypted) it only outputs ÿþ*
Note the ÿþ. This is how an UTF-16 LE BOM (*) appears if text data having this BOM is decoded/shown using the ISO/IEC 8859-1 (or CP-1252) code page, which often is the default code page used in many (english/non-localized) Windows installations.
(*) The UTF-16 LE BOM (UTF-16 Little-Endian Byte Order Mark) are two bytes 0xFF,0xFE. To learn more about what BOMs are and what their purpose is, i suggest this Wikipedia article: https://en.wikipedia.org/wiki/Byte_order_mark
Found this answer that I think applies to your issue. Pay special attention to "encryptedData = output.ToArray();"
Reading from a cryptostream to the end of the stream
byte[] encryptedData;
rijCrypto.Padding = System.Security.Cryptography.PaddingMode.ISO10126;
rijCrypto.KeySize = 256;
using (var input = new MemoryStream(Encoding.Unicode.GetBytes(tempData)))
using (var output = new MemoryStream())
{
var encryptor = rijCrypto.CreateEncryptor();
using (var cryptStream = new CryptoStream(output, encryptor, CryptoStreamMode.Write))
{
var buffer = new byte[1024];
var read = input.Read(buffer, 0, buffer.Length);
while (read > 0)
{
cryptStream.Write(buffer, 0, read);
read = input.Read(buffer, 0, buffer.Length);
}
cryptStream.FlushFinalBlock();
encryptedData = output.ToArray();
}
}
I am trying to use a SSO solution in C#, where the documentation is only available in PHP.
I have this PHP Code:
function encrypt ($message)
{
$initialVector = "1234567890123456";
$key = md5($this->apiPassword);
$crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $message, MCRYPT_MODE_CFB, $initialVector);
return base64_encode($initialVector) .":" . base64_encode($crypt);
}
The C# Code I tried is the following:
private string encrypt(string message)
{
RijndaelManaged aes128 = new RijndaelManaged();
aes128.BlockSize = 128;
aes128.KeySize = 128;
aes128.Mode = CipherMode.CFB;
aes128.Padding = PaddingMode.None;
aes128.IV = Encoding.ASCII.GetBytes("1234567890123456");
aes128.Key = Encoding.ASCII.GetBytes(getMd5(key));
byte[] plainTextBytes = Encoding.ASCII.GetBytes(json);
ICryptoTransform encryptor = aes128.CreateEncryptor();
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write);
cs.Write(plainTextBytes, 0, plainTextBytes.Length);
// convert our encrypted data from a memory stream into a byte array.
byte[] cypherTextBytes = ms.ToArray();
// close memory stream
ms.Close();
return Convert.ToBase64String(aes128.IV) + ":" + Convert.ToBase64String(cypherTextBytes);
}
key and message are identical. The IV part is returned correctly, only the encrypted parts are not equal. The md5 method is also working correctly.
Edit: Changing the Padding also doesn't change anything.
I'm trying to read a file, encrypt it, and send it to a server over socket, where it is written. And then the other way around, read it on server, send it to client, decrypt it, and write it again.
My problem using C# Aes class is, that the input size doesn't equal the output size.
For example, when I read 4096 bytes from the file, the output size is 4112 bytes, 16 bytes more. OK, so 4112 bytes are sent and written on the server, but when I get the file again, I can only send a maximum of 4096 bytes over the socket, and then, of course, the decrypt function on client throws an exception, that the padding is invalid and cannot be removed. Sure I could try to read less bytes on the client, but that doesn't work as well.
I'm a very experienced C++ programmer, and I've done this with OpenSsl, and it worked like a charm. The input size has been always the output size, I don't know what is wrong with my functions in C#.
this is the sending part:
byte[] SendData = new byte[4096];
iBytesRead = FileRead.Read (SendData, 0, 4096);
SendData = aes.encrypt (Encoding.Default.GetString (SendData, 0, iBytesRead), iBytesRead);
String a = aes.decrypt (SendData); // no problems here because the size is correct
Socket.sendB (SendData, SendData.Length);
and the part of receiving from server:
byte[] WriteData = new byte[4096],
Temp;
if ((iBytesReceived = Socket.receiveB (ref WriteData)) == 0)
break;
if (Encoding.ASCII.GetString (WriteData, 0, iBytesReceived) == "end")
break;
for (uint i = 0; i < iBytesReceived; i++)
Temp[i] = WriteData[i];
byte[] a = Encoding.Default.GetBytes (aes.decrypt (Temp));
FileWrite.Write (a, 0, Temp.Length);
Aes functions:
public byte[] encrypt(String _InStr, int _InStrLength)
{
if (!bKeySet)
return ErrorReturn;
byte[] encrypted;
using (Aes aes = Aes.Create ())
{
aes.Key = Key;
aes.IV = IV;
//aes.Padding = PaddingMode.PKCS7;
//aes.BlockSize = 128;
//aes.KeySize = 128;
//aes.Mode = CipherMode.CFB;
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
// Create the streams used for encryption.
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs))
{
sw.Write(_InStr);
}
}
ms.Close ();
encrypted = ms.ToArray ();
}
}
return encrypted;
}
public String decrypt(byte[] _InStr)
{
if (!bKeySet)
return "";
String plaintext;
using (Aes aes = Aes.Create ())
{
aes.Key = Key;
aes.IV = IV;
//aes.Padding = PaddingMode.PKCS7;
//aes.BlockSize = 128;
//aes.KeySize = 128;
//aes.Mode = CipherMode.CBC;
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(_InStr))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
plaintext = srDecrypt.ReadToEnd ();
}
}
}
}
return plaintext;
}
As it was said, if any padding is used, the output will be aligned to a block size. However .Net doesn't want to work with incomplete blocks when PaddingMode.None is used. You should pad data yourself before encryption(decryption) and remove added bytes after.
One of the way to do this is to wrap ICryptoTransform passed to a CryptoStream
When I use the following class the output is padded.
public static string EncryptString(string ClearText) {
byte[] clearTextBytes = Encoding.UTF8.GetBytes(ClearText);
System.Security.Cryptography.SymmetricAlgorithm rijn = SymmetricAlgorithm.Create();
MemoryStream ms = new MemoryStream();
byte[] rgbIV = Encoding.ASCII.GetBytes("ryojvlzmdalyglrj");
byte[] key = Encoding.ASCII.GetBytes("hcxilkqbbhczfeultgbskdmaunivmfuo");
CryptoStream cs = new CryptoStream(ms, rijn.CreateEncryptor(key, rgbIV),
CryptoStreamMode.Write);
cs.Write(clearTextBytes, 0, clearTextBytes.Length);
cs.Close();
return Convert.ToBase64String(ms.ToArray());
}
public static string DecryptString(string EncryptedText)
{
byte[] encryptedTextBytes = Convert.FromBase64String(EncryptedText);
MemoryStream ms = new MemoryStream();
System.Security.Cryptography.SymmetricAlgorithm rijn = SymmetricAlgorithm.Create();
rijn.Mode = CipherMode.CFB;
byte[] rgbIV = Encoding.ASCII.GetBytes("ryojvlzmdalyglrj");
byte[] key = Encoding.ASCII.GetBytes("hcxilkqbbhczfeultgbskdmaunivmfuo"); ;
CryptoStream cs = new CryptoStream(ms, rijn.CreateDecryptor(key, rgbIV),
CryptoStreamMode.Write);
cs.Write(encryptedTextBytes, 0, encryptedTextBytes.Length);
cs.Close();
return Encoding.UTF8.GetString(ms.ToArray());
}
I understood from another post that there is
rijn.Padding = PaddingMode.None;
When I added this I get an error that says "Length of the data to encrypt is invalid"
Even when I try to encrypt a 6 byte string then I see get a long result.
var def1 = Encrypt.EncryptString("abcdefg");
gives me 24 bytes!
Can someone give me some advice here.
UPDATE
Changed to the following:
byte[] bytOut = ms.GetBuffer();
int i = 0;
for (i = 0; i < bytOut.Length; i++)
if (bytOut[i] == 0)
break;
// convert into Base64 so that the result can be used in xml
return System.Convert.ToBase64String(bytOut, 0, i);
When I check bytOut it's 16bytes Then the value returned after ToBase64 is 24 bytes. I am still not sure why the size is so large
Your problem is the mode of operation. The default is Cipher Block Chaining (CBC), which requires each block match up the block size of the algorithm, and padding to be used if necessary.
You can use another mode. Take CFB for example, it will internally pad your data before doing the plain ECB mode, and cut off the padding when it returns your result. (and do some clever stuff with the IVs so that you can continue to use the cipher without padding.) But it seems suitable for your case.
rijn.Mode = CipherMode.CFB;
Encryption algorithms work in blocks. It will always round up to the nearest block size. You just need a well-defined padding algorithm, so you can correctly remove the padding after decryption.