TRIPLEDES padding is invalid and cannot be removed. c# decrypt - c#

I have a problem when performing a decryption in TRIPLEDES that a provider sends me in HEX: EF69FF79BBD7E8E4EF69FF79BBD7E8E4 with the following key "0123456789ABCDEFFEDCBA9876543210", applying the following method:
public IActionResult GetTokenTemp1()
{
TripleDESCryptoServiceProvider tDESalg = new TripleDESCryptoServiceProvider();
MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
tDESalg.Key = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes("0123456789ABCDEFFEDCBA9876543210"));
byte[] cipherBytes = Convert.FromBase64String("EF69FF79BBD7E8E4EF69FF79BBD7E8E4");
string finalDecrypt = _3desTest.DecryptTextFromMemory(cipherBytes, tDESalg.Key, tDESalg.IV);
return Ok(finalDecrypt);
}
public static string DecryptTextFromMemory(byte[] Data, byte[] Key, byte[] IV)
{
try
{
// Create a new MemoryStream using the passed
// array of encrypted data.
MemoryStream msDecrypt = new MemoryStream(Data);
TripleDESCryptoServiceProvider de = new TripleDESCryptoServiceProvider();
var descritor = de.CreateDecryptor(Key, IV);
// Create a CryptoStream using the MemoryStream
// and the passed key and initialization vector (IV).
CryptoStream csDecrypt = new CryptoStream(msDecrypt,
descritor,
CryptoStreamMode.Read);
// Create buffer to hold the decrypted data.
byte[] fromEncrypt = new byte[Data.Length];
// Read the decrypted data out of the crypto stream
// and place it into the temporary buffer.
csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);
string es = new UTF8Encoding().GetString(fromEncrypt);
//Convert the buffer into a string and return it.
return new UTF8Encoding().GetString(fromEncrypt);
}
catch (CryptographicException e)
{
Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);
return null;
}
}
When I leave the default padding or any other to zero or none, I get the following error "adding is invalid and cannot be removed.",
but when I leave the padding at zero or none tripleDescryptorService.Padding = PaddingMode.None I get a format:
padding.none
I don't know what to do very well, when I do it on this page:
https://neapay.com/online-tools/des-calculator.html?data=EF69FF79BBD7E8E4EF69FF79BBD7E8E4&key=0123456789ABCDEFFEDCBA9876543210&algo=3DES&decr=true
I get the desired result.
I'm already desperate, I'm not very expert in encryption.
Thank you so much

The website uses neither a padding nor an IV. Therefore in the code the padding must be disabled and the ECB mode must be applied.
Furthermore the website expects a hex encoded key and ciphertext and returns the decrypted data also hex encoded, which therefore must not be UTF-8 decoded in the code:
public static byte[] DecryptTextFromMemory(byte[] encryptedData, byte[] key)
{
using (TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider())
{
tripleDES.Key = key;
tripleDES.Padding = PaddingMode.None;
tripleDES.Mode = CipherMode.ECB;
byte[] decryptedData = new byte[encryptedData.Length];
using (MemoryStream msDecrypt = new MemoryStream(encryptedData))
{
ICryptoTransform decryptor = tripleDES.CreateDecryptor(tripleDES.Key, null);
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
csDecrypt.Read(decryptedData, 0, decryptedData.Length);
}
}
return decryptedData;
}
}
For the hex encoding and decoding you can use arbitrary methods, e.g. from here.
With this the code:
byte[] data = HexStringToByteArray("EF69FF79BBD7E8E4EF69FF79BBD7E8E4");
byte[] key = HexStringToByteArray("0123456789ABCDEFFEDCBA9876543210");
Console.WriteLine(ByteArrayToHexString(DecryptTextFromMemory(data, key)));
returns the result of the website:
00000000003331720000000000333172
Please note: Your last change is not useful because it applies conversions and algorithms that are not consistent with the website.

Related

Padding-related CryptographicException in previously working code

