I want to decrypt an Encrypted Sting using AES/CBC/Nopadding in c# Windows Phone 8 application. My string is in file of IsolatedSorage. I pasted the string HERE which is junk.
From this Article I am using AesManaged class to decrypt.
But how to set padding to NoPadding because by default the padding set to PKCS7 from here.
string fileName = "titlepage.xhtml";
if (fileStorage.FileExists(fileName))
{
IsolatedStorageFileStream someStream = fileStorage.OpenFile(fileName, System.IO.FileMode.Open, FileAccess.Read);
using (StreamReader reader = new StreamReader(someStream))
{
str1 = reader.ReadToEnd();
MessageBox.Show(str1);
try
{
string text = Decrypt(str1, "****************", "****************");
MessageBox.Show(text);
}
catch (CryptographicException cryptEx)
{
MessageBox.Show(cryptEx.Message, "Encryption Error", MessageBoxButton.OK);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "General Error", MessageBoxButton.OK);
}
}
}
public string Decrypt(string dataToDecrypt, string password, string salt)
{
AesManaged aes = null;
MemoryStream memoryStream = null;
try
{
//Generate a Key based on a Password and HMACSHA1 pseudo-random number generator
//Salt must be at least 8 bytes long
//Use an iteration count of at least 1000
Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, Encoding.UTF8.GetBytes(salt), 10000);
//Create AES algorithm
aes = new AesManaged();
//Key derived from byte array with 32 pseudo-random key bytes
aes.Key = rfc2898.GetBytes(32);
//IV derived from byte array with 16 pseudo-random key bytes
aes.IV = rfc2898.GetBytes(16);
//Create Memory and Crypto Streams
memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, aes.CreateDecryptor(), CryptoStreamMode.Write);
byte[] data = Convert.FromBase64String(dataToDecrypt);
cryptoStream.Write(data, 0, data.Length);
cryptoStream.FlushFinalBlock();
//Return Decrypted String
byte[] decryptBytes = memoryStream.ToArray();
//Dispose
if (cryptoStream != null)
cryptoStream.Dispose();
//Retval
return Encoding.UTF8.GetString(decryptBytes, 0, decryptBytes.Length);
}
finally
{
if (memoryStream != null)
memoryStream.Dispose();
if (aes != null)
aes.Clear();
}
}
Edit 1:
When I am decrypting my Encrypted string in thins line
byte[] data = Convert.FromBase64String(dataToDecrypt);
Moving to Finally block and getting exception of The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters in decrypted string.
It is bit of confuse on this which is supported class to Decrypt in windows phone.
If I am completely wrong suggest me url of article regarding algorithm in Windows Phone
Edit 2:
As Below answer suggested " I am getting cyperText as bytes it is fine in decryption side. But it is giving an exception with the description
[Cryptography_SSD_InvalidDataSize]
Arguments:
Debugging resource strings are unavailable. Often the key and arguments provide
sufficient information to diagnose the problem
I believe that problem is IV[salt key] or setting padding to AesManged.
But I can't change padding property to AesManaged in Windows Phone.
By default padding to AesManged is PKCS7. I want to change to NoPadding. Because my cyperText is encrypted using AES/CBC/NoPadding algorithm "
If I understand the problem, you have data that is already encrypted in AES CBC mode, with no padding. But on the phone where you want to decrypt the data, the only option you have is PKCS#7 padding.
Well, you are in luck! You can decrypt the ciphertext using PKCS#7 padding. All you need to do is add the padding to the ciphertext, on the phone, and then decrypt it.
To add padding after the fact, you will encrypt a small bit of data and append it to the ciphertext. Then, you decrypt the modified ciphertext, and take that small bit of data off, and you have the original plaintext.
Here is how you do it:
Take a ciphertext on the phone. This is a multiple of 16 bytes, even if there is no padding. There is no other possibility -- AES ciphertext is always a multiple of 16 bytes.
Take the LAST 16 bytes of the ciphertext aside, and set that as the IV of your AES ENCRYPT. (Encrypt, not decrypt.) Use the same key as you are going to use to decrypt later.
Now encrypt something smaller than 16 bytes, for example, the character '$'. The phone is going to add PKCS#7 padding to this.
Append the resulting 16-bytes of ciphertext to the original ciphertext from step 1, and you now have a properly PKCS#7-padded ciphertext which includes the original plaintext plus the added '$'.
Use the original IV, and the same key, and now DECRYPT this combined ciphertext. You can now remove the '$' that will appear at the end of your plaintext (or whatever you added in step 3.)
When the small bit is encrypted with the last 16-bytes of the original ciphertext, you are actually extending the ciphertext in true AES CBC mode, and you happen to be doing that with PKCS#7 padding, so you can now decrypt the whole thing and take the small bit off. You will have the original plaintext which had no padding.
I thought this would be interesting to show in code:
var rfc2898 = new Rfc2898DeriveBytes("password", new byte[8]);
using (var aes = new AesManaged())
{
aes.Key = rfc2898.GetBytes(32);
aes.IV = rfc2898.GetBytes(16);
var originalIV = aes.IV; // keep a copy
// Prepare sample plaintext that has no padding
aes.Padding = PaddingMode.None;
var plaintext = Encoding.UTF8.GetBytes("this plaintext has 32 characters");
byte[] ciphertext;
using (var encryptor = aes.CreateEncryptor())
{
ciphertext = encryptor.TransformFinalBlock(plaintext, 0, plaintext.Length);
Console.WriteLine("ciphertext: " + BitConverter.ToString(ciphertext));
}
// From this point on we do everything with PKCS#7 padding
aes.Padding = PaddingMode.PKCS7;
// This won't decrypt -- wrong padding
try
{
using (var decryptor = aes.CreateDecryptor())
{
var oops = decryptor.TransformFinalBlock(ciphertext, 0, ciphertext.Length);
}
}
catch (Exception e)
{
Console.WriteLine("caught: " + e.Message);
}
// Last block of ciphertext is used as IV to encrypt a little bit more
var lastBlock = new byte[16];
var modifiedCiphertext = new byte[ciphertext.Length + 16];
Array.Copy(ciphertext, ciphertext.Length - 16, lastBlock, 0, 16);
aes.IV = lastBlock;
using (var encryptor = aes.CreateEncryptor())
{
var dummy = Encoding.UTF8.GetBytes("$");
var padded = encryptor.TransformFinalBlock(dummy, 0, dummy.Length);
// Set modifiedCiphertext = ciphertext + padded
Array.Copy(ciphertext, modifiedCiphertext, ciphertext.Length);
Array.Copy(padded, 0, modifiedCiphertext, ciphertext.Length, padded.Length);
Console.WriteLine("modified ciphertext: " + BitConverter.ToString(modifiedCiphertext));
}
// Put back the original IV, and now we can decrypt...
aes.IV = originalIV;
using (var decryptor = aes.CreateDecryptor())
{
var recovered = decryptor.TransformFinalBlock(modifiedCiphertext, 0, modifiedCiphertext.Length);
var str = Encoding.UTF8.GetString(recovered);
Console.WriteLine(str);
// Now you can remove the '$' from the end
}
}
The string you linked to is not Base-64. It looks as if it is raw encrypted bytes, interpreted as characters. Either work on the encryption side to output a Base-64 string encoding of the raw bytes or else work on the decryption side to read the cyphertext as raw bytes, not as text, and forget about removing the Base-64.
Generally better to work on the encryption side since passing Base-64 text is a lot less error-prone than passing raw bytes.
Related
I'm trying to decrypt a Rijndael-128 encrypted cipher, these are the values:
Cipher: "QfJzZ9V6Jm43jYPiVaXP9mu+f88S/JC24saHbOMxxC8="
Key: "45744855535472525844494538555934",
Mode: CBC
Result should be: "abcd#1234"
This website seems to decrypt the cipher just fine:
https://codebeautify.org/encrypt-decrypt
I'm trying to do the same thing in C# with absolutely no luck, what am I missing here?
class Program
{
static void Main(string[] args)
{
var text = Decrypt("QfJzZ9V6Jm43jYPiVaXP9mu+f88S/JC24saHbOMxxC8=", Convert.FromBase64String("45744855535472525844494538555934"));
}
public static string Decrypt(string Text, byte[] keyBytes)
{
var textBytes = Convert.FromBase64String(Text);
var rijKey = new RijndaelManaged();
rijKey.IV = textBytes.Take(rijKey.BlockSize / 8).ToArray();
rijKey.Padding = PaddingMode.None;
rijKey.Mode = CipherMode.CBC;
var decryptor = rijKey.CreateDecryptor(keyBytes, rijKey.IV);
var memoryStream = new MemoryStream(textBytes);
var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
var pTextBytes = new byte[textBytes.Length];
var decryptedByteCount = cryptoStream.Read(pTextBytes, 0, pTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
string plainText = Encoding.UTF8.GetString(pTextBytes, 0, decryptedByteCount);
return plainText;
}
}
The problem with your code is this line:
rijKey.GenerateIV();
You need the original IV. You can't just use a random one.
If you go to the site you linked to, each time you press encrypt with the key and text you have given, you get a different encrypted text (because a random IV is used). The web page must be prepending the random IV used to encrypt to the encrypted text (or less likely, the web page is storing it), which is why it can then decrypt the encrypted text.
[Your code also needs using statements.]
Is it possible to NOT use the IV when implementing Rijndael decryption?
How to Use Rijndael ManagedEncryption with C#
I have this code in CryptoJS, inside browser:
var decrypt = function (cipherText) {
var key = "a_long_key_goes_here";
var iv = "initial_vector_goes_here";
key = CryptoJS.enc.Hex.parse(key);
iv = CryptoJS.enc.Hex.parse(iv);
var decrypted = CryptoJS.TripleDES.decrypt({
ciphertext: CryptoJS.enc.Hex.parse(cipherText)
}, key, {
iv: iv,
mode: CryptoJS.mode.CBC
});
var clearText = decrypted.toString(CryptoJS.enc.Utf8);
return clearText;
};
This code is not written by me. Also the cipherText come from another server that I have no access to. However, I have access to key and to iv.
I can decrypt that cipherText inside a browser's console. But I want to use these keys to decrypt that cipherText inside C# code. Here's the code I've written:
public void Desrypt()
{
ICryptoTransform decryptor;
UTF8Encoding encoder;
string key = "a_long_key_goes_here";
string iv = "initial_vector_goes_here";
var cipherText = "cipher_text_goes_here";
string clearText = "";
byte[] cipherBytes = FromHexString(cipherText);
using (Aes aes = Aes.Create())
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(key, new byte[] { });
aes.Key = pdb.GetBytes(32);
aes.IV = pdb.GetBytes(16);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(cipherBytes, 0, cipherBytes.Length);
cs.Close();
}
clearText = Encoding.Unicode.GetString(ms.ToArray());
}
}
return clearText;
}
public static byte[] FromHexString(string hexString)
{
var bytes = new byte[hexString.Length / 2];
for (var i = 0; i < bytes.Length; i++)
{
bytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
}
return bytes;
}
I have some problems though. I don't understand if I'm correctly decoding the given cipherText from hexadecimal or not. Also I can't instantiate Rfc2898DeriveBytes, because I don't know what the second parameter (salt) should be.
Also I don't know where should I use that iv I've gotten from the CryptoJS code.
Could you please help?
So that both codes are compatible, the following changes of the C# code are necessary:
The return type of the Decrypt method must be changed from void to string.
Key and IV have to be decoded hexadecimal like the ciphertext with FromHexString.
Instead of AES, TripleDES must be used.
Rfc2898DeriveBytes implements PBKDF2 and must not be applied (since the JavaScript code does not use PBKDF2 either).
The decrypted data must not be decoded with Encoding.Unicode (which corresponds to UTF16LE in .NET), but with Encoding.UTF8.
The C# code can handle 24 bytes keys (to support 3TDEA) and 16 bytes keys (to support the less secure 2TDEA). The posted CryptoJS code also handles these key sizes plus additionally 8 bytes keys (to support the least secure, DES compatible variant 1TDEA).
The following C# code decrypts a ciphertext generated with CryptoJS and 3TDEA:
public string Decrypt()
{
byte[] key = FromHexString("000102030405060708090a0b0c0d0e0f1011121314151617"); // 24 bytes (3TDEA)
byte[] iv = FromHexString("0001020304050607"); // 8 bytes
byte[] ciphertext = FromHexString("2116057c372e0e95dbe91fbfd148371b8e9974187b71e7c018de89c757280ad342d4191d29472040ee70d19015b025e1");
string plaintext = "";
using (TripleDES tdes = TripleDES.Create())
{
tdes.Key = key;
tdes.IV = iv;
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, tdes.CreateDecryptor(tdes.Key, tdes.IV), CryptoStreamMode.Write))
{
cs.Write(ciphertext, 0, ciphertext.Length);
}
plaintext = Encoding.UTF8.GetString(ms.ToArray());
}
}
return plaintext;
}
The decryption is also possible with the posted JavaScript code, which shows the functional equivalence of both codes.
Note: Since AES is more performant than TripleDES, AES should be used if possible.
I found an implementation for AES encryption/decryption that's supposed to work in PHP and C#:
https://odan.github.io/2017/08/10/aes-256-encryption-and-decryption-in-php-and-csharp.html
However, in this example, the IV is always 0, which is not good.
So, as the author suggests, I use the openssl_random_pseudo_bytes() function:
$ivlen = openssl_cipher_iv_length($method);
$iv = openssl_random_pseudo_bytes($ivlen);
However, the problem now is, that I have to store the IV somewhere so that the C# app can use it for decryption. My idea was to base64_encode it and prepend it to the encrypted message with ":" separating both, so that I can simply split the string, then base64 decode it in C# and can use the IV. However, this does not work. This is the code:
public string DecryptString(string cipherText, byte[] key, byte[] iv)
{
// Instantiate a new Aes object to perform string symmetric encryption
Aes encryptor = Aes.Create();
encryptor.Mode = CipherMode.CBC;
// Set key and IV
byte[] aesKey = new byte[32];
Array.Copy(key, 0, aesKey, 0, 32);
encryptor.Key = aesKey;
encryptor.IV = iv;
// Instantiate a new MemoryStream object to contain the encrypted bytes
MemoryStream memoryStream = new MemoryStream();
// Instantiate a new encryptor from our Aes object
ICryptoTransform aesDecryptor = encryptor.CreateDecryptor();
// Instantiate a new CryptoStream object to process the data and write it to the
// memory stream
CryptoStream cryptoStream = new CryptoStream(memoryStream, aesDecryptor, CryptoStreamMode.Write);
// Will contain decrypted plaintext
string plainText = String.Empty;
try {
// Convert the ciphertext string into a byte array
byte[] cipherBytes = Convert.FromBase64String(cipherText);
// Decrypt the input ciphertext string
cryptoStream.Write(cipherBytes, 0, cipherBytes . Length);
// Complete the decryption process
cryptoStream.FlushFinalBlock();
// Convert the decrypted data from a MemoryStream to a byte array
byte[] plainBytes = memoryStream.ToArray();
// Convert the decrypted byte array to string
plainText = Encoding.ASCII.GetString(plainBytes, 0, plainBytes.Length);
} finally {
// Close both the MemoryStream and the CryptoStream
memoryStream.Close();
cryptoStream.Close();
}
// Return the decrypted data as a string
return plainText;
}
And this is how I try to call the function with the IV prepended to the encrypted message:
private void btnDecrypt_Click(object sender, EventArgs e)
{
string encrypted = txtEncrypted.Text;
string password = txtPW.Text;
string[] temp = encrypted.Split(":".ToCharArray());
string iv_str = temp[0];
encrypted = temp[1];
SHA256 mySHA256 = SHA256Managed.Create();
byte[] key = mySHA256.ComputeHash(Encoding.ASCII.GetBytes(password));
iv_str = Encoding.Default.GetString(Convert.FromBase64String(iv_str));
byte[] iv = Encoding.ASCII.GetBytes(iv_str);
txtDecrypted.Text = this.DecryptString(encrypted, key, iv);
}
Doesn't work. It decrypts something, but that's just gibberish and not the message I encrypted in PHP.
I think it has to do with the IV somehow.
#Topaco:
Thank you very much... now I see what my mistake was. It works now with generated IV.
By the way, two more questions on the strength of the encryption:
Is it ok to use the following function to generate an IV (GenerateIV() for some reason won't work):
byte[] iv = new byte[16];
Random rnd = new Random();
rnd.NextBytes(iv);
I added a randomly generated salt to the password of the user, so that the key is a hash from the user password and a salt. I also prepend the salt, together with the now randomly generated IV, to the message. Then for the decryption process I use the prepended salt and the key the user enters. Works so far. But does it weaken the encryption? No, right?
Thank you very much.
// Edit: Code format doesn't work, don't know why.
I am writing a encrypted (Rijndael) byte array in a .txt file.
When I read it out, I get a byte[48]. As soon as i decrypt it, I get a byte[32].
Why am I losing bytes here? If I write the result in the Console, it also cuts at a specific point.
static void ShowEntries()
{
string path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
path = path + #"\SafePass\";
byte[] file = File.ReadAllBytes(path + #"\crypt.txt");
using (MemoryStream memory = new MemoryStream(file))
{
using (BinaryReader binary = new BinaryReader(memory))
{
byte[] result = binary.ReadBytes(file.Length);
byte[] plainText = new byte[48];
plainText = Decrypt(result);
string SplainText = Converter(plainText);
Console.WriteLine(SplainText);
}
}
}
static string Converter(byte[] data)
{
string base64 = Convert.ToBase64String(data);
return base64;
}
static byte[] Decrypt(byte[] encryptedByte)
{
{
string password = #"mykey123"; // Your Key Here
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(password);
MemoryStream mem = new MemoryStream();
RijndaelManaged RMCrypto = new RijndaelManaged();
CryptoStream cs = new CryptoStream(mem,
RMCrypto.CreateDecryptor(key, key),
CryptoStreamMode.Write);
cs.Write(encryptedByte, 0, encryptedByte.Length);
byte[] cipherText = null;
cipherText = mem.ToArray();
cs.Close();
return cipherText;
}
}
Assuming that your input data (i.e. what you're encrypting) is 32 bytes long, what's happening is that the encrypted data is being padded, which means that extra redundant information is added to the encrypted data.
In .NET, the default padding mode for symmetrical algorithms like Rijndael is PKCS #7.
I think that if you look at the extra data in the encrypted array all the extra values will be 16 (32 bytes input, next block is at 48, padding is the difference: 48-32=16).
Note that the padded bytes will be removed upon decryption, provided that the same padding mode is used for decryption as encryption. It's not going to affect your data.
But if you really want, you can set the padding mode to None, or one of the other values mentioned on MSDN.
Here's a similar answer to a similar question that you can also refer to.
I am trying to write client software which performs AES encryption and decryption of messages to a device using c#.
Using the AES class from System.Security.Cryptography, there is no problem sending encrypted messages to the device. The device decrypts these successfully.
The problem occurs when decrypting messages received from the device. We get the message: "Padding is invalid and cannot be removed."
I have searched the web and tried three different approaches but all have the same error - see below. I also tried the three approaches without setting the KeySize property.
In addition to the client being written in C#, a python client was also written where there everything works fine - using the python aes library.
So, having got a python version I was able to compare the lengths of the received cipherText which is 32 bytes long and is a byte array. 15 bytes are padding.
I really appreciate help.
Option 1
byte[] messageBuffer = null;
using (Aes aesAlg = Aes.Create())
{
aesAlg.BlockSize = 128;
aesAlg.KeySize = 128;
aesAlg.Mode = CipherMode.CBC;
aesAlg.Key = encryptionKey; //used by device to encrypt. encryptionKey is a 16 byte array
aesAlg.IV = sentIV; //This agrees with the IV that was used to encrypt the message by the device. sentIV is a 16 byte array
//aesAlg.Padding = PaddingMode.PKCS7; // this makes no difference
byte[] cipherText = encryptedMessagePart; //encryptedMessagePart is byte[] encryptedMessagePart
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
try
{
messageBuffer = decryptor.TransformFinalBlock(cipherText, 0, cipherText.Length); //****fails here ********************
}
catch (Exception ex)
{
....;
}
}
Option 2
byte[] messageBuffer = new byte [1024];
using (Aes aesAlg = Aes.Create())
{
aesAlg.BlockSize = 128;
aesAlg.KeySize = 128;
aesAlg.Mode = CipherMode.CBC;
aesAlg.Key = encryptionKey; //used by device to encrypt. encryptionKey is a 16 byte array
aesAlg.IV = sentIV; //This agrees with the IV that was used to encrypt the message by the device. sentIV is a 16 byte array
//aesAlg.Padding = PaddingMode.PKCS7; // this makes no difference
byte[] cipherText = encryptedMessagePart; //encryptedMessagePart is byte[] encryptedMessagePart
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
using (var msDecrypt = new MemoryStream(cipherText))
{
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
try
{
var zx = csDecrypt.Read(messageBuffer, 0, cipherText.Length); //****fails here ********************
}
catch (Exception ex)
{
....;
}
}
}
}
Option 3
byte[] messageBuffer = new byte [1024];
using (Aes aesAlg = Aes.Create())
{
aesAlg.BlockSize = 128;
aesAlg.KeySize = 128;
aesAlg.Mode = CipherMode.CBC;
aesAlg.Key = encryptionKey; //used by device to encrypt. encryptionKey is a 16 byte array
aesAlg.IV = sentIV; //This agrees with the IV that was used to encrypt the message by the device. sentIV is a 16 byte array
//aesAlg.Padding = PaddingMode.PKCS7; // this makes no difference
byte[] cipherText = encryptedMessagePart; //encryptedMessagePart is byte[] encryptedMessagePart
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
using (var msDecrypt = new MemoryStream(cipherText))
{
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (var srDecrypt = new StreamReader(csDecrypt))
{
try
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
var pt = srDecrypt.ReadToEnd(); //****fails here ********************
messageBuffer = Utils.GetBytes(pt); //convert to bytes
}
catch (Exception ex)
{
....;
}
}
}
}
}
Padding errors are expected for anything where the key or message has been corrupted. For small messages smaller than one block it could also be that the IV is incorrectly handled. As the device seems to be using C# that's the most likely cause.
Much less likely, but possible, is that ISO 10126 padding is used. PKCS#7 padded messages can be unpadded using an ISO 10126 unpadding routine. However, the reverse is not true as PKCS#7 relies on all the values in the padding to be correct, not just the last one. In ISO 10126 padding only the last byte indicates the amount of padding bytes used; the other bytes may have any value.
You can of course always have a look yourself. Simply indicate "no padding" and print out the message in hexadecimals. If the message is total garbage either the message or even more likely the key is incorrect. If it looks OK then you should be able to distinguish the padding method from the last bytes; the Wikipedia article on padding lists all the common schemes.
I resolved this problem very simply by in the decryption routine, explicitly setting padding mode to none by:
aesAlg.Padding = PaddingMode.None;
In the original python routines, padding mode was not used.
I assumed, incorrectly, by not stating padding mode, padding mode would be none.
(In case you are wondering, encrytpion routines were written in python only. On decryption routines were written in Python and C#)