How do I remove .net CryptoStream padding - c#

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.

Related

Lost character/s during encrypt-decrypt using rijindeal algorthm in c#

I have implement code Encrypt and Decrypt method. Input string value passed to encrypt method and get the encrypt value stored in xml file . after I getting encrypted value to read xml file using Decrypt Method to read value. I am getting Error in rare case(Encrypted input value is not correct and Decrypted output value). how do i resolve this Issue . Please share to me .
Here Sample code
public static string Decrypt(string cipherText)
{
try
{
string incoming = cipherText.Replace('_', '/').Replace('-', '+');
switch (cipherText.Length % 4)
{
case 2: incoming += "=="; break;
case 3: incoming += "="; break;
}
byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
byte[] cipherTextBytes = Convert.FromBase64String(incoming);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null);
byte[] keyBytes = password.GetBytes(keysize / 8);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);
MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
byte[] plainTextBytes = new byte[cipherTextBytes.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
catch (Exception ex)
{
return "Exception";
}
}
You are adding manually a padding to the end of the data, if you don't reverse that on the decipher then it would not work (it must be added after decripting as you did it before).
But, also, that padding is unnecessary, AES256 needs the data to be padded, yes, but the cryptostream will do that for you, so if you remove all that padding stuff it will work.
USE Trim() Function AND REMOVE ALL OF THE WHITE SPACES
This issue may occur when there are white spaces.
Use Trim() function to remove white spaces.
example -: cipherText.Trim()

AesCryptoServiceProvider throws Cryptographic exception

I am doing some project for school. I am having server client communication with TcpClient and TcpListener. At the begining I create AES key on server, and then send it to client using RSA. I have no problems here. However, when I try to encrypt string on client and then encrpyt it on server I get an exception.
Padding is invalid and cannot be removed
Server code:
Byte[] bytes = new Byte[1024];
String data = null;
clientStream.Read(bytes, 0, bytes.Length); // preberemo iz streama
//Array.Clear(bytes, 0, bytes.Length);
// string temp = Encoding.UTF8.GetString(bytes11);
//temp = temp.Replace("\0", "");
//yte[] bytes = Encoding.UTF8.GetBytes(temp);
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, aes.CreateDecryptor(aes.Key,aes.IV), CryptoStreamMode.Write))
{
//StreamWriter swEncrypt = new StreamWriter(csEncrypt);
csEncrypt.Write(bytes, 0, bytes.Length);
}
byte[] encrypted = msEncrypt.ToArray();
string enc = Encoding.UTF8.GetString(encrypted, 0, encrypted.Length);
}
Client code:
byte[] messg = Encoding.UTF8.GetBytes(messig);
// dobimo client stream
string enc = null;
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, aes.CreateEncryptor(aes.Key, aes.IV), CryptoStreamMode.Write))
{
csEncrypt.Write(messg,0,messg.Length);
}
byte[] encrypted = msEncrypt.ToArray();
enc = Encoding.UTF8.GetString(encrypted, 0, encrypted.Length);
}
byte[] data = new byte[1024];
data = Encoding.UTF8.GetBytes(enc);
//CryptoStream CryptStream = new CryptoStream(stream,aes.CreateEncryptor(aes.Key, aes.IV),CryptoStreamMode.Write);
stream.Write(data, 0, data.Length); // pošljem sporočilo
I get exception on server when trying to use
msEncrypt.ToArray();
However If I dinamically allocate Byte[], or I remove all the null values, I get an exception saying "the input data is not a complete block".
I have solved this using:
aes.Padding = PaddingMode.Zeros;
The problem is likely Encoding.UTF8.GetString(encrypted, 0, encrypted.Length);. That means the code treats bytes that can have any value as a text encoding. This means that if the bytes do not represent valid text that they will either change value (e.g. be substituted with question marks) or left out all together.
It is required to use base 64 encoding to treat the ciphertext as actual text. In this modern day and age, ciphertext is always binary (usually grouped in bytes).
Note that using PaddingMode.Zeros does not solve the problem. There may be information removed from the ciphertext if UTF-8 decoding is used. PaddingMode.Zeros only removes the exception, it doesn't solve the underlying problem of information loss.