I have a program which stores encrypted text data. Whenever new data is added, the encrypted data is loaded from file, decrypted, the new string data is appended, and finally the data is re-encrypted and saved to disk. This used to work until recently, now however I get a CryptographicException: Padding is invalid and cannot be removed when decrypting the loaded data. This is the code I use to encrypt/decrypt the data:
public static byte[] Encrypt(string text, byte[] key) {
byte[] encrypted;
byte[] IV;
using (var aes = Aes.Create()) {
aes.Key = key;
aes.GenerateIV();
IV = aes.IV;
aes.Mode = CipherMode.CBC;
var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using (var msEncrypt = new MemoryStream())
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) {
using (var swEncrypt = new StreamWriter(csEncrypt)) {
swEncrypt.Write(text);
}
encrypted = msEncrypt.ToArray();
}
}
// return plaintext IV and encrypted text payload concatenated
return IV.Concat(encrypted).ToArray();
} // Encrypt()
public static string Decrypt(byte[] bytes, byte[] key) {
string plaintext = null;
using (var aes = Aes.Create()) {
aes.Key = key;
// split iv and encryped cyphertext
byte[] IV = new byte[aes.BlockSize / 8];
byte[] cipherText = new byte[bytes.Length - IV.Length];
Array.Copy(bytes, IV, IV.Length);
Array.Copy(bytes, IV.Length, cipherText, 0, cipherText.Length);
aes.IV = IV;
aes.Mode = CipherMode.CBC;
var decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using (var msDecrypt = new MemoryStream(cipherText))
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
using (var srDecrypt = new StreamReader(csDecrypt)) {
plaintext = srDecrypt.ReadToEnd();
// !!! EXCEPTION HAPPENS HERE !!!
}
}
return plaintext;
}
The encrypted byte[] array is read/written using plain File.ReadAllBytes / File.WriteAllBytes.
I tried to change the the code to read byte by byte until an exception occurs, which gave me the decrypted text minus 16 bytes. However, only the first third contained valid text, the rest was a few garbled bytes, followed by a (equally garbled) 16 byte sequence, repeated over and over. This makes me suspect that some kind of corruption occurred during a previous save operation.
Any help would be greatly appreciated, regarding to recovering the data (if possible) and pointing out problems/bugs in the encryption/decryption code (if any).

How is encryption done without encoding the string to byte[]?

