InvalidKeyException:非法密钥大小-Java代码为加密类引发异常-如何修复



我一直在尝试获得一些可用的Java代码来加密Paypal按钮。这不是一件容易的事!即使我从Paypal获得一些代码,我也会面临错误。。呃。。

这就是我目前所拥有的,我认为它最终会起作用。

我从贝宝的网站下载了Java.zip文件。其中有两个类-ClientSide.java和ButtonEncryption.java

问题-我收到一个InvalidKeyException : Illegal key size错误。

问题
1) 如何解决此问题?2) 哪行代码引发了错误?

C:jakarta-tomcatwebappsPlanBWEB-INFclasses>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)


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's 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=_xclicknbusiness=buyer@hotmail.comnitem_name=vasenitemprice=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's 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();
        }
    }
}


已编辑:有关密钥/证书的信息

我通过以下命令用OpenSSL生成了私钥和公钥证书。
私钥
openssl genrsa-out私钥.pem 1024
公共证书
openssl req-new-key privatekey.pem-x509-days 1095-out public-cert.pem
已创建PKCS12文件
openssl pkcs12-export-in-public-cert.pem-inkey privatekey.pem-out my_pkcs12.p12


此外,我必须从贝宝网站下载贝宝公共证书。


已编辑-添加编译警告-BouncyCastle

C:jakarta-tomcatwebappsPlanBWEB-INFclasses>javac .palmbservletspaypalClientSide.java -Xlint
.palmbservletspaypalClientSide.java:85: warning: [deprecation] addSigner(java.security.PrivateKey,java.security.cert.X509Certificate,java.lang.String) in org.bouncycastle.cms.CMSSignedDataGenerator has been deprecated
                signedGenerator.addSigner( privateKey, certificate, CMSSignedDat
aGenerator.DIGEST_SHA1 );
                               ^
.palmbservletspaypalClientSide.java:88: warning: [unchecked] unchecked call
to add(E) as a member of the raw type java.util.ArrayList
                certList.add(certificate);
                            ^
.palmbservletspaypalClientSide.java:90: warning: [deprecation] addCertificatesAndCRLs(java.security.cert.CertStore) in org.bouncycastle.cms.CMSSignedGenerat
or has been deprecated
                signedGenerator.addCertificatesAndCRLs(certStore);
                               ^
.palmbservletspaypalClientSide.java:97: warning: [deprecation] generate(org.
bouncycastle.cms.CMSProcessable,boolean,java.lang.String) in org.bouncycastle.cm
s.CMSSignedDataGenerator has been deprecated
                CMSSignedData signedData = signedGenerator.generate(cmsByteArray, true, "BC");
                                                          ^
.palmbservletspaypalClientSide.java:102: warning: [deprecation] addKeyTransR
ecipient(java.security.cert.X509Certificate) in org.bouncycastle.cms.CMSEnvelope
dGenerator has been deprecated
                envGenerator.addKeyTransRecipient(payPalCert);
                            ^
.palmbservletspaypalClientSide.java:103: 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 CMSProcess
ableByteArray(signed),
                                                       ^
6 warnings


JCE策略文件安装步骤

以下是我安装JCE无限制强度策略文件的步骤:
1) 访问了Oracle上的Java JCE下载页面
2) 从zip中提取的文件
3) 将local_policy.jar和US_export_policy.jar文件放在C:\Java\jdk1.6.0_22\jre\lib\security文件夹中
注意:C:\Java\jdk1.6.0_22设置为%Java_HOME%
4) 更新了系统类路径以包括jar的位置。
注意:JDK1.6附带的安全文件夹中还有其他文件,包括:java.policy、java.security、javaws.policy、trusted.libraries,但这些文件可能与JCE文件无关,对吧?


编辑2011年6月23日-进一步配置后的结果

我在上访问了Bouncy Castle页面http://www.bouncycastle.org/specifications.html#install
向下滚动至5.0 Bouncy Castle Provider,然后阅读5.1示例下的信息。它提到将Bouncy Castle Provider的参数添加到java.security文件中。我的文件位于C:\Java\jdk1.6.0_22\jre\lib\security下。

我在文件中添加了以下行-security.provider.10=org.bouncycastle.jce.provider.BouncyCastleProvider

此外,我发现我没有将Bouncy Castle jar添加到类路径中,所以我继续这样做了。

现在,在进行了这些更改、重新编译并尝试执行ClientSide.java之后,我得到了同样的异常:但也许重点应该放在异常中关于bouncycastle提供者-的部分

at org.bouncycastle.jce.provider.JDKPKCS12KeyStore.cryptData(Unknown Source)
at org.bouncycastle.jce.provider.JDKPKCS12KeyStore.engineLoad(Unknown Source)

@PeteryB-我确信我正确安装了策略文件。根据我在这里所说的,你还有什么可以建议我试试的吗?你能看看Bouncy Castle网站吗?@http://www.bouncycastle.org/specifications.html#install看看有没有我遗漏的东西

所以问题一定出在您的JCE Unlimited Strength安装上。

请确保覆盖JDK的jdk1.6.0_25jrelibsecurity和JRE的libsecurity文件夹中的local_policy.jarUS_export_policy.jar