C# DES ECB Encryption

I am having difficulty encrypting something in C#.
I have 3 variables.
First one is a 16 digit hex,lets call it X value I.E 0072701351979990
Second one is also a 16 digit hex value, lets call it Y I.E 3008168011FFFFFF
These two values have to be XOR 'ed to get the key for the DES-ECB encryption.
Thus resulting in 307a66934068666f . Now thus is my keyblock for the encryption.
Then i have this as my datablock,which is 64 bits for encryption 0E329232EA6D0D73
Now i have the following code for encryption this.
The result of the encryption should be XOR'ed with the datablock again and
result in a 64bit result. This is not the case.
This is my code for the encryption
$ public static string DESEncrypt(string keyBlock,string dataBlock){
DES desEncrypt = new DESCryptoServiceProvider();
byte[] keyBlockBytes = BitConverter.GetBytes(Convert.ToInt64(keyBlock, 16));
byte[] dataBlockBytes = BitConverter.GetBytes(Convert.ToInt64(dataBlock, 16));
desEncrypt.Mode = CipherMode.ECB;
desEncrypt.Key = keyBlockBytes;
ICryptoTransform transForm = desEncrypt.CreateEncryptor();
MemoryStream enecryptedStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(enecryptedStream, transForm, CryptoStreamMode.Write);
cryptoStream.Write(dataBlockBytes, 0, dataBlockBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] encryptedData = new byte[enecryptedStream.Length];
enecryptedStream.Position = 0;
enecryptedStream.Read(encryptedData, 0, encryptedData.Length);
string enCryptedHex = BitConverter.ToString(encryptedData);
return enCryptedHex.Replace("-","");
}
What am i doing wrong?
UPDATED QUESTION
I have tested the above solution from CodeInChaos.
It does give me back a 64 bit result. But still there is something wrong.
Here is my updated code.
The keyblock value is abababababababab
and the data block value is 215135734068666F.
The resultant 64 bit result should be XOR'ed with the data block again.
The final answer is suppose to be 414945DD33C97C47 but I get
288a08c01a57ed3d.
Why does it not come out right?
Here is the specifications in suppliers documentation for the encryption.
Encryption is DEA in accordance with FIPS 46-3, single DES in ECB mode, using a single 64-
bit DES Key with odd parity.
$ public static string DESEncrypt(string keyBlock,string dataBlock){
DES desEncrypt = new DESCryptoServiceProvider();
byte[] keyBlockBytes = BitConverter.GetBytes(Convert.ToInt64(keyBlock, 16));
byte[] dataBlockBytes = BitConverter.GetBytes(Convert.ToInt64(dataBlock, 16));
desEncrypt.Mode = CipherMode.ECB;
desEncrypt.Key = keyBlockBytes;
desEncrypt.Padding = PaddingMode.None;
ICryptoTransform transForm = desEncrypt.CreateEncryptor();
MemoryStream enecryptedStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(enecryptedStream, transForm, CryptoStreamMode.Write);
cryptoStream.Write(dataBlockBytes, 0, dataBlockBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] encryptedData = enecryptedStream.ToArray();
string enCryptedHex = BitConverter.ToString(encryptedData);
enCryptedHex = enCryptedHex.Replace("-", "");
long iDeaEncrypt = Convert.ToInt64(enCryptedHex, 16);
long iDataBlock = Convert.ToInt64(dataBlock, 16);
long decoderKey = iDeaEncrypt ^ iDataBlock;
string decKeyHex = Convert.ToString(decoderKey, 16);
return decKeyHex;
}
I think you need to set the padding to PaddingMode.None:
desEncrypt.Padding = PaddingMode.None;
But you should really think hard, if DES and ECB is really what you want.
b.t.w.
byte[] encryptedData = new byte[enecryptedStream.Length];
encryptedStream.Position = 0;
encryptedStream.Read(encryptedData, 0, encryptedData.Length);
can be replaced by:
encryptedData = encryptedStream.ToArray();
Perhaps it is necessary to set DES Provider to use the FIPS 46-3 Standard so that the DEA uses the permutation tables etc. specified in FIPS 46-3. Unfortunately I’m also struggling with this same issue.

C# Encrypt Text Output