I've been trying to understand encryption/decryption code of TripleDES for some days. And I have seen many codes in the google, and the code shown below is one of them.
static void Main(string[] args)
{
string original = "Here is some data to encrypt!";
TripleDESCryptoServiceProvider myTripleDES = new TripleDESCryptoServiceProvider();
byte[] encrypted = EncryptStringToBytes(original, myTripleDES.Key, myTripleDES.IV);
string encrypt = Convert.ToBase64String(encrypted);
string roundtrip = DecryptStringFromBytes(encrypted, myTripleDES.Key, myTripleDES.IV);
Console.WriteLine("encryted: {0}", encrypt);
Console.WriteLine("Round Trip: {0}", roundtrip);
Console.ReadLine();
}
static byte[] EncryptStringToBytes(string plainText, byte[] Key, byte[] IV)
{
byte[] encrypted;
using (TripleDESCryptoServiceProvider tdsAlg = new TripleDESCryptoServiceProvider())
{
tdsAlg.Key = Key;
tdsAlg.IV = IV;
ICryptoTransform encryptor = tdsAlg.CreateEncryptor(tdsAlg.Key, tdsAlg.IV);
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
return encrypted;
}
static string DecryptStringFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
{
string plaintext = null;
using (TripleDESCryptoServiceProvider tdsAlg = new TripleDESCryptoServiceProvider())
{
tdsAlg.Key = Key;
tdsAlg.IV = IV;
ICryptoTransform decryptor = tdsAlg.CreateDecryptor(tdsAlg.Key, tdsAlg.IV);
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
There is no error in the code. I works fine. But strangely I noticed that the plainText is never been encoded. There is no line like Encoding.Unicode.GetBytes(plainText); or Encoding.UTF8.GetBytes(plainText); or similar like that. So, my question is , how does (in the code) the plainText which is a string gets converted to the encrypted byte? Is there any work done inside the streams? If thats so then where and how? As far as I understood there is no such line in between the streams that converts the string to byte. So , How does the overall code is working without this basic transformation?
Update:
Is this code really a valid code?
You are sending the plaintext to the encryption stream in the line swEncrypt.Write(plaintext). This does the byte conversion.
The StreamWriter is doing the encoding. The constructor being used specifies UTF-8 encoding:
This constructor creates a StreamWriter with UTF-8 encoding without a
Byte-Order Mark (BOM)

Rijndael Encryption | Padding is invalid and cannot be removed

Im new to cryptography and im not quite sure what im doing wrong here,
public static byte[] EncryptData(byte[] data, string keystr)
{
if (keystr.Length > 32)
keystr = keystr.Substring(0, 32);
else
while (keystr.Length != 32)
keystr += "0";
byte[] iv = Encoding.UTF8.GetBytes(SALT);
byte[] key = Encoding.UTF8.GetBytes(keystr);
using (MemoryStream memoryStream = new MemoryStream())
{
using (RijndaelManaged rijndaelManaged = new RijndaelManaged { Key = key, IV = iv, Padding = PaddingMode.PKCS7, Mode = CipherMode.CBC })
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, rijndaelManaged.CreateEncryptor(key, iv), CryptoStreamMode.Write))
{
cryptoStream.Write(data, 0, data.Length);
}
}
return memoryStream.ToArray();
}
}
public static byte[] DecryptData(byte[] data, string keystr)
{
if (keystr.Length > 32)
keystr = keystr.Substring(0, 32);
else
while (keystr.Length != 32)
keystr += "0";
byte[] iv = Encoding.UTF8.GetBytes(SALT);
byte[] key = Encoding.UTF8.GetBytes(keystr.ToUpper());
using (MemoryStream memoryStream = new MemoryStream())
{
using (RijndaelManaged rijndaelManaged = new RijndaelManaged { Key = key, IV = iv, Padding = PaddingMode.PKCS7, Mode = CipherMode.CBC })
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, rijndaelManaged.CreateDecryptor(key, iv), CryptoStreamMode.Write))
{
cryptoStream.Write(data, 0, data.Length);
}
}
return memoryStream.ToArray();
}
}
As you can see im passing in a byte array and a password. i make sure the password is always 32 chars.
Im getting Padding is invalid and cannot be removed. when i decrypt data.
The key and salt is always the same.
The key may be passed in the same to both methods, but for some reason, after you've thrown away more entropy (for longer strings) or padded out the key (for shorter strings), for some reason you do this:
keystr.ToUpper()
But only for the decryption side. So the keys being used are different.
I'd strongly suggest that you don't call ToUpper. Other suggestions would be to probably not have a fixed salt/IV and to allow both the iv and the key to be passed as byte arrays also, rather than strings. Encryption naturally deals with byte arrays, and putting wrapper methods like these in place that actually encourage weaker encryption is probably a bad idea.

How to decrypt an AES-256-CBC encrypted string

