"Padding is invalid and cannot be removed" when decrypting with Rijndael - c#

I'm trying to decrypt a string crypted with Rijndael algorythm. This type of cryptation apply a padding with "#" on the right of the Key and IV, if they are less than 16 characters long. The string to decrypt is received from a Webservice that sends it, and the Key, to me in XML SOAP Format. The IV is the Mac Address of my machine (that the server use as IV to encrypt the string). When i try to decrypt the received string, my program crash at this instruction:
while ((num5 = stream3.ReadByte()) != -1)
and it give to me this error "Padding is not valid and it cannot be removed".
I've searched this error on MSDN, and it says that it happen when the IV used to encrypt is different from the IV used to decrypt, but, i repeat, the IV is the MacAddress and it is the same everytime.
This is the sourcecode of Encrypt and Decrypt functions:
public static string Decrypt(string strInputString, string strKeyString, string myIV)
{
if ((strInputString == null) || (strInputString.Length == 0))
{
return strInputString;
}
try
{
int num5;
int keySize = 0x100;
int blockSize = 0x100;
int length = keySize / 0x10;
if (strKeyString.Length > length)
{
strKeyString = strKeyString.Substring(0, length);
}
if (strKeyString.Length < length)
{
strKeyString = strKeyString.PadRight(length, '#');
}
Encoding.Unicode.GetBytes(strKeyString);
if (myIV.Length > length)
{
myIV = myIV.Substring(0, length);
}
if (myIV.Length < length)
{
myIV = myIV.PadRight(length, '#');
}
Encoding.Unicode.GetBytes(myIV);
byte[] bytes = Encoding.Unicode.GetBytes(strKeyString);
byte[] rgbIV = Encoding.Unicode.GetBytes(myIV);
RijndaelManaged managed = new RijndaelManaged {
BlockSize = blockSize,
KeySize = keySize
};
MemoryStream stream = new MemoryStream();
for (int i = 0; i < strInputString.Length; i += 2)
{
stream.WriteByte(byte.Parse(strInputString.Substring(i, 2), NumberStyles.AllowHexSpecifier));
}
stream.Position = 0L;
MemoryStream stream2 = new MemoryStream();
CryptoStream stream3 = new CryptoStream(stream, managed.CreateDecryptor(bytes, rgbIV), CryptoStreamMode.Read);
while ((num5 = stream3.ReadByte()) != -1)
{
stream2.WriteByte((byte) num5);
}
stream3.Close();
stream2.Close();
stream.Close();
byte[] buffer3 = stream2.ToArray();
return Encoding.Unicode.GetString(buffer3);
}
catch (Exception exception)
{
Log.Error(exception.Message);
}
}
public static string Encrypt(string strInputString, string strKeyString, string myIV)
{
if ((strInputString == null) || (strInputString.Length == 0))
{
return strInputString;
}
try
{
int num4;
int keySize = 0x100;
int blockSize = 0x100;
int length = keySize / 0x10;
if (strKeyString.Length > length)
{
strKeyString = strKeyString.Substring(0, length);
}
if (strKeyString.Length < length)
{
strKeyString = strKeyString.PadRight(length, '#');
}
Encoding.Unicode.GetBytes(strKeyString);
if (myIV.Length > length)
{
myIV = myIV.Substring(0, length);
}
if (myIV.Length < length)
{
myIV = myIV.PadRight(length, '#');
}
Encoding.Unicode.GetBytes(myIV);
byte[] bytes = Encoding.Unicode.GetBytes(strKeyString);
byte[] rgbIV = Encoding.Unicode.GetBytes(myIV);
string str = "";
RijndaelManaged managed = new RijndaelManaged {
BlockSize = blockSize,
KeySize = keySize
};
MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(strInputString));
MemoryStream stream2 = new MemoryStream();
CryptoStream stream3 = new CryptoStream(stream2, managed.CreateEncryptor(bytes, rgbIV), CryptoStreamMode.Write);
while ((num4 = stream.ReadByte()) != -1)
{
stream3.WriteByte((byte) num4);
}
stream3.Close();
stream2.Close();
stream.Close();
foreach (byte num5 in stream2.ToArray())
{
str = str + num5.ToString("X2");
}
return str;
}
catch (Exception exception)
{
Log.Error(exception.Message);
}
}
}

