Генерация ключей Java, шифрование php, расшифровка Java

Я просто разрабатываю программное обеспечение с Java-клиентом и PHP-сервером. Клиент Java генерирует 2 ключа RSA. Открытый ключ отправляется с помощью почтового запроса на сервер php. Сервер шифрует ответ с помощью открытого ключа и отправляет его обратно клиенту Java.
Но я получаю эту ошибку:

Exception in thread "main" org.bouncycastle.crypto.InvalidCipherTextException: unknown block type
at org.bouncycastle.crypto.encodings.PKCS1Encoding.decodeBlock(Unknown Source)
at org.bouncycastle.crypto.encodings.PKCS1Encoding.processBlock(Unknown Source)

Насколько я понял, открытый и закрытый ключи не совпадают.
Ошибка появляется в этой строке: (где ответ должен быть расшифрован)
byte[] encodedCipher = asymmetricBlockCipher.processBlock(messageBytes, 0, messageBytes.length);

Так что на самом деле я думаю, что должна быть проблема с кодировкой Base64 открытого ключа или с его передачей, но я не смог ее найти. Если я echo закодированный ключ на сервере, он такой же, как закодированный на клиенте. Но я не нашел ничего полезного в шифровании base64 в последние часы.
Для Base64 в Java я использую это 2 класса:
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

Части моего Java-клиента:

Ключи генерируются: (они сохраняются как поля)

Отсюда: http://www.mysamplecode.com/2011/08/java-generate-rsa-key-pair-using-bouncy.html

private String publicKey;
private byte[] privateKey;

private void generateKeys() throws NoSuchProviderException, NoSuchAlgorithmException {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "BC");
BASE64Encoder base64Encoder = new BASE64Encoder();

SecureRandom rnd = new FixedRand();
generator.initialize(2048, rnd);

KeyPair keyPair = generator.generateKeyPair();
this.publicKey = base64Encoder.encode(keyPair.getPublic().getEncoded()).replaceAll("(?:\\r\\n|\\n\\r|\\n|\\r)", "").trim();
this.privateKey = keyPair.getPrivate().getEncoded();
}

Почтовый запрос: (с клиентом apache http)

private String readUrl(String urlString, String publicKey) throws Exception {
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(urlString);

List<NameValuePair> nameValuePairs = new ArrayList<>(1);
nameValuePairs.add(new BasicNameValuePair("key", publicKey));
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));

HttpResponse response = client.execute(post);

BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String line = "";
StringBuffer responseString = new StringBuffer();
while ((line = rd.readLine()) != null) {
responseString.append(line);
}
return responseString.toString();
}

Часть расшифровки:

private String decrypt(String crypted) throws IOException, InvalidCipherTextException {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

AsymmetricBlockCipher asymmetricBlockCipher = new RSAEngine();
asymmetricBlockCipher = new org.bouncycastle.crypto.encodings.PKCS1Encoding(asymmetricBlockCipher);
BASE64Decoder base64Decoder = new BASE64Decoder();
crypted = new String(base64Decoder.decodeBuffer(crypted));
AsymmetricKeyParameter asymmetricKeyParameter = PrivateKeyFactory.createKey(this.javaKeyToBouncycastle(privateKey));
asymmetricBlockCipher.init(false, asymmetricKeyParameter);

byte[] messageBytes = crypted.getBytes();
byte[] encodedCipher = asymmetricBlockCipher.processBlock(messageBytes, 0, messageBytes.length);

return new String(encodedCipher);
}

private PrivateKeyInfo javaKeyToBouncycastle(byte[] key) throws IOException {
ASN1InputStream pkstream = new ASN1InputStream(key);
return PrivateKeyInfo.getInstance(pkstream.readObject());
}

И часть моего php-сервера: (с phpseclib)

$key = trim(base64_decode($_POST['key'], true));
$rsa = new Crypt_RSA();
$rsa->loadKey($key);
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$crypt = $rsa->encrypt("Hello World");
echo base64_encode($crypt);

Спасибо 🙂
К сожалению, я не знаю много о шифровании банкоматов и большинстве частей кода, которые я нашел с помощью Google и настроил их, но я работаю над этим. (только частный проект)

1

Решение

Вы не должны переносить результат кодировки base 64 в строку.

crypted = new String(base64Decoder.decodeBuffer(crypted));
...
byte[] messageBytes = crypted.getBytes();

Даже если вы выполняете декодирование base 64 до этого, строка не может содержать случайные данные, так как не все данные представляют действительную закодированную строку. Вместо этого просто назначьте байтовый массив новой переменной, например,

byte[] ciphertext = base64Decoder.decodeBuffer(crypted);

и использовать это как вход для asymmetricBlockCipher,

1

Другие решения

Других решений пока нет …