I have created a few little programs that export data to a text file using StreamWriter and then I read them back in using StreamReader. This works great and does what I need it to do but I was wondering if there was a way that I could save this information without the user being able to access or modify it either intentionally or unintentionally. An example of something I would have in a text file would be if a checkbox was ticked, when you tick it it outputs "Ticked" to a text file, when the program is re - opened I know what state the form was in when it was closed. I obviously don't want to keep using text files. Does anyone have any ideas on how I can easily store this information without the user being able to modify it? Thank you very much.
The simplest way is to Base-64 encode/decode this text. This is not secure, but will prevent a casual user from modifying the data.
static public string EncodeTo64(string toEncode)
{
byte[] toEncodeAsBytes
= System.Text.ASCIIEncoding.ASCII.GetBytes(toEncode);
string returnValue
= System.Convert.ToBase64String(toEncodeAsBytes);
return returnValue;
}
static public string DecodeFrom64(string encodedData)
{
byte[] encodedDataAsBytes
= System.Convert.FromBase64String(encodedData);
string returnValue =
System.Text.ASCIIEncoding.ASCII.GetString(encodedDataAsBytes);
return returnValue;
}
EDIT: Real encryption
#region Encryption
string passPhrase = "Pasword"; // can be any string
string saltValue = "sALtValue"; // can be any string
string hashAlgorithm = "SHA1"; // can be "MD5"
int passwordIterations = 7; // can be any number
string initVector = "~1B2c3D4e5F6g7H8"; // must be 16 bytes
int keySize = 256; // can be 192 or 128
private string Encrypt(string data)
{
byte[] bytes = Encoding.ASCII.GetBytes(this.initVector);
byte[] rgbSalt = Encoding.ASCII.GetBytes(this.saltValue);
byte[] buffer = Encoding.UTF8.GetBytes(data);
byte[] rgbKey = new PasswordDeriveBytes(this.passPhrase, rgbSalt, this.hashAlgorithm, this.passwordIterations).GetBytes(this.keySize / 8);
RijndaelManaged managed = new RijndaelManaged();
managed.Mode = CipherMode.CBC;
ICryptoTransform transform = managed.CreateEncryptor(rgbKey, bytes);
MemoryStream stream = new MemoryStream();
CryptoStream stream2 = new CryptoStream(stream, transform, CryptoStreamMode.Write);
stream2.Write(buffer, 0, buffer.Length);
stream2.FlushFinalBlock();
byte[] inArray = stream.ToArray();
stream.Close();
stream2.Close();
return Convert.ToBase64String(inArray);
}
private string Decrypt(string data)
{
byte[] bytes = Encoding.ASCII.GetBytes(this.initVector);
byte[] rgbSalt = Encoding.ASCII.GetBytes(this.saltValue);
byte[] buffer = Convert.FromBase64String(data);
byte[] rgbKey = new PasswordDeriveBytes(this.passPhrase, rgbSalt, this.hashAlgorithm, this.passwordIterations).GetBytes(this.keySize / 8);
RijndaelManaged managed = new RijndaelManaged();
managed.Mode = CipherMode.CBC;
ICryptoTransform transform = managed.CreateDecryptor(rgbKey, bytes);
MemoryStream stream = new MemoryStream(buffer);
CryptoStream stream2 = new CryptoStream(stream, transform, CryptoStreamMode.Read);
byte[] buffer5 = new byte[buffer.Length];
int count = stream2.Read(buffer5, 0, buffer5.Length);
stream.Close();
stream2.Close();
return Encoding.UTF8.GetString(buffer5, 0, count);
}
#endregion
You should call ProtectedData.Protect to encrypt the data using a per-user key.
Note that it wouldn't be very hard for a skilled user to decrypt and modify the data.
Anything that your program does on the user's machine can be done by the user too.
You can add a checksum or hash to the file - if the file contents doesn't agree with the checksum, you know it was tampered with.
If it is important that users can't read the contents of the file, you can encrypt it.
I don't believe you can make a file that can't be tampered with (a savvy user could use a hex editor and change it, for example) - the best you can do is detect such tampering.
You can use the Ionic zip libraries to zip those text files. If necessary you could also use features of Ionic zip like password protection and encryption. And you'll still be able to open the file (with zipping applications like, for example, 7zip) manually yourself using the same settings you used to create it in the first place.
If a program can access the information, a user usually can too. However you can produce data the user will not immediately understand.
I would start by creating a class that holds all state information you want to save, isolating the problem. Coincidentally, the BinaryFormatter class will then allow you to easily save and load this class to/from a file. I don't know if it's results are "unreadable enough" - if not, apply Base64 encoding like Leon mentioned.
While you could base64 encode or even fully encrypt your configuration data (with SHA1 or MD5) as already suggested, I think good practice would be to work with the framework classes dealing with configuration data (Configuration under the System.Configuration namespace) and it's built in ability to encrypt data (via the ProtectSection method of the ConfigurationSection class).
First of all you should declare and initialize an instance:
using System.Configuration;
...
static void Main(string[] args)
{
Configuration config;
config = ConfigurationManager.OpenExeConfiguration(/*path to config file*/); //Use ConfigurationManager.OpenMachineConfiguration(/*path to config file*/) when opening machine configuration
...
After that you need to define a custom configuration section that defines your configuration (msdn example)
Once you've done that you just need to initialize an instance of your custom configuration section and add it to the configuration file using this code:
isTicked = config.Sections.Add("isTicked", customSection);
To encrypt the section you just added use this code (with further examples in both VB.NET and C# found here):
config.Sections["isTicked"].SectionInformation.ProtectSection("protection provider");
The "DPAPIProtectedConfigurationProvider" and "RSAProtectedConfigurationProvider" are built in by default.
Once you want to decrypt the section use this code:
config.Sections["isTicked"].SectionInformation.UnprotectSection();
To stress a point - encryption and decryption both take effect only after you save the configuration file
To save the file, use the code:
config.Save(); //config.SaveAs("string") is also available
Further information about the relevant classes and methods can be found in the msdn, starting with the Configuration class page linked above.
Try this code to encrypt and decrypt your text!
It is quite easy and strong I think...
public static class Crypto
{
private static readonly byte[] IVa = new byte[] { 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x11, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };
public static string Encrypt(this string text, string salt)
{
try
{
using (Aes aes = new AesManaged())
{
Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(Encoding.UTF8.GetString(IVa, 0, IVa.Length), Encoding.UTF8.GetBytes(salt));
aes.Key = deriveBytes.GetBytes(128 / 8);
aes.IV = aes.Key;
using (MemoryStream encryptionStream = new MemoryStream())
{
using (CryptoStream encrypt = new CryptoStream(encryptionStream, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
byte[] cleanText = Encoding.UTF8.GetBytes(text);
System.Diagnostics.Debug.WriteLine(String.Concat("Before encryption text data size: ", text.Length.ToString()));
System.Diagnostics.Debug.WriteLine(String.Concat("Before encryption byte data size: ", cleanText.Length.ToString()));
encrypt.Write(cleanText, 0, cleanText.Length);
encrypt.FlushFinalBlock();
}
byte[] encryptedData = encryptionStream.ToArray();
string encryptedText = Convert.ToBase64String(encryptedData);
System.Diagnostics.Debug.WriteLine(String.Concat("Encrypted text data size: ", encryptedText.Length.ToString()));
System.Diagnostics.Debug.WriteLine(String.Concat("Encrypted byte data size: ", encryptedData.Length.ToString()));
return encryptedText;
}
}
}
catch(Exception e)
{
return String.Empty;
}
}
public static string Decrypt(this string text, string salt)
{
try
{
using (Aes aes = new AesManaged())
{
Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(Encoding.UTF8.GetString(IVa, 0, IVa.Length), Encoding.UTF8.GetBytes(salt));
aes.Key = deriveBytes.GetBytes(128 / 8);
aes.IV = aes.Key;
using (MemoryStream decryptionStream = new MemoryStream())
{
using (CryptoStream decrypt = new CryptoStream(decryptionStream, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
byte[] encryptedData = Convert.FromBase64String(text);
System.Diagnostics.Debug.WriteLine(String.Concat("Encrypted text data size: ", text.Length.ToString()));
System.Diagnostics.Debug.WriteLine(String.Concat("Encrypted byte data size: ", encryptedData.Length.ToString()));
decrypt.Write(encryptedData, 0, encryptedData.Length);
decrypt.Flush();
}
byte[] decryptedData = decryptionStream.ToArray();
string decryptedText = Encoding.UTF8.GetString(decryptedData, 0, decryptedData.Length);
System.Diagnostics.Debug.WriteLine(String.Concat("After decryption text data size: ", decryptedText.Length.ToString()));
System.Diagnostics.Debug.WriteLine(String.Concat("After decryption byte data size: ", decryptedData.Length.ToString()));
return decryptedText;
}
}
}
catch(Exception e)
{
return String.Empty;
}
}
}
Just to add another implementation of Leon's answer, and following the
Microsoft docs
Here a class example that encrypts and decrypts strings
public static class EncryptionExample
{
#region internal consts
internal const string passPhrase = "pass";
internal const string saltValue = "salt";
internal const string hashAlgorithm = "MD5";
internal const int passwordIterations = 3; // can be any number
internal const string initVector = "0123456789abcdf"; // must be 16 bytes
internal const int keySize = 64; // can be 192 or 256
#endregion
#region public static Methods
public static string Encrypt(string data)
{
string res = string.Empty;
try
{
byte[] bytes = Encoding.ASCII.GetBytes(initVector);
byte[] rgbSalt = Encoding.ASCII.GetBytes(saltValue);
byte[] buffer = Encoding.UTF8.GetBytes(data);
byte[] rgbKey = new PasswordDeriveBytes(passPhrase, rgbSalt, hashAlgorithm, passwordIterations).GetBytes(keySize / 8);
RijndaelManaged managed = new RijndaelManaged();
managed.Mode = CipherMode.CBC;
ICryptoTransform transform = managed.CreateEncryptor(rgbKey, bytes);
byte[] inArray = null;
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, transform, CryptoStreamMode.Write))
{
csEncrypt.Write(buffer, 0, buffer.Length);
csEncrypt.FlushFinalBlock();
inArray = msEncrypt.ToArray();
res = Convert.ToBase64String(inArray);
}
}
}
catch (Exception ex)
{
Console.WriteLine("Encrypt " + ex);
}
return res;
}
public static string Decrypt(string data)
{
string res = string.Empty;
try
{
byte[] bytes = Encoding.ASCII.GetBytes(initVector);
byte[] rgbSalt = Encoding.ASCII.GetBytes(saltValue);
byte[] buffer = Convert.FromBase64String(data);
byte[] rgbKey = new PasswordDeriveBytes(passPhrase, rgbSalt, hashAlgorithm, passwordIterations).GetBytes(keySize / 8);
RijndaelManaged managed = new RijndaelManaged();
managed.Mode = CipherMode.CBC;
ICryptoTransform transform = managed.CreateDecryptor(rgbKey, bytes);
using (MemoryStream msEncrypt = new MemoryStream(buffer))
{
using (CryptoStream csDecrypt = new CryptoStream(msEncrypt, transform, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
res = srDecrypt.ReadToEnd();
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("Decrypt " + ex);
}
return res;
}
}
By the way, here is the "salt value" definition that I had googled to find out what it was.
Salt value
If an attacker does not know the password, and is trying to guess it with a brute-force attack, then every password he tries has to be tried with each salt value. So, for a one-bit salt (0 or 1), this makes the encryption twice as hard to break in this way.
Preventing unintentional string modification can be done using a checksum, as pointed in this answer.
However, it's quite easy to generate such a checksum, as they are not that many widely used algorithms.
Thus that doesn't protect you against intentional modification.
To prevent that, people use digital signatures. That allows anyone to verify your data hasn't be tampered, but only you (the owner of the private secret) can generate the signature.
Here is an example in C#.
However, as others pointed out, you need to embed your private key somewhere in your binary, and a (not so) skilled programmer will be able to retrieve it, even if you obfuscate your .net dll or you make that in a separate native process.
That would be enough for most concerns though.
If you are really concerned by security, then you need to move on the cloud, and execute the code on a machine you own.

Console.WriteLine Doesnt Display Line After Large Number of Binary Zeros

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.

Categories

Resources