Java code to encrypt PayPal buttons using legacy BouncyCastle methods - how to fix it?

I am really trying to get working code, good examples and, most importantly, good documentation on how to use Paypal Java SDK to encrypt payments on the site. I turned to Paypal for help (posted on their forum, contacted support), but have not received any help yet.

I went to https://www.paypal.com/us/cgi-bin/?cmd=p/xcl/rec/e wp code and downloaded the Paypal Java SDK. Inside zip there is a ReadMe.txt file with configuration instructions. The instructions are quite simple.

I went to the Bouncy Castle website - http://www.bouncycastle.org/latest_releases.html - download the latest versions of the following jars:
bcmail-jdk16-146.jar
bcpg-jdk16-146.jar
bcprov-jdk16-146.jar
bctest- jdk16-146.jar

Then I went to the http://www.oracle.com/technetwork/java/javase/down uploads /index.html to upload the jurisdiction protection policy files for the Java Cryptography Extension (JCE) unlimited power.

I put all the JARS in the appropriate folders, updated the class path, and then tried to compile the ClientSide.java class that came with the Paypal Java SDK.

The compiler tells me that obsolete classes exist, showing me the following errors after recompiling with -Xlint.

.\palmb\servlets\paypal\ClientSide.java:98: warning: [deprecation] addSigner(jav
a.security.PrivateKey,java.security.cert.X509Certi​ficate,java.lang.String) in org.bouncycastle.cms.CMSSignedDataGenerator has been deprecated
                signedGenerator.addSigner( privateKey, certificate, CMSSignedDataGenerator.DIGEST_SHA1 );
                               ^
.\palmb\servlets\paypal\ClientSide.java:101: warning: [unchecked] unchecked call
 to add(E) as a member of the raw type java.util.ArrayList
                certList.add(certificate);
                            ^
.\palmb\servlets\paypal\ClientSide.java:103: warning: [deprecation] addCertificatesAndCRLs(java.security.cert.CertStor​e) in org.bouncycastle.cms.CMSSignedGenerator has been deprecated
                signedGenerator.addCertificatesAndCRLs(certStore);
                               ^
.\palmb\servlets\paypal\ClientSide.java:110: warning: [deprecation] generate(org.bouncycastle.cms.CMSProcessable,boole​an,java.lang.String) in org.bouncycastle.cms.CMSSignedDataGenerator has been deprecated
                CMSSignedData signedData = signedGenerator.generate(cmsByteArray, true, "BC");
                                                  ​        ^
.\palmb\servlets\paypal\ClientSide.java:115: warning: [deprecation] addKeyTransRecipient(java.security.cert.X509Certif​icate) in org.bouncycastle.cms.CMSEnvelopedGenerator has been deprecated  envGenerator.addKeyTransRecipient(payPalCert);
                            ^