Works fine for me with test code below - are you sure you're passing in the encrypted string for decryption ?
static void Main(string[] args)
{
string strInputString = "test";
string strKeyString = "test123";
string myIV = GetMacAddress();
string encryptedString = Encrypt(strInputString, strKeyString, myIV);
string decryptedString = Decrypt(encryptedString, strKeyString, myIV);
}
public static string Decrypt(string strInputString, string strKeyString, string myIV)
{
if ((strInputString == null) || (strInputString.Length == 0))
{
return strInputString;
}
int num5;
int keySize = 0x100;
int blockSize = 0x100;
int length = keySize / 0x10;
if (strKeyString.Length > length)
{
strKeyString = strKeyString.Substring(0, length);
}
if (strKeyString.Length < length)
{
strKeyString = strKeyString.PadRight(length, '#');
}
Encoding.Unicode.GetBytes(strKeyString);
if (myIV.Length > length)
{
myIV = myIV.Substring(0, length);
}
if (myIV.Length < length)
{
myIV = myIV.PadRight(length, '#');
}
Encoding.Unicode.GetBytes(myIV);
byte[] bytes = Encoding.Unicode.GetBytes(strKeyString);
byte[] rgbIV = Encoding.Unicode.GetBytes(myIV);
RijndaelManaged managed = new RijndaelManaged
{
BlockSize = blockSize,
KeySize = keySize
};
MemoryStream stream = new MemoryStream();
for (int i = 0; i < strInputString.Length; i += 2)
{
stream.WriteByte(byte.Parse(strInputString.Substring(i, 2), NumberStyles.AllowHexSpecifier));
}
stream.Position = 0L;
MemoryStream stream2 = new MemoryStream();
CryptoStream stream3 = new CryptoStream(stream, managed.CreateDecryptor(bytes, rgbIV), CryptoStreamMode.Read);
while ((num5 = stream3.ReadByte()) != -1)
{
stream2.WriteByte((byte)num5);
}
stream3.Close();
stream2.Close();
stream.Close();
byte[] buffer3 = stream2.ToArray();
return Encoding.Unicode.GetString(buffer3);
}
public static string Encrypt(string strInputString, string strKeyString, string myIV)
{
if ((strInputString == null) || (strInputString.Length == 0))
{
return strInputString;
}
int num4;
int keySize = 0x100;
int blockSize = 0x100;
int length = keySize / 0x10;
if (strKeyString.Length > length)
{
strKeyString = strKeyString.Substring(0, length);
}
if (strKeyString.Length < length)
{
strKeyString = strKeyString.PadRight(length, '#');
}
Encoding.Unicode.GetBytes(strKeyString);
if (myIV.Length > length)
{
myIV = myIV.Substring(0, length);
}
if (myIV.Length < length)
{
myIV = myIV.PadRight(length, '#');
}
Encoding.Unicode.GetBytes(myIV);
byte[] bytes = Encoding.Unicode.GetBytes(strKeyString);
byte[] rgbIV = Encoding.Unicode.GetBytes(myIV);
string str = "";
RijndaelManaged managed = new RijndaelManaged
{
BlockSize = blockSize,
KeySize = keySize
};
MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(strInputString));
MemoryStream stream2 = new MemoryStream();
CryptoStream stream3 = new CryptoStream(stream2, managed.CreateEncryptor(bytes, rgbIV), CryptoStreamMode.Write);
while ((num4 = stream.ReadByte()) != -1)
{
stream3.WriteByte((byte)num4);
}
stream3.Close();
stream2.Close();
stream.Close();
foreach (byte num5 in stream2.ToArray())
{
str = str + num5.ToString("X2");
}
return str;
}
private static string GetMacAddress()
{
string macAddresses = "";
foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
{
if (nic.OperationalStatus == OperationalStatus.Up)
{
macAddresses += nic.GetPhysicalAddress().ToString();
break;
}
}
return macAddresses;
}

Padding is probably Pkcs#5. Instead of #, pad with a byte value that is the number of bytes to pad.
So if you have 5 bytes to pad, padding bytes will be 0505050505, if you need to pad 2 bytes, padding will be 0202 .

I don't think that the IV is the issue. It's the password itself. I suspect that the password used by the server to encrypt is not the password being used by the client to decrypt.
The only way I could reproduce the crash the OP was reporting was by passing in an incorrect password to the Decrypt() method. Passing in an IV that was just slightly incorrect wouldn't throw an exception. For example, I encrypted with the IV as a MAC address in caps and using colons, and then decrypted with the IV as the same MAC address in lower case and using dashes. -- first few bytes were scrambled, but by about byte 16 everything was started matching up with the plain text original.