在我的情况下,我会把新的.罐子放在:

C:Program FilesJavajdk1.6.0_25jrelibsecurity

C:Program FilesJavajre6libsecurity


如果您正在运行Java 8并遇到此问题。以下步骤应该会有所帮助!

转到JRE安装(例如-jre1.8.0_181\lib\security\policy\unlimited),复制local_policy.jar并在JDK安装目录(例如-jdk1.8.0_141\JRE\lib\security)中将其替换为"local_policy.jar"。

如果使用256位密钥运行我的AES加密程序时仍收到InvalidKeyException,但不是使用128位密钥,这是因为您没有正确安装新的策略JAR文件,并且与BouncyCastle无关(它也受到这些策略文件的限制)。试着卸载,然后重新安装java,然后用新的无限强度的jar替换旧的jar。除此之外,我没什么想法,祝你好运。

如果您在winzip中打开lib/security/local_policy.jar和US_export_policy.jar文件,并在记事本中查看conatined*.policy文件,并确保它们看起来像这样,则可以看到策略文件本身:

default_local.policy:

    // Country-specific policy file for countries with no limits on crypto strength.
grant {
    // There is no restriction to any algorithms.
    permission javax.crypto.CryptoAllPermission; 
};

default_US_export.policy:

// Manufacturing policy file.
grant {
    // There is no restriction to any algorithms.
    permission javax.crypto.CryptoAllPermission; 
};

在客户端代码中添加以下代码:

static {
    Security.insertProviderAt(new BouncyCastleProvider(),1);
 }

这样就不需要在java.security文件中添加任何条目。

当您尝试从"C:\jakarta tomcat/webapps/PlanB/Certs/my_pkcs12.p12"此处加载它们的密钥库时,似乎引发了错误:

ks.load( new FileInputStream(_privateKeyPath), _keyPass.toCharArray() ); 

您是否尝试将文件路径中的"/"替换为"\\"?如果这没有帮助,那可能与Java的无限强度管辖权策略文件有关。您可以通过编写一个执行AES加密的小程序来检查这一点。尝试使用128位密钥加密,如果有效,则尝试使用256位密钥,看看是否失败。

执行AES加密的代码:

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class Test 
{
    final String ALGORITHM = "AES";                       //symmetric algorithm for data encryption
    final String PADDING_MODE = "/CBC/PKCS5Padding";      //Padding for symmetric algorithm
    final String CHAR_ENCODING = "UTF-8";                 //character encoding
    //final String CRYPTO_PROVIDER = "SunMSCAPI";             //provider for the crypto
    int AES_KEY_SIZE = 256;  //symmetric key size (128, 192, 256) if using 256 you must have the Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files  installed
    private String doCrypto(String plainText) throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, UnsupportedEncodingException
    {
        byte[] dataToEncrypt = plainText.getBytes(CHAR_ENCODING);
        //get the symmetric key generator
        KeyGenerator keyGen = KeyGenerator.getInstance(ALGORITHM);
        keyGen.init(AES_KEY_SIZE); //set the key size
        //generate the key
        SecretKey skey = keyGen.generateKey();
        //convert to binary
        byte[] rawAesKey = skey.getEncoded();
        //initialize the secret key with the appropriate algorithm
        SecretKeySpec skeySpec = new SecretKeySpec(rawAesKey, ALGORITHM);
        //get an instance of the symmetric cipher
        Cipher aesCipher = Cipher.getInstance(ALGORITHM + PADDING_MODE);
        //set it to encrypt mode, with the generated key
        aesCipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        //get the initialization vector being used (to be returned)
        byte[] aesIV = aesCipher.getIV();
        //encrypt the data
        byte[] encryptedData = aesCipher.doFinal(dataToEncrypt);    
        //initialize the secret key with the appropriate algorithm
        SecretKeySpec skeySpecDec = new SecretKeySpec(rawAesKey, ALGORITHM);
        //get an instance of the symmetric cipher
        Cipher aesCipherDec = Cipher.getInstance(ALGORITHM +PADDING_MODE);
        //set it to decrypt mode with the AES key, and IV
        aesCipherDec.init(Cipher.DECRYPT_MODE, skeySpecDec, new IvParameterSpec(aesIV));
        //decrypt and return the data
        byte[] decryptedData = aesCipherDec.doFinal(encryptedData);
        return new String(decryptedData, CHAR_ENCODING);
    }
    public static void main(String[] args)
    {
        String text = "Lets encrypt me";
        Test test = new Test();
        try {
            System.out.println(test.doCrypto(text));
        } catch (InvalidKeyException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchProviderException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (BadPaddingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

这个代码对你有用吗?

您可能还想尝试在以下行中指定您的充气城堡提供商:

Cipher.getInstance(ALGORITHM +PADDING_MODE, "YOUR PROVIDER");

看看这是否是一个与充气城堡有关的错误。

我也面临同样的问题。尝试先在java安全文件夹中添加US_export_policy.jarlocal_policy.jar,但问题仍然存在。然后在tomcat setenv.sh文件中的java_opts中添加以下内容,就成功了。

-Djdk.tls.ephemeralDHKeySize=2048

请查看此链接以获取更多信息

相关内容

最新更新