.\palmb\servlets\paypal\ClientSide.java:116: warning: [deprecation] generate(org.bouncycastle.cms.CMSProcessable,java.​lang.String,java.lang.String) in org.bouncycastle.cms.CMSEnvelopedDataGenerator has been deprecated
                CMSEnvelopedData envData = envGenerator.generate( new CMSProcessableByteArray(signed),
                                                  ​     ^
6 warnings

Java 1.6, . Paypal , , , , , .

Bouncy Castle (www.bouncycastle.org) (http://www.bouncycastle.org/documentation.html) 1.6 - , , .

- Java Paypal? BouncyCastle ? , .


ClientSide

package palmb.servlets.paypal;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertStore;
import java.security.cert.CertStoreException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Enumeration;

import org.bouncycastle.cms.CMSEnvelopedData;
import org.bouncycastle.cms.CMSEnvelopedDataGenerator;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.openssl.PEMReader;
import org.bouncycastle.util.encoders.Base64;

/**
 */
public class ClientSide 
{
    private String  keyPath;
    private String  certPath;
    private String  paypalCertPath;
    private String  keyPass;

    public ClientSide( String keyPath, String certPath, String paypalCertPath, String keyPass )
    {
        this.keyPath = keyPath;
        this.certPath = certPath;
        this.paypalCertPath = paypalCertPath;
        this.keyPass = keyPass;
    }   

    public String getButtonEncryptionValue(String _data, String _privateKeyPath, String _certPath, String _payPalCertPath,
                                            String _keyPass) throws IOException,CertificateException,KeyStoreException,
                                            UnrecoverableKeyException,InvalidAlgorithmParameterException,NoSuchAlgorithmException,
                                            NoSuchProviderException,CertStoreException,CMSException {
        _data = _data.replace(',', '\n');
        CertificateFactory cf = CertificateFactory.getInstance("X509", "BC");

        // Read the Private Key
        KeyStore ks = KeyStore.getInstance("PKCS12", "BC");
        ks.load( new FileInputStream(_privateKeyPath), _keyPass.toCharArray() );

        String keyAlias = null;
        Enumeration aliases = ks.aliases();
        while (aliases.hasMoreElements()) {
            keyAlias = (String) aliases.nextElement();
        }

        PrivateKey privateKey = (PrivateKey) ks.getKey( keyAlias, _keyPass.toCharArray() );

        // Read the Certificate
        X509Certificate certificate = (X509Certificate) cf.generateCertificate( new FileInputStream(_certPath) );

        // Read the PayPal Cert
        X509Certificate payPalCert = (X509Certificate) cf.generateCertificate( new FileInputStream(_payPalCertPath) );

        // Create the Data
        byte[] data = _data.getBytes();

        // Sign the Data with my signing only key pair
        CMSSignedDataGenerator signedGenerator = new CMSSignedDataGenerator();

        signedGenerator.addSigner( privateKey, certificate, CMSSignedDataGenerator.DIGEST_SHA1 );

        ArrayList certList = new ArrayList();
        certList.add(certificate);
        CertStore certStore = CertStore.getInstance( "Collection", new CollectionCertStoreParameters(certList) );
        signedGenerator.addCertificatesAndCRLs(certStore);

        CMSProcessableByteArray cmsByteArray = new CMSProcessableByteArray(data);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        cmsByteArray.write(baos);
        System.out.println( "CMSProcessableByteArray contains [" + baos.toString() + "]" );

        CMSSignedData signedData = signedGenerator.generate(cmsByteArray, true, "BC");

        byte[] signed = signedData.getEncoded();

        CMSEnvelopedDataGenerator envGenerator = new CMSEnvelopedDataGenerator();
        envGenerator.addKeyTransRecipient(payPalCert);
        CMSEnvelopedData envData = envGenerator.generate( new CMSProcessableByteArray(signed),
                CMSEnvelopedDataGenerator.DES_EDE3_CBC, "BC" );

        byte[] pkcs7Bytes = envData.getEncoded();


        return new String( DERtoPEM(pkcs7Bytes, "PKCS7") );

    }

    public static byte[] DERtoPEM(byte[] bytes, String headfoot) 
    {
        ByteArrayOutputStream pemStream = new ByteArrayOutputStream();
        PrintWriter writer = new PrintWriter(pemStream);

        byte[] stringBytes = Base64.encode(bytes);

        System.out.println("Converting " + stringBytes.length + " bytes");

        String encoded = new String(stringBytes);

        if (headfoot != null) {
            writer.print("-----BEGIN " + headfoot + "-----\n");
        }

        // write 64 chars per line till done
        int i = 0;
        while ((i + 1) * 64 < encoded.length()) {
            writer.print(encoded.substring(i * 64, (i + 1) * 64));
            writer.print("\n");
            i++;
        }
        if (encoded.length() % 64 != 0) {
            writer.print(encoded.substring(i * 64)); // write remainder
            writer.print("\n");
        }
        if (headfoot != null) {
            writer.print("-----END " + headfoot + "-----\n");
        }
        writer.flush();
        return pemStream.toByteArray();
    }

}


ButtonEncryption

package palmb.servlets.paypal;

//import com.paypal.crypto.sample.*;

import palmb.servlets.paypal.ClientSide;

import java.io.*;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertStoreException;
import java.security.cert.CertificateException;
import org.bouncycastle.cms.CMSException;

/**
 */
public class ButtonEncryption {


    //path to public cert
    private static String certPath = "C:/jakarta-tomcat/webapps/PlanB/Certs/public-cert.pem";

    //path to private key in PKCS12 format
    private static String keyPath = "C:/jakarta-tomcat/webapps/PlanB/Certs/my_pkcs12.p12";

    //path to Paypal public cert
    private static String paypalCertPath = "C:/jakarta-tomcat/webapps/PlanB/Certs/paypal_cert_pem.txt";

    //private key password
    private static String keyPass = "password"; //will be replaced with actual password when compiled and executed

    //the button command, properties/parameters
    private static String cmdText = "cmd=_xclick\nbusiness=buyer@hotmail.com\nitem_name=vase\nitemprice=25.00";  //cmd=_xclick,business=sample@paypal.com,amount=1.00,currency_code=USD

    //output file for form code
    private static String output = "test.html";


    public static void main(String[] args) 
    {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); 


        String stage = "sandbox";

        try 
        {
            ClientSide client_side = new ClientSide( keyPath, certPath, paypalCertPath, keyPass );

            String result = client_side.getButtonEncryptionValue( cmdText, keyPath, certPath, paypalCertPath, keyPass );

            File outputFile = new File( output );
            if ( outputFile.exists() )
                outputFile.delete();

            if ( result != null && result != "")
            {
                try {        
                    OutputStream fout= new FileOutputStream( output );
                    OutputStream bout= new BufferedOutputStream(fout);
                    OutputStreamWriter out = new OutputStreamWriter(bout, "US-ASCII");

                    out.write( "<form action=\"https://www." );
                    out.write( stage );
                    out.write( "paypal.com/cgi-bin/webscr\" method=\"post\">" );  
                    out.write( "<input type=\"hidden\" name=\"cmd\" value=\"_s-xclick\">" );  ;
                    out.write( "<input type=\"image\" src=\"https://www." );
                    out.write( stage );
                    out.write( "paypal.com/en_US/i/btn/x-click-but23.gif\" border=\"0\" name=\"submit\" " );
                    out.write( "alt=\"Make payments with PayPal - it fast, free and secure!\">" );
                    out.write( "<input type=\"hidden\" name=\"encrypted\" value=\"" );
                    out.write( result );
                    out.write( "\">" );
                    out.write( "</form>");

                    out.flush();  // Don't forget to flush!
                    out.close();
                  }
                  catch (UnsupportedEncodingException e) {
                    System.out.println(
                     "This VM does not support the ASCII character set."
                    );
                  }
                  catch (IOException e) {
                    System.out.println(e.getMessage());        
                  }
            }
        } 
        catch (NoSuchAlgorithmException e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
        catch (NoSuchProviderException e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
        catch (IOException e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
        catch (CMSException e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
        catch (CertificateException e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
        catch (KeyStoreException e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
        catch (UnrecoverableKeyException e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
        catch (InvalidAlgorithmParameterException e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
        catch (CertStoreException e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}


- ButtonEncryption

C:\jakarta-tomcat\webapps\PlanB\WEB-INF\classes>java palmb.servlets.paypal.ButtonEncryption
java.io.IOException: exception decrypting data - java.security.InvalidKeyException: Illegal key size
        at org.bouncycastle.jce.provider.JDKPKCS12KeyStore.cryptData(Unknown Source)
        at org.bouncycastle.jce.provider.JDKPKCS12KeyStore.engineLoad(Unknown Source)
        at java.security.KeyStore.load(Unknown Source)
        at palmb.servlets.paypal.ClientSide.getButtonEncryptionValue(ClientSide.
java:63)
        at palmb.servlets.paypal.ButtonEncryption.main(ButtonEncryption.java:81)
+3
2

Paypal , API Paypal. . Java, Paypal . , .

API Paypal, .

0

KeySize, JCE . , JRE.

... PayPal, ( bouncycastle javadoc):

private final static String getButtonEncryptionValue(String commandData, String keystorePath,
        String keystorePassword, boolean sandbox) throws IOException, CertificateException, KeyStoreException,
        UnrecoverableKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException,
        NoSuchProviderException, CertStoreException, CMSException, OperatorCreationException {

    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

    commandData = commandData.replace(',', '\n');
    CertificateFactory cf = CertificateFactory.getInstance("X509", "BC");

    // Read the Private Key
    KeyStore ks = KeyStore.getInstance("PKCS12", "BC");
    ks.load(new FileInputStream(keystorePath), keystorePassword.toCharArray());

    String keyAlias = null;
    Enumeration<String> aliases = ks.aliases();
    while (aliases.hasMoreElements()) {
        keyAlias = (String) aliases.nextElement();
    }

    PrivateKey privateKey = (PrivateKey) ks.getKey(keyAlias, keystorePassword.toCharArray());

    // Read the Certificate
    X509Certificate certificate = (X509Certificate) cf.generateCertificate(ApplicationProxyService.class
            .getResourceAsStream("/myCompanyPublicCert.pem.cer"));

    // Read the PayPal Cert
    X509Certificate payPalCert = (X509Certificate) cf.generateCertificate(ApplicationProxyService.class
            .getResourceAsStream("/paypalPublicCert" + (sandbox ? "-sandbox" : "") + ".pem.cer"));

    // Create the Data
    // System.out.println(commandData);
    byte[] data = commandData.getBytes();

    // Sign the Data with my signing only key pair
    CMSSignedDataGenerator signedGenerator = new CMSSignedDataGenerator();

    List<X509Certificate> certList = new ArrayList<X509Certificate>();
    certList.add(certificate);

    //deprecated: Store certStore = CertStore.getInstance("Collection", new CollectionCertStoreParameters(certList));
    Store certStore = new JcaCertStore(certList);

    // deprecated: signedGenerator.addCertificatesAndCRLs(certStore);
    signedGenerator.addCertificates(certStore);

    // deprecated: signedGenerator.addSigner(privateKey, certificate, CMSSignedDataGenerator.DIGEST_SHA1);

    ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(privateKey);
    signedGenerator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(
            new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()).build(sha1Signer, certificate));

    CMSProcessableByteArray cmsByteArray = new CMSProcessableByteArray(data);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    cmsByteArray.write(baos);
    LOGGER.debug("CMSProcessableByteArray contains [" + baos.toString() + "]");

    // deprecated: CMSSignedData signedData = signedGenerator.generate(cmsByteArray, true, "BC");
    CMSSignedData signedData = signedGenerator.generate(cmsByteArray, true);

    byte[] signed = signedData.getEncoded();

    CMSEnvelopedDataGenerator envGenerator = new CMSEnvelopedDataGenerator();

    // deprecated: envGenerator.addKeyTransRecipient(payPalCert);
    envGenerator.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(payPalCert).setProvider("BC"));

    // deprecated: CMSEnvelopedData envData = envGenerator.generate(new CMSProcessableByteArray(signed),
    // CMSEnvelopedDataGenerator.DES_EDE3_CBC, "BC");
    CMSEnvelopedData envData = envGenerator.generate(new CMSProcessableByteArray(signed),
            new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider("BC").build());

    byte[] pkcs7Bytes = envData.getEncoded();

    return new String(DERtoPEM(pkcs7Bytes, "PKCS7"));

}

, DERtoPEM() , , 64 (0% 64 == 0 64% 64 == 0). :

private static final byte[] DERtoPEM(byte[] bytes, String headfoot) {

    byte[] stringBytes = Base64.encode(bytes);

    // System.out.println("Converting " + stringBytes.length + " bytes");
    StringBuilder sb = new StringBuilder();
    sb.append("-----BEGIN " + headfoot + "-----\n");
    String encoded = new String(stringBytes);
    // write 64 chars per line till done
    int i = 0;
    while ((i + 1) * 64 < encoded.length()) {
        sb.append(encoded.substring(i * 64, (i + 1) * 64));
        sb.append("\n");
        i++;
    }
    // if (encoded.length() % 64 != 0) { //FIXME (fixed via next line): this is a BUG that drops remaining data if data.length==64!
    String remainder = encoded.substring(i * 64);
    if (StringUtils.isNotEmpty(remainder)) {
        sb.append(remainder); // write remainder
        sb.append("\n");
    }
    sb.append("-----END " + headfoot + "-----\n");
    return sb.toString().getBytes();

}
+1

All Articles