Click here to Skip to main content
15,891,730 members
Please Sign up or sign in to vote.
1.44/5 (2 votes)
See more:
Hello,

I'm new with this encryption and decryption techniques.

I'm working on a task with Clickbank Instant Notification system in C#. The result sent from clickbank is in following format:

{"notification": "ENCRYPTED_NOTIFICATION", "iv": "INITIALIZATION_VECTOR"}

I have the encrypted Notification, IV, and my Secret key. Next is to perform decryption of notification. Clickbank provided Java sample code to do decryption. I tried to understand it and write my C# code.

Below is the java code:


Java
public void processNotification(final HttpServletRequest theRequest,
                               final HttpServletResponse theResponse)
    throws IOException {
    try {
        final StringBuilder buffer = new StringBuilder();
        final String secretKey = "YOUR SECRET KEY"; 

        try {
            String line;
            final BufferedReader reader = theRequest.getReader();
            while(null != (line = reader.readLine())) {
                buffer.append(line);
            }
        } catch(final Exception ex) {
            ex.printStackTrace();
        } 

        final JSONParser parser = new JSONParser();
        final JSONObject obj = (JSONObject) parser.parse(buffer.toString()); 

        final String initializationVector = (String) obj.get("iv");
        final String encryptedNotification = (String) obj.get("notification"); 
        final MessageDigest digest = MessageDigest.getInstance("SHA-1");
        digest.reset();
        digest.update(secretKey.getBytes("UTF-8"));
        final String key = new String(Hex.encodeHex(digest.digest())).substring(0, 32);

        final IvParameterSpec iv =
            new IvParameterSpec(DatatypeConverter.parseBase64Binary(initializationVector));
        final SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
        final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);

        final JSONObject notification = (JSONObject) parser.parse(
        new String(cipher.doFinal(DatatypeConverter.parseBase64Binary(encryptedNotification)),
                       "ISO-8859-1"));

        //
        // Make use of the notification here...
        // 

    } catch(final NoSuchPaddingException
        | ParseException
        | NoSuchAlgorithmException
        | InvalidAlgorithmParameterException
        | BadPaddingException
        | IllegalBlockSizeException
        | UnsupportedEncodingException
        | InvalidKeyException ex) {
        ex.printStackTrace();
        theResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED,
                              "Could not decrypt instant notification");
    }
     theResponse.setStatus(HttpServletResponse.SC_NO_CONTENT);
}


Here is my C# code:



C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Security.Cryptography;
using System.Text;
using System.Configuration;
using System.IO;
using System.Net;
using System.Web.Script.Serialization;
using Newtonsoft.Json.Linq;

public partial class Default2 : System.Web.UI.Page
{
    string webconfconstrng = ConfigurationManager.ConnectionStrings["uSqlConnection"].ToString();

    protected void Page_Load(object sender, EventArgs e)
    {
        //Sample string with - Notification and IV
        string sContent = "{\"notification\":\"B/gHFsmO4Hf7sfjABxYxvZFb/0wRIXvWkh339FOITjpkKFmnL6uG8CDv/mKb/gNQnjnZVAOQGVmw"
+ "PEfOMJFniBfehdyeCjoMj5u4T0U5iNTssF9uHYZNioRa/Ss9FYKFAROjPurQC7tgahQJw7MTQTbE"
+ "Sed60HiqL1iw9jnB0VcSnNScPFyTnJHLP/mMpZtWis5Qy2i0Xjs9nmqjvKvbJy14hp5h1itARGEq"
+ "eFp6NmpuIk+XDgtZl5+mVjwK6B6uJi284R3SKbHwtw/yTpCqcFPRv5JScBMJCrfqOyI7vwSb1of7"
+ "B+Ux9p49vF3odaZc9jGRptu/evff/FfZXkvgtXAPDSWomQTvb4D5HMajDZb1687+12z/LGkcstCh"
+ "RntqUlvO0BLa3Gq/V44GrhqG8pXAZP8mGkynNxvEUl1joQ+4qSl4yNQ/3VUdr3uQHLqEXBL+e1QS"
+ "GKqukxdNPJ5NTJZg8y/oiVp4B4wZL32qbEKbztfxSR277cFtmZkMppZLWdsr/iS1iro4Z1yoRl/A"
+ "9/Rx//mkp3AdovOBNOOTYyASXtL1gaQ/bvn2CTXoXnJysPtKIERdHZx5tl0HGQvwerBykownhLDy"
+ "vBPtJ4oygBGkjrWixRh4DBEWIA0ajQIG/fVCL2wQAimDMXVkfiExQfK09tvoSbiWoI3VutARmafT"
+ "n0ym8lZ/hRcfBBdnFakjSiEgdjfO2d3OqSYrySHa4G72lGiSSLU0OF+xXR0dGW8JCy9ow92OJHLt"
+ "JTnKbqyOKl/esVYVJXMCcDvkhq9GIR2SeXWs5QsUoY0WxCaNfVOO+ff6E0llzP3qw1qqFXwaZHEw"
+ "zju1/+DFO8X3RsSvbmlEJpAG9FMgV93fNAxljLjHfyP07UwkKlVQT4S/i7MZ\",\"iv\":\"NEVFMEU2MUJDMTM1NzFCMA==\"}";

        try
        {
            JObject jObject = JObject.Parse(sContent);

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


            using (StreamWriter _testData = new StreamWriter(Server.MapPath("~/data.txt"), true))
            {
                //****************** Encrypted value to decrypt
                var notificationArray = System.Convert.FromBase64String(notification.ToString());

                //****************** IV must be 16 bytes long. I'm getting it correctly
                var ivArray = System.Convert.FromBase64String(iv.ToString());

                //****************** 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

                //Will return 16 bytes
                byte[] keyArray = Encoding.UTF8.GetBytes("My Secret Key");

                //Will return 32 bytes
                //byte[] key = Encoding.Unicode.GetBytes("My Secret Key"); 

                // Decrypt the bytes to a string. 
                string roundtrip = DecryptStringFromBytes(notificationArray, keyArray, ivArray);
            }
        }
        catch (Exception ex)
        {

            Response.Write("Error: " + ex.Message + "\n" + ex.StackTrace);

        }
    }


