Я пытаюсь реализовать схему проверки PKI, где строка сообщения подписывается закрытым ключом на сервере, подпись хранится на клиенте вместе со строкой сообщения. Затем клиент проверяет подпись с помощью открытого ключа.
Ограничения моей среды: сервер — Google App Engine, а клиент — программа Java. Я играл с решениями проверки PKI только для Java и только для Python и заставил их работать, однако при выполнении одной операции на Python, а другой на Java возникает проблема, в основном из-за ограничений формата файла ключа и моего ограниченного понимания терминологии криптографии. .
Одним из самых больших ограничений является поддержка криптографии в GAE. Единственная поддерживаемая библиотека — PyCrypto, и эта библиотека не может читать открытые/закрытые ключи, хранящиеся в форматах PEM, DER или X509. Насколько я смог найти, только M2Crypto поддерживает чтение из этих файлов, но его нельзя использовать внутри GAE, потому что это оболочка вокруг openssl, а не чистое решение для Python. Даже если бы я смог найти способ перевести открытые/закрытые ключи из PEM/DER/X509 в формат, который понимает PyCrypto, это сработает для меня. Но я не мог найти способ сделать это. Есть идеи?
Я нашел одно возможное решение в виде tlslite. tlslite может прочитать закрытый ключ из файла PEM и создать подпись. Вот код.
from tlslite.utils.cryptomath import bytesToBase64
from tlslite.utils.keyfactory import parsePEMKey
s = open('private.pem').read()
key = parsePEMKey(s)
doc = 'Sample text'
bytes = array('B')
bytes.fromstring(doc)
print bytesToBase64(key.sign(bytes))
Соответствующий код Java, который я использовал для проверки подписи.
String signAlgo = "SHA1WithRSAEncryption";
// read public key from public.der
byte[] encodedKey = new byte[294]; // shortcut hardcoding
getAssets().open("public.der").read(encodedKey);
// create public key object
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey pk = kf.generatePublic(publicKeySpec);
// read signature (created by python code above)
byte[] encodedSig = new byte[345];
getAssets().open("signature.txt").read(encodedSig);
byte[] decodedSig = Base64.decodeBase64(encodedSig);
// Do verification
Signature verifyalg = Signature.getInstance(signAlgo);
verifyalg.initVerify(pk);
verifyalg.update(message.getBytes());
Log.d(TAG, "Verif : "+verifyalg.verify(decodedSig));
Проверка не проходит.
Я подозревал, что tlslite использует другой алгоритм для создания подписи, чем ожидает код Java.
Поэтому я попытался это выяснить.
На стороне питона
print key.getSigningAlgorithm()
дал мне
pkcs1-sha1
на стороне Java я попытался найти все поддерживаемые алгоритмы с помощью этого кода:
Set<String> algos = java.security.Security.getAlgorithms("Signature");
for(String algo : algos) {
Log.d(TAG, algo);
}
Это дало мне
MD4WithRSAEncryption
RSASSA-PSS
SHA1withDSA
SHA1withRSA/ISO9796-2
1.2.840.113549.1.1.10
SHA512withRSA/PSS
MD5withRSA/ISO9796-2
DSA
SHA512WithRSAEncryption
SHA224withRSA/PSS
NONEWITHDSA
SHA256withRSA/PSS
SHA224WithRSAEncryption
SHA256WithRSAEncryption
SHA1withRSA/PSS
SHA1WithRSAEncryption
SHA384withRSA/PSS
SHA384WithRSAEncryption
MD5WithRSAEncryption
Я попробовал все значения SHA1 на стороне Java. Но никто не помог проверить подпись, сгенерированную tlslite, с помощью алгоритма pkcs1-sha1. Любая идея об этом отображении?