I'm new to C# and I really need help. I need to encrypt/decrypt a string with AES-256-CBC in C#, I found this to encrypt a string:
public static string EncryptString(string message, string KeyString, string IVString)
{
byte[] Key = ASCIIEncoding.UTF8.GetBytes(KeyString);
byte[] IV = ASCIIEncoding.UTF8.GetBytes(IVString);
string encrypted = null;
RijndaelManaged rj = new RijndaelManaged();
rj.Key = Key;
rj.IV = IV;
rj.Mode = CipherMode.CBC;
try
{
MemoryStream ms = new MemoryStream();
using (CryptoStream cs = new CryptoStream(ms, rj.CreateEncryptor(Key, IV), CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs))
{
sw.Write(message);
sw.Close();
}
cs.Close();
}
byte[] encoded = ms.ToArray();
encrypted = Convert.ToBase64String(encoded);
ms.Close();
}
catch (CryptographicException e)
{
Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);
return null;
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine("A file error occurred: {0}", e.Message);
return null;
}
catch (Exception e)
{
Console.WriteLine("An error occurred: {0}", e.Message);
}
finally
{
rj.Clear();
}
return encrypted;
}
I tried to write a decrypt function base on the above code, the following code is what I did:
// Decrypt a byte array into a byte array using a key and an IV
private byte[] Decrypt(byte[] cipherData, byte[] Key, byte[] IV)
{
byte[] decryptedData;
//string plaintext = null;
//MemoryStream ms = new MemoryStream(cipherData);
RijndaelManaged alg = new RijndaelManaged();
alg.KeySize = 256;
alg.BlockSize = 128;
alg.Key = Key;
alg.IV = IV;
alg.Mode = CipherMode.CBC;
alg.Padding = PaddingMode.Zeros;
//Array.Copy(Key, 0, IV, 0, IV.Length);
ICryptoTransform decryptor = alg.CreateDecryptor(alg.Key, alg.IV);
using(MemoryStream ms = new MemoryStream(cipherData))
{
using (CryptoStream csDecrypt = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
using (StreamReader sw = new StreamReader(csDecrypt))
{
sw.ReadToEnd();
sw.Close();
}
csDecrypt.Close();
decryptedData = ms.ToArray();
}
}
//byte[] decryptedData = System.Text.Encoding.Unicode.GetBytes(plaintext);
return decryptedData;
}
But it's nonsense, it can't decrypt anything. I'm really confused and need help. Thank you for any help!
P/s: Please don't give me other similar answered questions, I already take a look at them. Their encrypt function doesn't have the same output like the above encrypt function, while I need to decrypt string which MUST be encrypt by the above function. I have two friend who wrote decrypt function in PHP and objective-C, which matched with the above encrypt function, it's bad to have them do it again.
Looking at your encryption, something like this should do it, passing the resulting string from your encryption in should give the original string back;
// Decrypt a string into a string using a key and an IV
public static string Decrypt(string cipherData, string keyString, string ivString)
{
byte[] key = Encoding.UTF8.GetBytes(keyString);
byte[] iv = Encoding.UTF8.GetBytes(ivString);
try
{
using (var rijndaelManaged =
new RijndaelManaged {Key = key, IV = iv, Mode = CipherMode.CBC})
using (var memoryStream =
new MemoryStream(Convert.FromBase64String(cipherData)))
using (var cryptoStream =
new CryptoStream(memoryStream,
rijndaelManaged.CreateDecryptor(key, iv),
CryptoStreamMode.Read))
{
return new StreamReader(cryptoStream).ReadToEnd();
}
}
catch (CryptographicException e)
{
Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);
return null;
}
// You may want to catch more exceptions here...
}
A small note; you're getting the key using UTF8 encoding from the key string, UTF8 encoding may give you multiple bytes back for international characters, which may give a key or IV of the wrong length for encryption/decryption. Also, using the small range of passwords/keys with 8 characters and printable characters will not give you very secure encryption, you may want to run the string though SHA1 or similar before using it as a key (which will sadly make it incompatible with the current encryption)

Decrypted data with usage of TripleDESCryptoServiceProvider has additonal characters