    string DecryptStringFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
    {
        // Check arguments. 
        if (cipherText == null || cipherText.Length <= 0)
            throw new ArgumentNullException("cipherText");
        if (Key == null || Key.Length <= 0)
            throw new ArgumentNullException("Key");
        if (IV == null || IV.Length <= 0)
            throw new ArgumentNullException("IV");

        // Declare the string used to hold 
        // the decrypted text. 
        string plaintext = null;

        // Create an RijndaelManaged object 
        // with the specified key and IV. 
        using (RijndaelManaged rijAlg = new RijndaelManaged())
        {
            rijAlg.Key = Key;
            rijAlg.IV = IV;
            rijAlg.BlockSize = 128;
            rijAlg.KeySize = 256;
            rijAlg.Mode = CipherMode.CBC;
            rijAlg.Padding = PaddingMode.None;

            // Create a decrytor to perform the stream transform.
            ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);

            // Create the streams used for decryption. 
            using (MemoryStream msDecrypt = new MemoryStream(cipherText))
            {
                using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                {
                    using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                    {

                        // Read the decrypted bytes from the decrypting stream 
                        // and place them in a string.
                        plaintext = srDecrypt.ReadToEnd();
                    }
                }
            }
        }
        return plaintext;
    }
}



Using above C# code I'm able to get the value in plaintext variable of DecryptStringFromBytes function. But it is not decrypted correctly.

Please let me know where is the problem? I already spent 2 days with this and looking for a quick help.

Thank you for reading this thead.

Update:

My expected result is like:

