InvalidKeyException: Недопустимый размер ключа - исключение исключения кода Java для класса шифрования - как исправить?
Я пытаюсь получить некоторый рабочий код 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
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\[email protected]\nitem_name=vase\nitemprice=25.00"; //cmd=_xclick,[email protected],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();
}
}
}
Отредактировано: информация о ключах/сертификатах
Я сгенерировал закрытый ключ и открытый сертификат с 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
Это шаги, которые я предпринял для установки файлов политики безопасности без ограничений:
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) Обновлен путь к системному классу, чтобы включить расположение банок.
Примечание. Существуют другие файлы, которые поставляются вместе с JDK 1.6 в папке безопасности, включая: java.policy, java.security, javaws.policy, trusted.libraries - но они, вероятно, не имеют никакого отношения к файлам JCE, не так ли?
Изменить 6/23/2011 - результаты после дальнейшей настройки
Я отправился на страницу Загадки Загадки в 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 в путь класса, поэтому я пошел вперед и сделал это.
Теперь, после внесения этих изменений, перекомпиляции и попытки выполнить 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 и посмотреть, нет ли чего-то, что мне не хватает?
Ответы
Ответ 1
Таким образом, проблема должна быть связана с установкой JCE Unlimited Strength.
Обязательно перезапишите local_policy.jar
и US_export_policy.jar
как в JDK jdk1.6.0_25\jre\lib\security\
, так и в вашей JRE lib\security\
.
В моем случае я бы разместил новые .jars в:
C:\Program Files\Java\jdk1.6.0_25\jre\lib\security
и
C:\Program Files\Java\jre6\lib\security
Ответ 2
Если вы все еще получаете 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;
};
Ответ 3
Добавьте код кода в код клиента:
static {
Security.insertProviderAt(new BouncyCastleProvider(),1);
}
с этим нет необходимости добавлять какую-либо запись в файл java.security.
Ответ 4
Ошибка, кажется, бросается, когда вы пытаетесь загрузить их хранилище ключей из "C:/jakarta-tomcat/webapps/PlanB/Certs/my_pkcs12.p12" здесь:
ks.load( new FileInputStream(_privateKeyPath), _keyPass.toCharArray() );
Вы пытались заменить "/" на "\\" в вашем пути к файлу? Если это не поможет, возможно, это связано с файлами политики юрисдикции Java Unlimited Strength. Вы можете проверить это, написав небольшую программу, которая шифрует AES. Попробуйте шифровать с помощью 128-битного ключа, а затем, если это работает, попробуйте с помощью 256-битного ключа и посмотрите, не сработает ли он.
Код, который выполняет AES-encyrption:
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");
И посмотрим, может ли это быть ошибка, связанная с надувным замком.
Ответ 5
Я столкнулся с той же проблемой. Сначала пробовал добавлять US_export_policy.jar
и local_policy.jar
в папку безопасности java, но проблема не устранена. Затем добавлено ниже в java_opts
внутри файла tomcat setenv.sh
, и оно сработало.
-Djdk.tls.ephemeralDHKeySize=2048
Пожалуйста, проверьте эту ссылку для получения дополнительной информации