/
C# SDK Sample: Hosted Fields (Credit Card Numbers)
C# SDK Sample: Hosted Fields (Credit Card Numbers)
PemKeyUtils is used by the Hosted Fields to handle RSA encryption
using System; using System.IO; using System.Security.Cryptography; using System.Text; namespace SdkSample { public class PemKeyUtils { public static RSACryptoServiceProvider GetRsaProviderFromPublicKey( string pemString ) { var pemkey = DecodeOpenSslPublicKey( pemString ); return pemkey == null ? null : DecodeX509PublicKey( pemkey ); } //-------- Get the binary RSA PUBLIC key -------- private static byte[] DecodeOpenSslPublicKey( string instr ) { const string pempubheader = "-----BEGIN PUBLIC KEY-----"; const string pempubfooter = "-----END PUBLIC KEY-----"; string pemString = instr.Trim(); byte[] binkey; if (!pemString.StartsWith( pempubheader ) || !pemString.EndsWith( pempubfooter )) return null; StringBuilder sb = new StringBuilder( pemString ); sb.Replace( pempubheader, "" ); //remove headers/footers, if present sb.Replace( pempubfooter, "" ); string pubstr = sb.ToString().Trim(); //get string after removing leading/trailing whitespace try { binkey = Convert.FromBase64String( pubstr ); } catch (FormatException) { //if can't b64 decode, data is not valid return null; } return binkey; } static RSACryptoServiceProvider DecodeX509PublicKey(byte[] x509Key) { // encoded OID sequence for PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1" byte[] seqOid = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 }; // --------- Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob ------ using (var mem = new MemoryStream(x509Key)) { using (var binr = new BinaryReader(mem)) //wrap Memory Stream with BinaryReader for easy reading { try { var twobytes = binr.ReadUInt16(); switch (twobytes) { case 0x8130: binr.ReadByte(); //advance 1 byte break; case 0x8230: binr.ReadInt16(); //advance 2 bytes break; default: return null; } var seq = binr.ReadBytes(15); if (!CompareByteArrays(seq, seqOid)) //make sure Sequence for OID is correct return null; twobytes = binr.ReadUInt16(); if (twobytes == 0x8103) //data read as little endian order (actual data order for Bit String is 03 81) binr.ReadByte(); //advance 1 byte else if (twobytes == 0x8203) binr.ReadInt16(); //advance 2 bytes else return null; var bt = binr.ReadByte(); if (bt != 0x00) //expect null byte next return null; twobytes = binr.ReadUInt16(); if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81) binr.ReadByte(); //advance 1 byte else if (twobytes == 0x8230) binr.ReadInt16(); //advance 2 bytes else return null; twobytes = binr.ReadUInt16(); byte lowbyte; byte highbyte = 0x00; if (twobytes == 0x8102) //data read as little endian order (actual data order for Integer is 02 81) lowbyte = binr.ReadByte(); // read next bytes which is bytes in modulus else if (twobytes == 0x8202) { highbyte = binr.ReadByte(); //advance 2 bytes lowbyte = binr.ReadByte(); } else return null; byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; //reverse byte order since asn.1 key uses big endian order int modsize = BitConverter.ToInt32(modint, 0); byte firstbyte = binr.ReadByte(); binr.BaseStream.Seek(-1, SeekOrigin.Current); if (firstbyte == 0x00) { //if first byte (highest order) of modulus is zero, don't include it binr.ReadByte(); //skip this null byte modsize -= 1; //reduce modulus buffer size by 1 } byte[] modulus = binr.ReadBytes(modsize); //read the modulus bytes if (binr.ReadByte() != 0x02) //expect an Integer for the exponent data return null; int expbytes = binr.ReadByte(); // should only need one byte for actual exponent data (for all useful values) byte[] exponent = binr.ReadBytes(expbytes); // We don't really need to print anything but if we insist to... //showBytes("\nExponent", exponent); //showBytes("\nModulus", modulus); // ------- create RSACryptoServiceProvider instance and initialize with public key ----- RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); RSAParameters rsaKeyInfo = new RSAParameters { Modulus = modulus, Exponent = exponent }; rsa.ImportParameters(rsaKeyInfo); return rsa; } catch (Exception) { return null; } } } } private static bool CompareByteArrays( byte[] a, byte[] b ) { if (a.Length != b.Length) return false; var i = 0; foreach (var c in a) { if (c != b[i]) return false; i++; } return true; } } }
using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Net.Http; using System.Runtime.Serialization; using System.Runtime.Serialization.Json; using System.Security.Cryptography; using System.Text; namespace SdkSample { public class HostedFields { private const string BaseAddress = "https://token.ultracart.com"; private const string HostedFieldsPath = "/cgi-bin/UCCheckoutAPIHostedFields"; private const string PublicKeyPath = "/cgi-bin/UCCheckoutAPIHostedFieldsPublicKey"; private const string Referrer = "https://token.ultracart.com/"; private static readonly Uri ReferrerUri = new Uri(Referrer); private const string Version = "1.0"; // ReSharper disable once InconsistentNaming private const string OperationCVV = "storeCreditCardCvv2"; // ReSharper disable once InconsistentNaming private const string OperationCC = "storeCreditCardNumber"; public string MerchantId { get; set; } public string CartId { get; set; } //public string PublicKey { get; set; } public RSACryptoServiceProvider Rsa { get; set; } public static HostedFields Create(string merchantId) { return Create(merchantId, null); } public static HostedFields Create(string merchantId, string cartId) { var hostedFields = new HostedFields(merchantId, cartId) {Rsa = PemKeyUtils.GetRsaProviderFromPublicKey(GetPublicKey())}; return hostedFields; } private HostedFields(string merchantId, string cartId) { MerchantId = merchantId; CartId = cartId; } private static string GetPublicKey() { var hc = new HttpClient {BaseAddress = new Uri(BaseAddress)}; var result = hc.GetAsync(PublicKeyPath).Result; var key = result.Content.ReadAsStringAsync().Result; Console.WriteLine(key); return key; } private static JsonResult PostToTokenVault(HttpContent payload) { var hc = new HttpClient {BaseAddress = new Uri(BaseAddress)}; hc.DefaultRequestHeaders.Referrer = ReferrerUri; var result = hc.PostAsync(HostedFieldsPath, payload).Result; var serializer = new DataContractJsonSerializer(typeof(JsonResult)); var jsonResult = (JsonResult) serializer.ReadObject(result.Content.ReadAsStreamAsync().Result); Console.WriteLine($"PostJsonPayload Result: {jsonResult}"); return jsonResult; } public JsonResult StoreNumber(string creditCardNumber) { Console.WriteLine($"Storing CC: {creditCardNumber}"); var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); Console.WriteLine($"Epoch: {epoch}"); var timestamp = (long) (DateTime.UtcNow - epoch).TotalMilliseconds; Console.WriteLine($"Timestamp: {timestamp}"); var unencryptedPayload = creditCardNumber + "|" + timestamp; Console.WriteLine($"Unencrypted Payload: {unencryptedPayload}"); var encryptedBytes = Rsa.Encrypt(Encoding.ASCII.GetBytes(unencryptedPayload), false); //Console.WriteLine("Encrypted: " + Encoding.Default.GetString(encryptedBytes)); var base64Payload = Convert.ToBase64String(encryptedBytes); Console.WriteLine("Base 64:"); Console.WriteLine(base64Payload); var content = new List<KeyValuePair<string, string>>() { new KeyValuePair<string, string>("merchantId", MerchantId), new KeyValuePair<string, string>("operation", OperationCC), new KeyValuePair<string, string>("version", Version), new KeyValuePair<string, string>("creditCardNumberEncrypted", base64Payload), new KeyValuePair<string, string>("referrer", Referrer), }; // if the card number belongs to a shopping cart, cart id should be provided. if the card number will be used // to update an existing order, and auto order, and a customer profile (card already on file), then do not // provide a cart id and a token will be returned. That token is then attached to the appropriate record and // the server side logic will retrieve the credit card from the token vault using the token as the key. if (CartId != null) { content.Add(new KeyValuePair<string, string>("shoppingCartId", CartId)); } var formContent = new FormUrlEncodedContent(content.ToArray()); return PostToTokenVault(formContent); } // ReSharper disable once InconsistentNaming public JsonResult StoreCVV(string cvv) { var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); var timestamp = (long) (DateTime.UtcNow - epoch).TotalMilliseconds; var unencryptedPayload = cvv + "|" + timestamp; var encryptedBytes = Rsa.Encrypt(Encoding.ASCII.GetBytes(unencryptedPayload), false); var base64Payload = Convert.ToBase64String(encryptedBytes); var content = new List<KeyValuePair<string, string>>() { new KeyValuePair<string, string>("merchantId", MerchantId), new KeyValuePair<string, string>("operation", OperationCVV), new KeyValuePair<string, string>("version", Version), new KeyValuePair<string, string>("creditCardCvv2Encrypted", base64Payload), new KeyValuePair<string, string>("referrer", Referrer), }; // if the card number belongs to a shopping cart, cart id should be provided. if the card number will be used // to update an existing order, and auto order, and a customer profile (card already on file), then do not // provide a cart id and a token will be returned. That token is then attached to the appropriate record and // the server side logic will retrieve the credit card from the token vault using the token as the key. if (CartId != null) { content.Add(new KeyValuePair<string, string>("shoppingCartId", CartId)); } var formContent = new FormUrlEncodedContent(content.ToArray()); return PostToTokenVault(formContent); } [DataContract] [SuppressMessage("ReSharper", "InconsistentNaming")] public class JsonResult { [DataMember] internal bool success; [DataMember] internal string maskedValue; [DataMember] internal string cardType; [DataMember] internal string token; [DataMember] internal string errorMessage; public override string ToString() { return $"{nameof(success)}: {success}, {nameof(maskedValue)}: {maskedValue}, {nameof(cardType)}: {cardType}, {nameof(token)}: {token}, {nameof(errorMessage)}: {errorMessage}"; } } // private static int Main() { // // Console.WriteLine("HostedFields.Main executing."); // // const string merchantId = "DEMO"; // const string cartId = "1234567890"; // // var hostedFields = Create(merchantId, cartId); // // // var ccResult = hostedFields.StoreNumber("4444333322221111"); // Console.WriteLine("Result of Storing CC Number:"); // Console.WriteLine(ccResult); // // var cvvResult = hostedFields.StoreCVV("123"); // Console.WriteLine("Result of Storing CVV Number:"); // Console.WriteLine(cvvResult); // // return 0; // } } }
, multiple selections available,
Related content
C# SDK Sample: Customer Credit Cards
C# SDK Sample: Customer Credit Cards
More like this
C# SDK Sample: Initializing Routine
C# SDK Sample: Initializing Routine
More like this
Obtain CyberSource Security Key
Obtain CyberSource Security Key
More like this
Authorize.net integration
Authorize.net integration
More like this
UltraCart Hosted Credit Card Fields
UltraCart Hosted Credit Card Fields
More like this
Collecting Credit Card Numbers with Rest API
Collecting Credit Card Numbers with Rest API
More like this