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:
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"));
} 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:
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)
{
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))
{
var notificationArray = System.Convert.FromBase64String(notification.ToString());
var ivArray = System.Convert.FromBase64String(iv.ToString());
byte[] keyArray = Encoding.UTF8.GetBytes("My Secret Key");
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)
{
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");
string plaintext = null;
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;
ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.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;
}
}
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:
{
// 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.