Integrating encrypted paypal buttons is a pain! Hopefully this helps.
Basically it is a 4 stage process. I have put it together from postings on other sites. None of this is my own work so I can't take credit for it but I'm putting it all here in one place to hopefully save you time.
The code is provided AS IS. It works for me but it may not work for you. I offer no guarantees and I am unable to offer any help with modifying it. I host my applications at maximumasp.com so I can tell you this works on their VPS servers (Gratuitous plug: Maximumasp are great and my refferal number is DSHD-6726).
The sites where I found this information are:
http://www.pdncommunity.com/pdn/board/message?board.id=ewp&thread.id=4
http://www.paypaldeveloper.com/pdn/board/message?board.id=ewp&message.id=373&query.id=33453#M373
http://dotnetdiscussion.net/2008/02/27/aspnet-how-to-integrate-both-google-checkout-and-paypal-in-3-steps/
https://www.paypal.com/IntegrationCenter/ic_button-encryption.html#step2
The p12 certificate
Download and install Win32 OpenSSL from Shining Light Productions. Then Create a private key:
openssl genrsa -out my-prvkey.pem 1024
Create a public cert using the private key:
openssl req -new -key my-prvkey.pem -x509 -days 3650 -out my-pubcert.pem
Export the private key and public cert to PKCS#12 format:
openssl pkcs12 -export -inkey my-prvkey.pem -in my-pubcert.pem -out mycert.p12
You will be prompted for creating a password when you export to PKCS#12 format. Remember the password. You will need the .p12 file and its password when you use this class.
If you are on a shared virtual hosting plan, you may need to contact your hosting company to get them to install the certificate on your server. Send them the .p12 certificate and it's password.
Upload your certificate to your PayPal account to get your "cert_id" for the code behind, download the PayPal certificate and put it in your App_Data folder, then block non encrypted payments. All here: https://www.paypal.com/IntegrationCenter/ic_button-encryption.html#step2
The Form
Add these variables between the form tags of your aspx page
<input type="hidden" name="cmd" value="_s-xclick">
<asp:Literal runat="server" id="strEncrypt" />
Add an asp button with the postback url set to either the sandbox or live paypal site
<asp:Button ID="btnPayPal" runat="server" Text="Pay with PayPal" PostBackUrl="https://www.sandbox.paypal.com/cgi-bin/webscr" />
The code behind
This encrypts your form variables and writes a hidden variable named "encrypted" to the literal "strEncrypt". Put this where it will be executed before the user can click "btnPayPal" (e.g. Page_Load).
Add
Imports com.paypal.demo
Dim
paypalCertPath As String = Server.MapPath("~/App_Data/paypal_cert_pem.txt")
Dim signerPfxPath As String = Server.MapPath("~/App_Data/mycert.p12")
Dim signerPfxPassword As String = "mycert.p12 password" 'testing only - get from secure place when live.
Dim clearText As String = "cmd=_xclick" & vbLf & _
"business=you@yourbusiness.com" & vbLf & _
"currency_code=GBP" & vbLf & _
"item_name=Subscription" & vbLf & _
"amount=15.00" & vbLf & _
"no_shipping=2" & vbLf & _
"no_note=1" & vbLf & _
"return=https://www.yoursite.com/return.aspx" & vbLf & _
"cancel_return=https://www.yoursite.com/cancel.aspx" & vbLf & _
"cert_id=C2XRTSNRF7E2S"
Dim ewp As New ButtonEncryption()
ewp.LoadSignerCredential(signerPfxPath, signerPfxPassword)
ewp.RecipientPublicCertPath = paypalCertPath
Dim result As String = ewp.SignAndEncrypt(clearText)
strEncrypt.Text =
"<input type=""hidden"" name=""encrypted"" value=""" & result & """ />"
The class
This class has been slightly modified from PayPal_HarryX's original to prevent a "System.Security.Cryptography.CryptographicException: The system cannot find the file specified" error. It has also been converted to VB. You can download the original C# version from PayPal_HarryX's post but you need to change:
_signerCert = new X509Certificate2(signerPfxCertPath, signerPfxCertPassword);
to
_signerCert = new X509Certificate2(File.ReadAllBytes(signerPfxCertPath), signerPfxCertPassword, X509KeyStorageFlags.MachineKeySet);
And add the namespaces
using system.IO
using System.Security.Cryptography.X509Certificates
Here is the original. And here is the fix.
Save this class in the App_Code folder of your application.
Here is the modified VB code.
Imports
Microsoft.VisualBasic
Imports System
Imports System.Web
Imports System.Collections.Generic
Imports System.Text
Imports System.Security.Cryptography
Imports Pkcs = System.Security.Cryptography.Pkcs
Imports X509 = System.Security.Cryptography.X509Certificates
Imports System.Security.Cryptography.X509Certificates
Imports System.IONamespace com.paypal.demo
Public Class ButtonEncryption
Private _encoding As Encoding = Encoding.[Default]
Private _recipientPublicCertPath As String
Private _signerCert As X509.X509Certificate2
Private _recipientCert As X509.X509Certificate2Public Sub New()
End Sub
#Region
"Properties"
''' <summary>
''' Character encoding, e.g. UTF-8, Windows-1252
''' </summary>
Public Property Charset() As String
Get
Return _encoding.WebName
End Get
Set(ByVal value As String)
If value IsNot Nothing AndAlso value <> "" Then
_encoding = Encoding.GetEncoding(value)
End If
End Set
End Property
''' <summary>
''' Path to the recipient's public certificate in PEM format
''' </summary>
Public Property RecipientPublicCertPath() As String
Get
Return _recipientPublicCertPath
End Get
Set(ByVal value As String)
_recipientPublicCertPath = value
_recipientCert = New X509.X509Certificate2(_recipientPublicCertPath)
End Set
End Property
#End Region
''' <summary>
'''
''' </summary>
''' <param name="signerPfxCertPath">File path to the signer's public certificate plus private key in PKCS#12 format</param>
''' <param name="signerPfxCertPassword">Password for signer's private key</param>
Public Sub LoadSignerCredential(ByVal signerPfxCertPath As String, ByVal signerPfxCertPassword As String)
Try
_signerCert = New X509.X509Certificate2(File.ReadAllBytes(signerPfxCertPath), signerPfxCertPassword, X509KeyStorageFlags.MachineKeySet)
Catch ex As Exception
Throw New Exception("<b>Signer Cert Path: " & signerPfxCertPath & "</b><br><br>" & ex.ToString())
End Try
End Sub
''' <summary>
''' Sign a message and encrypt it for the recipient.
''' </summary>
''' <param name="clearText">Name value pairs must be separated by \n (vbLf or Chr(10)), for example "cmd=_xclick\nbusiness=..."</param>
''' <returns></returns>
Public Function SignAndEncrypt(ByVal clearText As String) As String
Dim result As String = Nothing
Dim messageBytes As Byte() = _encoding.GetBytes(clearText)
Dim signedBytes As Byte() = Sign(messageBytes)
Dim encryptedBytes As Byte() = Envelope(signedBytes)
result = Base64Encode(encryptedBytes)
Return result
End Function
Private Function Sign(ByVal messageBytes As Byte()) As Byte()
Dim content As New Pkcs.ContentInfo(messageBytes)
Dim signed As New Pkcs.SignedCms(content)
Dim signer As New Pkcs.CmsSigner(_signerCert)
signed.ComputeSignature(signer)
Dim signedBytes As Byte() = signed.Encode()
Return signedBytes
End Function
Private Function Envelope(ByVal contentBytes As Byte()) As Byte()
Dim content As New Pkcs.ContentInfo(contentBytes)
Dim envMsg As New Pkcs.EnvelopedCms(content)
Dim recipient As New Pkcs.CmsRecipient(Pkcs.SubjectIdentifierType.IssuerAndSerialNumber, _recipientCert)
envMsg.Encrypt(recipient)
Dim encryptedBytes As Byte() = envMsg.Encode()
Return encryptedBytes
End Function
Private Function Base64Encode(ByVal encoded As Byte()) As String
Const PKCS7_HEADER As String = "-----BEGIN PKCS7-----"
Const PKCS7_FOOTER As String = "-----END PKCS7-----"
Dim base64 As String = Convert.ToBase64String(encoded)
Dim formatted As New StringBuilder()
formatted.Append(PKCS7_HEADER)
formatted.Append(base64)
formatted.Append(PKCS7_FOOTER)
Return formatted.ToString()
End FunctionEnd Class
End Namespace
Good Luck!
If this post was helpful to you, Please "Mark As Answer".