0

I'm new with this encryption and decryption techniques.

I'm working on a task with Clickbank Instant Notification system. I'm getting the encrypted values from Clickbank and I want to decrypt the notification. My problem is very similar to this thread but it is not working for me. It is throwing following error:

Specified initialization vector (IV) does not match the block size for this algorithm.

Below is my code for decryption.

protected void Page_Load(object sender, EventArgs e)
{
    //Sample response
    string sContent = "{\"notification\":\"18XR9s5fwkbhvfriqYS6jDJERf++jshcTDQX4NuUoUHtS+YzfMCNiEvmIVNxkbT5My2xWLFPB9mb\nEjwpHd3A6b9WJDYiXc0nufTxhXDAL1JzyYryEZAq7Bogj7mHjxUfFhc419wDmQteoSEz4H0IsKha\nIoxSfA5znd6WZKCSY9Dxx0wbZ8jLNL8SOYxi7pbFdKgMgKULKEh4EPKaWAvhE5UjWtzuHvMX37NI\nOvApkBoYEDE2mrde/SjLigE38X2wsGB4M6pYVkfzEE6rbYfVNxadkNHmri1xlaa+Grudy6vt6wzq\nPUfroEb6uRlxj2e6dmKZE4kynJFmRosMJ4ZRC+sYW+DyvkbdSY2dl1ZMNPhP+yhcMkbU8HQKUipw\nd7FUpb6utfiDB8YL5z7pJMnjHP01PsIvG+eSj0Lfj1gmbtVJt6TOJ4BCZxZdfdPRlJtPdOUiMRRk\nQ3Wn5g9VuvzNYg2ostZ+/HE778M6lZ264KbpMZSqEj4cTPCGFFNt7VCz9fXVoDLa7oI7KGY6rgxb\nBLWXdX058RSd0gSzC8otkCx9b6p8FZ5XxAX4qbU814batcbxw3V3GGVf97VLSVysdrHc+PEFdocl\nqaRarCHG5e2ZpEgQLoCtRhA99qkuS9Uc9+Hm1KT4kD2HIrPSclJWzUMoKuAG4n95EG0Q5ca0WZQx\naLNhdPyJmSLNwjV/SNPxYdyy81ENZtLbwJOYENCnpd41z73HF91/R1hrxQ0rCZsb6BBRGUeowEzE\nSKPSbWjDCQ6hLZTjObsOt6eTAmn8TrzjyqdwUfxHhLEtIQIOr4gPXxXqwGHYcNkRFezkwMScl2Hr\nmJ+Zm1xCqs9+fOOiO6TtZYKS+9Dl/JevMfGdbcPw8/5F7+ZVAkCcDS8OGaVv\",\"iv\":\"NDVEM0M4ODZGMzE4OTVENA==\"}";


    using (var reader = new StreamReader(Request.InputStream))
    {
        //Using below two lines for live testing
        //JavaScriptSerializer js = new JavaScriptSerializer();
        //sContent = reader.ReadToEnd();

        JObject jObject = JObject.Parse(sContent);

        JToken notification = jObject["notification"];
        JToken i = jObject["iv"];


        using (StreamWriter _testData = new StreamWriter(Server.MapPath("~/data.txt"), true))
        {
            _testData.WriteLine("=======================Notification"); // Write the file. 
            _testData.WriteLine(notification.ToString());
            _testData.WriteLine("=======================IV"); // Write the file. 
            _testData.WriteLine(i.ToString());

            string n = notification.ToString();
            string v = i.ToString();

            string sk = "MY SECRET KEY";


            byte[] key = Encoding.UTF8.GetBytes(sk);
            byte[] iv = Encoding.UTF8.GetBytes(v);

            try
            {
                using (var rijndaelManaged =
                       new RijndaelManaged { Key = key, IV = iv, Mode = CipherMode.CBC })
                using (var memoryStream =
                       new MemoryStream(Convert.FromBase64String(n)))
                using (var cryptoStream =
                       new CryptoStream(memoryStream,
                           rijndaelManaged.CreateDecryptor(key, iv),
                           CryptoStreamMode.Read))
                {
                    var dString = new StreamReader(cryptoStream).ReadToEnd();
                }
            }
            catch (CryptographicException ex)
            {
                Console.WriteLine("A Cryptographic error occurred: {0}", ex.Message);

            }
        }
    }
}

Please let me know where I'm wrong?

Thanks

Community
  • 1
  • 1
