Мы портируем PHP (Yii Framework) на Java (Play! Framework 2.2.x) и наткнулись на этот фрагмент кода:
$sign = base64_decode($sign64);
// $cert is a string read from a file.
$pubkey = openssl_get_publickey($cert);
// $data is composed of incoming username data, time, etc.
if(openssl_verify("$data", $sign, $pubkey) != 1) {
$this->verifies = false;
} else {
$this->verifies = true;
}
openssl_free_key($pubkey);
Я сократил этот код, чтобы он содержал основы.
$ data — это поле, отправленное с запросом GET.
$ sign64 — другое поле, отправленное с этим GET-запросом. Он предоставляется другим сервером и является подписью, которая проверяет достоверность отправленных данных.
Файл $ cert содержит строку «—— BEGIN CERTIFICATE ——«.
Поэтому я должен спросить; Что является стандартным способом реализации этого кода проверки в Java?
В частности, мы используем Play! Фреймворк. До сих пор я сделал следующее:
String sign = new String(javax.xml.bind.DatatypeConverter.parseBase64Binary(sign64));
java.io.FileInputStream filestream = new java.io.FileInputStream(new java.io.File("certificate.crt"));
java.security.cert.CertificateFactory cf = java.security.cert.CertificateFactory.getInstance("X.509");
java.security.cert.Certificate cert = cf.generateCertificate(filestream);
java.security.PublicKey pubkey = cert.getPublicKey();
try
{
cert.verify(pubkey, sign64); // This seems to be the closest to what I desire...
}
catch (...)
{
// Here I output the error message...
}
В итоге я получаю исключение NoSuchProviderException. Он показывает некоторый загадочный текст, который совпадает со строкой «знак». Мой вопрос: я делаю что-то в корне неправильно? Является ли parseBase64Binary правильным? Является ли метод подписи правильным? Не должно быть; так как я здесь вообще не подписываю переменную данных. Как мне сделать это правильно в Java / Play! Фреймворк?
Проблема была решена с помощью следующего кода: (Это для тех, у кого тот же вопрос)
import java.security.*;
// ...
public static boolean verifySignature(String data, PublicKey key, byte[] signature) throws Exception {
Signature signer = Signature.getInstance("SHA1withRSA");
signer.initVerify(key);
signer.update(data.getBytes());
return (signer.verify(signature));
}
Открытый ключ читается с использованием кода, приведенного в вопросе. Подпись использует:
byte [] sign = java.util.Base64.getDecoder (). decode (sign64);
Самой большой проблемой было выяснить, какой алгоритм использовать. Пример, из которого я получил приведенный выше код, был «SHA1withDSA», многое было перепробовано. В конце концов строка «SHA1withRSA» сработала. Он правильно проверяет подписанные данные от нашего поставщика данных.
Других решений пока нет …