Reputation: 331
I spent a whole day investigating this and search all related questions on Stack Overflow for this question so please don't mention about possible duplicates.
The code below gives me a System.Security.Cryptography.CryptographicException: 'Specified padding mode is not valid for this algorithm.'
While using the very same parameters on this website : http://aes.online-domain-tools.com it decrypts perfectly into "Hello world" then filled with five 'x05' bytes for padding (PKCS#7 padding).
However the code below will always yield an exception when calling the TransformFinalBlock()
Context: Console application running on Win8.1 with .NET Core 2.0 / Algorithm is AES / CBC / padding PKCS#7
I also tried the proposed solution here: Specified padding mode is not valid for this algorithm - c# - System.Security.Cryptography but no success (I also don't understand why if IV is already set in the SymmetricAlgorithm instance, it should be used later on when deciphering?
static void Main(string[] args)
{
string encryptedStr = "e469acd421dd71ade4937736c06fdc9d";
string passphraseStr = "1e089e3c5323ad80a90767bdd5907297b4138163f027097fd3bdbeab528d2d68";
string ivStr = "07dfd3f0b90e25e83fd05ba338d0be68";
// Convert hex strings to their ASCII representation
ivStr = HexStringToString(ivStr);
passphraseStr = HexStringToString(passphraseStr);
encryptedStr = HexStringToString(encryptedStr);
// Convert our ASCII strings to byte arrays
byte[] encryptedBytes = Encoding.ASCII.GetBytes(encryptedStr);
byte[] key = Encoding.ASCII.GetBytes(passphraseStr);
byte[] iv = Encoding.ASCII.GetBytes(ivStr);
// Configure our AES decryptor
SymmetricAlgorithm algorithm = Aes.Create();
algorithm.Mode = CipherMode.CBC;
algorithm.Padding = PaddingMode.PKCS7;
algorithm.KeySize = 256;
//algorithm.BlockSize = 128;
algorithm.Key = key;
algorithm.IV = iv;
Console.WriteLine("IV length " + iv.Length); // 16
Console.WriteLine("Key length " + key.Length); // 32
ICryptoTransform transform = algorithm.CreateDecryptor(algorithm.Key, algorithm.IV);
// Perform decryption
byte[] outputBuffer = transform.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
// Convert it back to a string
string result = Encoding.ASCII.GetString(outputBuffer);
Console.WriteLine(result);
Console.ReadLine();
}
public static string HexStringToString(string hexString)
{
var sb = new StringBuilder();
for (var i = 0; i < hexString.Length; i += 2)
{
var hexChar = hexString.Substring(i, 2);
sb.Append((char)Convert.ToByte(hexChar, 16));
}
return sb.ToString();
}
Upvotes: 4
Views: 3997
Reputation: 31312
The problem is in the way how you convert hex string to byte array. Try to debug your code and check the value of array encryptedBytes
. You'll see the following array:
{ 0x3f, 0x69, 0x3f, 0x3f, 0x21, 0x3f, 0x71, 0x3f, 0x3f, 0x3f, 0x77, 0x36, 0x3f, 0x6f, 0x3f, 0x3f }
which is far from input e469acd421dd71ade4937736c06fdc9d
.
You shouldn't use System.String
object as just a holder of binary char codes because .Net strings are UTF16-encoded.
Now when root cause is clear, the fix is pretty straighforward. Change your HexStringToString
method so that it converts hex string to bytes array directly:
public static byte[] HexStringToByteArray(string hexString)
{
if (hexString.Length % 2 != 0)
{
throw new InvalidOperationException($"Inalid hex string '{hexString}'");
}
byte[] bytes = new byte[hexString.Length / 2];
for (var i = 0; i < hexString.Length; i += 2)
{
var hexChar = hexString.Substring(i, 2);
bytes[i / 2] = Convert.ToByte(hexChar, 16);
}
return bytes;
}
Then adjust the code in Main()
:
byte[] encryptedBytes = HexStringToByteArray(encryptedStr);
byte[] key = HexStringToByteArray(passphraseStr);
byte[] iv = HexStringToByteArray(ivStr);
This will give you desired Hello world
in result
variable.
Upvotes: 3