waghekapil
  • 321
  • 1
  • 5
  • 22
  • 3
    1) You use text as `key`/`iv`, that makes no sense. Keys represented as strings are typically hex or Base64 encoded. 2) The IV must be exactly 16 bytes in length and the key must be exactly 32 bytes in length. – CodesInChaos Mar 23 '15 at 11:01
  • Thanks for reply. I checked it and My secret key is 16 letters long and IV is returned from the Clickbank. – waghekapil Mar 23 '15 at 11:23
  • 1
    A quick look found something about `JValue` and a `byte[]` operator, but my `JToken` knowledge is about 0 so I cannot really use that for an answer. Keys and IV's are bytes, no characters, as Codes already stipulated. – Maarten Bodewes Mar 24 '15 at 00:16
  • What is the value of i.ToString()? – Animal Style Mar 24 '15 at 17:49
  • value of v is "NDVEM0M4ODZGMzE4OTVENA==". (without quotes) – waghekapil Mar 24 '15 at 18:11

2 Answers2

1

I just finished banging my head on this exact same problem, so here is my solution. The thing to keep in mind is the passphrase/secretkey gets hashed by sha1 and the first 32 hex characters are used as the key bytes. The part that was throwing me off was the characters are UFT16 characters in c# and were actually 2 bytes each but not what the source encryption used. So what I did was convert the string to a ASCII string which had the correct byte array. Not the cleanest code but it's functional.

    public static string DecryptClickBankNotification(string cipherText, string passPhrase, string initVector)
    {
        string decryptedString = null;

        byte[] inputBytes = Encoding.UTF8.GetBytes(passPhrase);

        SHA1 sha1 = SHA1.Create();
        byte[] key = sha1.ComputeHash(inputBytes);

        StringBuilder hex = new StringBuilder(key.Length * 2);
        foreach (byte b in key)
            hex.AppendFormat("{0:x2}", b);

        string secondPhaseKey = hex.ToString().Substring(0,32);

        ASCIIEncoding asciiEncoding = new ASCIIEncoding();

        byte[] keyBytes = asciiEncoding.GetBytes(secondPhaseKey);
        byte[] iv = Convert.FromBase64String(initVector);

        try
        {
            using (RijndaelManaged rijndaelManaged = new RijndaelManaged
            { 
                Key = keyBytes,
                IV = iv,
                Mode = CipherMode.CBC, 
                Padding = PaddingMode.PKCS7})
                using (Stream memoryStream = new MemoryStream(Convert.FromBase64String(cipherText)))
                using (CryptoStream cryptoStream =
                   new CryptoStream(memoryStream,
                       rijndaelManaged.CreateDecryptor(keyBytes, iv),
                       CryptoStreamMode.Read))
            {
                decryptedString = new StreamReader(cryptoStream).ReadToEnd();
            }
        }
        catch (Exception ex)
        {
            Trace.WriteLine(new TraceData(TraceCategoryEnum.Errors, "Error decrypting message: " + ex.Message));
        }

        return decryptedString;
    }
PeterO
  • 161
  • 1
  • 4
  • UTF-8 characters are single bytes for ASCII characters and multi-byte for other characters. UTF-16 are two byte characters for ASCII characters, this format is often used internally in computer languages. – zaph Apr 28 '16 at 08:06
  • Sorry you are correct, I meant it was UTF-16 is the internal string representation but the answer still holds true. Updated answer from UTF-8 to UTF-16 – PeterO May 10 '16 at 18:15
0

If your v has 16 letters and you Encoding.UTF8.GetBytes(v); the number of bytes could be between 16 and 64. This could be giving you the error.

Specified initialization vector (IV) does not match the block size for this algorithm.

Verify that iv is 16 bytes.

Animal Style
  • 689
  • 2
  • 10
  • 31
  • Value of IV is "NDVEM0M4ODZGMzE4OTVENA==" It is 24 letters long. I think it is in Base64. IV must be 16 bytes long. var ivArray = System.Convert.FromBase64String("NDVEM0M4ODZGMzE4OTVENA=="); I'm getting it correctly. And, Key must be 32 bytes long. My key length is 16 letters. It is in Hexadecimal format. When I convert it into UTF-8 it gives me 16 bytes. (Not working) When I convert it into Unicode it gives me 32 bytes. (Even Not working). In java code SHA-1, and UTF-8 encoding is used. So, I think here is something I'm missing – waghekapil Mar 24 '15 at 18:09
  • Checked. iv is 16 bytes long – waghekapil Mar 24 '15 at 18:18