InvalidKeyException: недопустимый размер ключа - исключение для кода Java для класса шифрования - как это исправить? - PullRequest
36 голосов
/ 16 июня 2011

Я пытался получить работающий Java-код для шифрования кнопок Paypal. Это нелегкая задача! Даже когда я получаю некоторый код от Paypal, я сталкиваюсь с ошибками .. тьфу ..

Итак, вот что у меня есть, и я думаю, что в конечном итоге это сработает.

Я скачал файл Java.zip с веб-сайта Paypal. Внутри него есть два класса - ClientSide.java и ButtonEncryption.java

Проблема - Я получаю InvalidKeyException : Illegal key size ошибку.

Вопросы
1) Как мне решить эту проблему? 2) Какая строка кода выдает ошибку?

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)


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 class

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=_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'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 private-key.pem 1024
Публичный сертификат
openssl req -new -key private-key.pem -x509 -days 1095 -out public-cert.pem
Создан файл PKCS12
openssl pkcs12 -export -in public-cert.pem -inkey private-key.pem -out my_pkcs12.p12


Кроме того, мне пришлось загрузить общедоступный сертификат Paypal с веб-сайта Paypal.


Отредактировано - добавление предупреждений компиляции - BouncyCastle

C:\jakarta-tomcat\webapps\PlanB\WEB-INF\classes>javac .\palmb\servlets\paypal\ClientSide.java -Xlint
.\palmb\servlets\paypal\ClientSide.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 );
                               ^
.\palmb\servlets\paypal\ClientSide.java:88: 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:90: warning: [deprecation] addCertificatesAndCRLs(java.security.cert.CertStore) in org.bouncycastle.cms.CMSSignedGenerat
or has been deprecated
                signedGenerator.addCertificatesAndCRLs(certStore);
                               ^
.\palmb\servlets\paypal\ClientSide.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");
                                                          ^
.\palmb\servlets\paypal\ClientSide.java:102: warning: [deprecation] addKeyTransR
ecipient(java.security.cert.X509Certificate) in org.bouncycastle.cms.CMSEnvelope
dGenerator has been deprecated
                envGenerator.addKeyTransRecipient(payPalCert);
                            ^
.\palmb\servlets\paypal\ClientSide.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) Пошел на Java JCE Скачать Страница в Oracle.
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) Обновлен системный путь к классам, чтобы включить расположение банок.
Примечание. В папке security находятся другие файлы, поставляемые с JDK 1.6, в том числе: java.policy, java.security, javaws.policy, trust.libraries - но они, вероятно, не имеют ничего общего с файлами JCE, верно?

<Ч />

Редактировать 23.06.2011 - результаты после дальнейшей настройки

Я зашел на страницу Bouncy Castle в http://www.bouncycastle.org/specifications.html#install
Прокрутите вниз до 5.0 Поставщик Bouncy Castle , затем прочитайте информацию в 5.1 Пример . В нем упоминается о добавлении параметра для поставщика Bouncy Castle в файл java.security. Мой файл находится в C: \ Java \ jdk1.6.0_22 \ jre \ lib \ security.

Я добавил в свой файл следующую строку - security.provider.10=org.bouncycastle.jce.provider.BouncyCastleProvider

Кроме того, я обнаружил, что я не добавил баночки Bouncy Castle в путь к классам, поэтому я пошел дальше и сделал это.

Теперь, после внесения этих изменений, перекомпиляции и попытки выполнить ClientSide.java я получил то же исключение: но, возможно, основное внимание должно быть уделено той части исключения, где говорится о провайдере bouncycastle -

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

@ PeteyB - Я уверен, что правильно установил файлы политики. Исходя из того, что я здесь изложил, есть ли что-нибудь еще, что вы можете предложить мне попробовать? Можете ли вы взглянуть на сайт Bouncy Castle @ http://www.bouncycastle.org/specifications.html#install и посмотреть, есть ли что-то, чего мне не хватает?

Ответы [ 5 ]

73 голосов
/ 17 июня 2011

Таким образом, проблема должна быть в вашей установке JCE Unlimited Strength.

Убедитесь, что вы перезаписали local_policy.jar и US_export_policy.jar как в вашем JDK jdk1.6.0_25\jre\lib\security\, так и в папке lib\security\ вашего JRE.

В моем случае я бы поместил новые .jarsв:

C:\Program Files\Java\jdk1.6.0_25\jre\lib\security

и

C:\Program Files\Java\jre6\lib\security


Если вы работаете Java 8 и выстолкнуться с этой проблемой.Следующие шаги должны помочь!

Перейдите к вашей установке JRE (например, - jre1.8.0_181 \ lib \ security \ policy \ unlimited) скопируйте local_policy.jar и замените его на 'local_policy.jar'в вашем каталоге установки JDK (например, - jdk1.8.0_141 \ jre \ lib \ security).

6 голосов
/ 23 июня 2011

Если вы все еще получаете исключение InvalidKeyException при запуске моей программы шифрования AES с 256-битными ключами, но не с 128-битными ключами, это потому, что вы неправильно установили файлы JAR новой политики и не имеете ничего общего с BouncyCastle ( который также ограничен этими файлами политики). Попробуйте удалить, затем переустановить Java, а затем заменить старые банки на новые с неограниченной прочностью. Кроме этого, у меня нет идей, удачи.

Вы можете увидеть сами файлы политики, если откроете файлы lib / security / local_policy.jar и US_export_policy.jar в winzip и посмотрите на объединенные файлы * .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; 
};
4 голосов
/ 23 августа 2012

Добавьте ниже код в вашем коде клиента:

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

при этом нет необходимости добавлять какие-либо записи в файл java.security.

1 голос
/ 17 июня 2011

Ошибка выдается, когда вы пытаетесь загрузить их хранилище ключей из "C: /jakarta-tomcat/webapps/PlanB/Certs/my_pkcs12.p12" здесь:

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

Вы пытались заменить"/" с "\\" в вашем пути к файлу?Если это не помогает, возможно, это связано с файлами политики Java Unlimited Strength Jurisdiction.Вы можете проверить это, написав небольшую программу, которая выполняет шифрование 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");

И посмотрите, может ли это быть ошибка, связанная с надувным замком.

0 голосов
/ 06 декабря 2017

Я столкнулся с той же проблемой.Попытался сначала добавить US_export_policy.jar и local_policy.jar в папку безопасности java, но проблема осталась.Затем добавили ниже в java_opts внутри tomcat setenv.sh файл, и он заработал.

-Djdk.tls.ephemeralDHKeySize=2048

Пожалуйста, проверьте эту ссылку для получения дополнительной информации

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...