Are you using the same character encoding as the original string at the time of encryption?
I had a similar issue... the difference, in the end, was how i was passing the data (string) to be encrypted. If I copy/pasted into a textbox, the encryption was different than if i hardcoded into the program. So in short... the encoding of the original data makes a big difference. While the characters may look the same, in reality they could be represented quite differently (8 bytes, 16 bytes, etc).
Find out how the original string was encoded prior to the encryption algorithm (maybe check on the IV parameter encodings as well.

Related

Hex input to SHA256 hash

online hash code can be obtained from this site with SHA256.
https://emn178.github.io/online-tools/sha256.html
The hash code of 1 is "6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b"
but if we make the hash code input type of 1 hex, "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a" comes out.
I can do the first one in c# code, but I couldn't find a c# code that can do the second one. Could you help?
static string ComputeSha256Hash(string rawData)
{
// Create a SHA256
using (SHA256 sha256Hash = SHA256.Create())
{
// ComputeHash - returns byte array
byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData));
// Convert byte array to a string
StringBuilder builder = new StringBuilder();
for (int i = 0; i < bytes.Length; i++)
{
builder.Append(bytes[i].ToString("x2"));
}
return builder.ToString();
}
}
Please try this, the key is convert hex to bytes.
public static byte[] StringToByteArray(string hex)
{
int len = hex.Length;
//the stackoverflow answer assumes you have even length,
//so I insert a 0 if odd length.
if (len % 2 == 1)
{
hex = hex.Insert(0, "0");
}
return Enumerable.Range(0, len)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}
static string ComputeSha256Hash(string rawData)
{
using (SHA256 sha256Hash = SHA256.Create())
{
byte[] bytes = sha256Hash.ComputeHash(StringToByteArray(rawData));
StringBuilder builder = new StringBuilder();
for (int i = 0; i < bytes.Length; i++)
{
builder.Append(bytes[i].ToString("x2"));
}
return builder.ToString();
}
}
static void Main(string[] args)
{
string hash = ComputeSha256Hash("1");
Console.WriteLine(hash);
Console.ReadKey();
}

C# encrypt code and c++ encrypt code is not matching