I am facing with problem when decrypting data with usage of TripleDESCryptoServiceProvider. The problem is that decrypted value contains beside of original value some additional, strange characters at the end
Per instance if I provide "rastko" to be encrypted, I will get later with decryption something like this "rastko⥊㮶". For other values it could be different number of 'dummy' characters or in some cases I will get exact value.
Then, I saw that for all encrypted data byte array size is divisible by 8. It looks like any provided data is rounded on value that is divisible by 8. Only in case when original encoded value is divisible by 8, decryption will retrieve appropriate value.
Here are methods that I am using :
public static byte[] EncryptPassword(string password, out byte[] cryptoKey, out byte[] cryptoIV)
{
try
{
UnicodeEncoding unicodeEncoding = new UnicodeEncoding();
byte[] unicodePassword = unicodeEncoding.GetBytes(password);
byte[] encryptedPassword;
using (TripleDESCryptoServiceProvider tripleDes = new TripleDESCryptoServiceProvider())
{
tripleDes.Key = GetCryptoKey();
tripleDes.Mode = CipherMode.CBC;
tripleDes.Padding = PaddingMode.PKCS7;
cryptoKey = tripleDes.Key;
cryptoIV = tripleDes.IV;
using (MemoryStream memoryStream = new MemoryStream())
{
ICryptoTransform cryptoTransform = tripleDes.CreateEncryptor();
using (
CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write))
{
cryptoStream.Write(unicodePassword, 0, unicodePassword.Length);
////cryptoStream.FlushFinalBlock();
}
encryptedPassword = memoryStream.ToArray();
}
}
return encryptedPassword;
}
catch (Exception ex)
{
throw new Exception("Password encryption failed !", ex);
}
}
public static string DecryptPassword(byte[] encryptedPassword, byte[] cryptoKey, byte[] cryptoIV)
{
try
{
UnicodeEncoding unicodeEncoding = new UnicodeEncoding();
string readablePassword;
using (TripleDESCryptoServiceProvider tripleDes = new TripleDESCryptoServiceProvider())
{
tripleDes.Key = cryptoKey;
tripleDes.IV = cryptoIV;
tripleDes.Mode = CipherMode.CBC;
tripleDes.Padding = PaddingMode.PKCS7;
// Create a new MemoryStream using the passed
// array of encrypted data.
using (MemoryStream memoryStream = new MemoryStream(encryptedPassword))
{
// Create crypto transform that defines the basic operations of cryptographic transformations.
ICryptoTransform cryptoTransform = tripleDes.CreateDecryptor();
// Create a CryptoStream using the MemoryStream and the passed key and initialization vector (IV).
using (CryptoStream decryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write))
{
decryptoStream.Write(encryptedPassword, 0, encryptedPassword.Length);
///decryptoStream.FlushFinalBlock();
}
byte[] decryptedPassword = memoryStream.ToArray();
//Convert the buffer into a string and return it.
readablePassword = unicodeEncoding.GetString(decryptedPassword, 0, decryptedPassword.Length);
}
}
return readablePassword;
}
catch (Exception ex)
{
throw new Exception("Password decryption failed !", ex);
}
}
private static byte[] GetCryptoKey()
{
UnicodeEncoding unicodeEncoding = new UnicodeEncoding();
string plainKey = "rastkoisajev2310982josipasenera153";
byte[] encodedKey = unicodeEncoding.GetBytes(plainKey);
// Prepares 192 bit key
byte[] preparedKey = new byte[24];
Array.Copy(encodedKey, preparedKey, 24);
return preparedKey;
}
Here is sample test invocation :
private static void CryptoTest()
{
string password = "rastko";
byte[] cryptoKey;
byte[] cryptoIV;
byte[] encryptedPassword = Crypto.EncryptPassword(password, out cryptoKey, out cryptoIV);
string decryptedPAssword = Crypto.DecryptPassword(encryptedPassword, cryptoKey, cryptoIV);
}
I have not good experience with security. What I see is that IV vector is 8byte size and as I found it is related to BlockSize, that is 8times greater then IV size. TripleDESCryptoServiceProvider for IV vector is using 8byte value. I can not change this.
Could you please tell me what I have to do or did I wrote something wrongly ?
DES is a 64 bit block cypher. Any text that does not divide cleanly into 64 bit (=8 byte) blocks needs to be padded to make up a whole number of blocks. You need to set padding for encryption and decryption. If you have control of both ends then use PKCS#5 padding to encrypt and decrypt. If you only have control over the decryption end, then ask the encrypting end what padding they are using and expect that.
Note that encrypting a password is normally not the way to go. Use PBKDF2 instead. Don't confuse passwords and keys!
Try to make sure that your CryptoStreams get closed or flushed:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.cryptostream.flushfinalblock.aspx
If you don't then the padding/unpadding will likely not be performed, and you get trash instead.
After detail investigation I have found the solution for my problem.
I have changed a little bit decryption logic.
Instead of this part in DecryptPassword method :
// Create a CryptoStream using the MemoryStream and the passed key and initialization vector (IV).
using (CryptoStream decryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write))
{
decryptoStream.Write(encryptedPassword, 0, encryptedPassword.Length);
///decryptoStream.FlushFinalBlock();
}
byte[] decryptedPassword = memoryStream.ToArray();
//Convert the buffer into a string and return it.
readablePassword = unicodeEncoding.GetString(decryptedPassword, 0, decryptedPassword.Length);
}
I am now using the Read logic from CryptoStream and then I am just removing nullable characters. It is like this now :
// Create a CryptoStream using the MemoryStream and the passed key and initialization vector (IV).
using (CryptoStream decryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Read))
{
// Create buffer to hold the decrypted data.
byte[] fromEncrypt = new byte[encryptedPassword.Length];
decryptoStream.Read(fromEncrypt, 0, fromEncrypt.Length);
//Convert the buffer into a string and return it.
readablePassword = unicodeEncoding.GetString(fromEncrypt);
readablePassword = readablePassword.Replace("\0", string.Empty);
}
This works perfectly for me ! Thank you all for your time.

Categories