XML
{
    // Time of the transaction in RFC-3339 format [25 characters]
    "transactionTime": "2014-09-05T13:47:51-06:00",
    // ClickBank receipt [8 - 21 characters]
    "receipt": "CWOGBZLN",
    // Type of Transaction (SALE, JV_SALE, INSF, RFND, CGBK, BILL, JV_BILL,
    // TEST_SALE, TEST_JV_SALE, TEST_BILL, TEST_JV_BILL, TEST_RFND)
    "transactionType": "SALE",
    // Vendor nickname [5 - 10 characters]
    "vendor": "testacct",
    // Affiliate nickname [5 - 10 characters]
    "affiliate": "bobkelso",
    // Your role in the transaction (e.g., VENDOR, AFFILIATE, JV_VENDOR) [6 - 9 characters]
    "role": "VENDOR",
    // Total you received for this transaction in USD [numeric value with 2 decimal precision]
    "totalAccountAmount": 0.00,
    // Payment method used by the customer. [AMEX, AUST, BLME, DISC, DNRS, ELV, ENRT, IMAS,
    // JCBC, MAES, MSTR, PYPL, STVA, SWIT, TEST, VISA]
    "paymentMethod": "VISA",
    // Total the customer was charged [numeric value with 2 decimal precision]
    "totalOrderAmount": 0.00,
    // Total the customer paid in taxes. ONLY AVAILABLE TO THE VENDOR [numeric value with 2
    // decimal precision]
    "totalTaxAmount": 0.00,
    // Total the customer paid in shipping. ONLY AVAILABLE TO THE VENDOR [numeric value with
    // 2 decimal precision]
    "totalShippingAmount": 0.00,
    // The currency the customer paid in. ONLY AVAILABLE TO THE VENDOR [3 characters]
    "currency": "USD",
    // The language displayed on the order form. ONLY AVAILABLE TO THE VENDOR
    // [DE, EN, ES, FR, IT, PT]
    "orderLanguage": "EN",
    // Any tracking codes passed into the order from. ONLY AVAILABLE TO THE VENDOR AND
    // THE AFFILIATE [0 - 24 characters each]
    "trackingCodes": [
        "tracking_code"
    ],
    // A list of products purchased on this order
    "lineItems": [
        {
            // Product SKU. [1 - 10 characters]
            "itemNo": "1",
            // Product title. [0 - 255 characters]
           "productTitle": "Product Title",
            // Was the product shippable? [true, false]
            "shippable": true,
           // Was the product subscription based? [true, false]
            "recurring": true,
            // Amount you received on this given line item. [numeric value with 2
            // decimal precision]
            "accountAmount": 0.00,
            // Product download URL for the customer. ONLY AVAILABLE TO THE VENDOR
            "downloadUrl": "<download_url>"
        }
    ],
    "customer": {
        // Shipping customer information. ALL FIELDS ARE ONLY AVAILABLE TO THE VENDOR
        // [each field is 0 - 255 characters]
        "shipping": {
            "firstName": "TEST",
            "lastName": "GUY",
            "fullName": "Test Guy",
           "phoneNumber": "",
            "email": "test@example.net",
            "address": {
                "address1": "12 Test Lane",
                "address2": "Suite 100",
                "city": "LAS VEGAS",
                "county": "LAS VEGAS",
                "state": "NV",
                "postalCode": "89101",
                "country": "US"
            }
        },
        // Billing customer information. FIELDS ARE ONLY AVAILABLE TO THE VENDOR UNLESS
        // OTHERWISE STATED [all fields are 0 - 255 characters]
        "billing": {
            "firstName": "TEST",
            "lastName": "GUY",
            "fullName": "Test Guy",
            "phoneNumber": "",
            "email": "test@example.net",
            "address": {
                // AVAILABLE TO ALL RECIPIENTS
                "state": "NV",
                // AVAILABLE TO ALL RECIPIENTS
                "postalCode": "89101",
                // AVAILABLE TO ALL RECIPIENTS
                "country": "US"
            }
        }
    },
    // If the order is part of an upsell, that information will be found here
    "upsell": {
        // ClickBank receipt number that started the upsell flow
        "upsellOriginalReceipt": "XXXXXXXX",
        // ID of the upsell flow. ONLY AVAILABLE TO THE VENDOR [integer value]
        "upsellFlowId": 55,
        // Session ID for the upsell. ONLY AVAILABLE TO THE VENDOR [0 - 16 characters]
        "upsellSession": "VVVVVVVVVV",
        // Upsell path. ONLY AVAILABLE TO THE VENDOR [0 - 12 characters]
        "upsellPath": "upsell_path"
    },
    // If there is Pytch information associated with this order, the information will be
    // found here and is available to all recipients.
    "hopfeed": {
        "hopfeedClickId": "hopfeed_click",
        "hopfeedApplicationId": 0000,
        "hopfeedCreativeId": 0000,
        "hopfeedApplicationPayout": 0.00,
        "hopfeedVendorPayout": 0.00
    },
    // Version of the instant notification. [double numeric value]
    "version": 6.0,
    // The number of attempts ClickBank has tried to send this instant notification
    // before receiving a success, or failing with too many attempts. [integer value]
    "attemptCount": 1,

   // Any vendor provided variables to the paylink will be provided here.   
    "vendorVariables": {
       "v1": "variable1", 
       "v2": "variable2" 
    }

}



The result I'm getting is:

(JEw.m\nCaj��:|H;_�Q��j�ۧ��:���'���pk��ӟ�B%ǩ����\v&�{�\f]�\0�rո\n�{��;����\r�1vQ���z4_Iד��5�'��HGo�Pn�30�Ř���x�ct��P˳�iY+��R��M[�Of�X��}����+,$�+r��\\\v��˦��!�/����R�\r����0p��/gv���H���I]Ϟx��?fp�ΜY�;miJ����rj�r�F;_����g�Z�壋�^�n�M��65�i���BKE�T:ہ��uX����b\r���ܟҲ��\0qN���\02Bd���Us�d˳��\0�g����f����]��lj\rۗ��gz�\n\nm̯�{oC3t�N���d�<�\0��\b=�%f�T⨓��ѐT'\0�Ϊ�KNO�\"�ά<��H�\vw9�#�,!�<�a�{�w�ԏr�fR�`o\t7\r^�����#_AX�ܿR���l\n���VyW���XltZK��m�P�uh��s��ʓj�,J��䳕l���7�E�Ο�����k\";�bu��g\0�'����\b������\a������M \b����=��DBT��YGqg��)\r�0�ʛ\rpȹ��8%���,�WSL�ґ]��<ˮa���w�zśk+%>

The area of code involved is:

DecryptStringFromBytes function.
Posted
Updated 23-Mar-15 23:14pm
v3
Comments
Richard MacCutchan 24-Mar-15 4:44am    
Firstly, please format your code blocks properly with <pre> tags (use the "code" link above the edit window). And secondly, you need to give a more detailed explanation of what results are expected and what results you see, and the area of code involved.
Kapil Waghe 24-Mar-15 5:15am    
Thanks for your suggestions. I updated the question as suggested.
Richard MacCutchan 24-Mar-15 7:25am    
I don't know much about encryption, but are you sure you are using exactly the same cipher and byte transformations in both C# and Java?
Darren_vms 27-Mar-15 11:38am    
I'm the same as Richard with regards to encryption but reading the java code it looks like its using padding whilst the c# has PaddingMode.None;

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900