I'm implementing encrypt/decrypt code with c++/c#
I referred to this post and referred to answers.z`
But c++/c# encrypted code was not matched.
Here are my codes.
C++
// base64 encode part
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(BYTE c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
std::string base64_encode(BYTE const* buf, unsigned int bufLen) {
std::string ret;
int i = 0;
int j = 0;
BYTE char_array_3[3];
BYTE char_array_4[4];
while (bufLen--) {
char_array_3[i++] = *(buf++);
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (i = 0; (i < 4); i++)
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
if (i)
{
for (j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
ret += base64_chars[char_array_4[j]];
while ((i++ < 3))
ret += '=';
}
return ret;
}
//start encrypt
std::string key = "01286567891233460123456789a12345";
std::string iv = "0123456789123456";
std::string encrypt(const std::string& str_in)
{
std::string str_out;
std::string str_out2;
byte* keybyte = (byte*)key.c_str();
CryptoPP::AES::Encryption aesEncryption((byte*)key.c_str(), CryptoPP::AES::MAX_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, (byte*)iv.c_str());
StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink(str_out));
stfEncryptor.Put(reinterpret_cast<const unsigned char*>(str_in.c_str()), str_in.length() + 1);
stfEncryptor.MessageEnd();
str_out2 = base64_encode(reinterpret_cast<const unsigned char*>(str_out.c_str()), strlen(str_out.c_str()));
return str_out2;
}
std::string decrypt(const std::string& cipher_text)
{
std::string str_out;
//need to insert code of decrypt base64
CryptoPP::AES::Decryption aesDecryption((byte*)key.c_str(), CryptoPP::AES::MAX_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, (byte*)iv.c_str());
CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink(str_out));
stfDecryptor.Put(reinterpret_cast<const unsigned char*>(cipher_text.c_str()), cipher_text.size());
stfDecryptor.MessageEnd();
return str_out;
}
c#
public string Encrypt(string testCode)
{
string clearText = testCode;
byte[] clearBytes = Encoding.Default.GetBytes(clearText);
using (Aes encryptor = Aes.Create("AES"))
{
//encryptor.BlockSize = 128;
encryptor.Padding = PaddingMode.Zeros;
encryptor.KeySize = 128;
encryptor.Mode = CipherMode.CBC;
encryptor.Key = Encoding.Default.GetBytes("01286567891233460123456789a12345");
encryptor.IV = Encoding.Default.GetBytes("0123456789123456");
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
byte[] bt = ms.ToArray();
clearText = Convert.ToBase64String(bt); //clearText = Encoding.Default.GetString(bt);
}
}
return clearText; //Return the encrypted command
}
public string Decrypt(string cipherText)
{
byte[] clearBytes = Convert.FromBase64String(cipherText);
using (Aes decryptor = Aes.Create("AES"))
{
// decryptor.BlockSize = 128;
decryptor.Padding = PaddingMode.Zeros;
decryptor.KeySize = 128;
decryptor.Mode = CipherMode.CBC;
decryptor.Key = Encoding.Default.GetBytes("01286567891233460123456789a12345");
decryptor.IV = Encoding.Default.GetBytes("0123456789123456");
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, decryptor.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
byte[] bt = ms.ToArray();
cipherText = Encoding.Default.GetString(bt);
}
}
return cipherText; //Return the decrypted text
}
c++ result
encrypted code : ks8zzu20w6zURkuZMgbx8g==
decrypted code : test
c# result
encrypted code : nsWRYBylyjVaJ5Yckk+SRw==
decrypted code : test
I tested with test word both of C++/C# however encrypted code was not matched.
Also, I tested after remove base64 encode code but pure encrypted code was not matched as well.
Could anyone please share your knowledge?
EDIT1
I tried to copy encrypted code by c++ and pasted to c# decrypt code like below
string testcode = "ks8zzu20w6zURkuZMgbx8g=="
Decrypt(testcode)
//result - test↗↗↗↗↗
As you can see, the results look very similar, but there is something weird.
↗ This symbol is added after the word test.
I could not found out why result like this. Is there something I missed?
Solved
std::string encrypt(const std::string& str_in)
{
std::string str_out;
std::string str_out2;
byte* keybyte = (byte*)key.c_str();
CryptoPP::AES::Encryption aesEncryption((byte*)key.c_str(), CryptoPP::AES::MAX_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, (byte*)iv.c_str());
StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink(str_out));
// 'str_in.length() + 1' in the line below makes the encryption code different from c# code.
/*stfEncryptor.Put(reinterpret_cast<const unsigned char*>(str_in.c_str()), str_in.length() + 1);*/
stfEncryptor.Put(reinterpret_cast<const unsigned char*>(str_in.c_str()), str_in.length());
stfEncryptor.MessageEnd();
str_out2 = cryptobase64_encode(str_out);
return str_out2;
}
As I commented, str_in.length() + 1 makes the encrypted code different from C# code.
And I changed C# padding options from Zeros to PKCS7 for matching c++ encrypted code.
But I don't know why I need to set this option. I think I need to study this.
Anyway, It works well. Special thanks to #jdweng.

Find bytes from an offset

So I have this:
public static long FindPosition(Stream stream, byte[] byteSequence)
{
if (byteSequence.Length > stream.Length)
return -1;
byte[] buffer = new byte[byteSequence.Length];
using (BufferedStream bufStream = new BufferedStream(stream, byteSequence.Length))
{
int i;
while ((i = bufStream.Read(buffer, 0, byteSequence.Length)) == byteSequence.Length)
{
if (byteSequence.SequenceEqual(buffer))
return bufStream.Position - byteSequence.Length;
else
bufStream.Position -= byteSequence.Length - PadLeftSequence(buffer, byteSequence);
}
}
return -1;
}
private static int PadLeftSequence(byte[] bytes, byte[] seqBytes)
{
int i = 1;
while (i < bytes.Length)
{
int n = bytes.Length - i;
byte[] aux1 = new byte[n];
byte[] aux2 = new byte[n];
Array.Copy(bytes, i, aux1, 0, n);
Array.Copy(seqBytes, aux2, n);
if (aux1.SequenceEqual(aux2))
return i;
i++;
}
return i;
}
Which works perfectly to get an offset that has a specific set of bytes, but now I want to do the inverse, find a set of bytes from a specific offset.
How can I do that?
Try this example:
long offset = 100L; // Offset
int bytesCount = 20; // Number of bytes to read
byte[] buffer = new byte[bytesCount];
stream.Seek( offset, SeekOrigin.Begin ); // Set offset from Begin of a stream
stream.Read( buffer, 0, bytesCount ); // Read bytesCount from previous set offset
More detail about Seek and Read

How to convert from decimal to binary invert it with ~ and convert back to decimal

Not sure if I am in the right direction.
I can't find info about tilde.
int n = 5;
int m = ~n;
string numAsString = Convert.ToString(~n, 2);
char[] NumAsChar = numAsString.ToCharArray();
long l = Convert.ToInt64(numAsString, 2);
Console.WriteLine(numAsString);
Console.WriteLine(l);
You're probably looking for a simple answer.
int n = 5;
byte[] nbytes = BitConverter.GetBytes(n);
for(int i = 0 ; i < nbytes.Length; i++)
nbytes[i] = ~nbytes[i];
n = BitConverter.ToInt32(nbytes, 0);
edit: you actually can't do ~ on a byte[]. You can either do
for(int i = 0 ; i < nbytes.Length; i++)
nbytes[i] = ~nbytes[i];
or just not use a byte array at all.
For clarity's sake, do note that you can just do
n = ~n;
and skip doing any of the separation. But you specifically asked for the byte conversion.
Use these 2 methods
static byte[] GetBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
static string GetString(byte[] bytes)
{
char[] chars = new char[bytes.Length / sizeof(char)];
System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
return new string(chars);
}
And then use them like this
byte[] bytes = GetTheBytes(str);
byte[] reversed = bytes.Reverse().ToArray();
var revStr = GetString(reversed)
I did it like this.Any suggestions on making it simpler.
int n = 100;
//Convert decimal to binary
string numAsString = Convert.ToString(n, 2);
char[] NumAsChar = numAsString.ToCharArray();
Console.WriteLine(numAsString);
//Invert bits
for (int i = 0; i < numAsString.Length; i++)
{
if (NumAsChar[i] == '0')
{
NumAsChar[i] = '1';
}
else
{
NumAsChar[i] = '0';
}
}
string NewNumAsString = new string(NumAsChar);
//Convert inverted binary num to decimal
long l = Convert.ToInt64(NewNumAsString, 2);
Console.WriteLine(NewNumAsString);
Console.WriteLine(l);

Encode decoded string with Base64String

I am learning how to encode and decode string. This is a method to decode chiper text to plain text I found around the web.
public static string Decode(string chiperText)
{
byte[] numArray = Convert.FromBase64String(chiperText);
byte[] numArray1 = new byte[(int)numArray.Length - 1];
byte num = (byte)(numArray[0] ^ 188);
for (int i = 1; i < (int)numArray.Length; i++)
{
numArray1[i - 1] = (byte)(numArray[i] ^ 188 ^ num);
}
return Encoding.ASCII.GetString(numArray1);
}
My problem is I have no idea how to encode to original state. I try this method and it doesn't work.
public static string Encode(string plainText)
{
byte[] bytes = Encoding.ASCII.GetBytes(plainText);
byte[] results = new byte[(int)bytes.Length - 1];
byte num = (byte)(bytes[0] ^ 188);
for (int i = 1; i < bytes.Length; i++)
{
results[i - 1] = (byte)(bytes[i] ^ 188 ^ num);
}
return Convert.ToBase64String(results);
}
Although I agree entirely with SLaks comment that the above does not constitute any kind of crypto that you should use, the following procedure will produce the "encrypted" data that you are looking to decrypt:
public static string Encode(string plainText)
{
byte[] numArray = System.Text.Encoding.Default.GetBytes(plainText);
byte[] numArray1 = new byte[(int)numArray.Length + 1];
// Generate a random byte as the seed used
(new Random()).NextBytes(numArray1);
byte num = (byte)(numArray1[0] ^ 188);
numArray1[0] = numArray1[0];
for (int i = 0; i < (int)numArray.Length; i++)
{
numArray1[i + 1] = (byte)(num ^ 188 ^ numArray[i]);
}
return Convert.ToBase64String(numArray1);
}
Please do not, for a single second, consider using this as a method for 'encrypting' sensitive data.

Categories

Resources