Java和Python中的PKI验证
我正在尝试实现一个公钥基础设施(PKI)验证方案,具体来说就是在服务器上用私钥对一段消息进行签名,然后把这个签名和消息一起存储在客户端。客户端再用公钥来验证这个签名。
我所在的环境有一些限制,服务器是谷歌的应用引擎,而客户端是一个Java程序。我尝试过只用Java和只用Python的PKI验证方案,并且都能正常工作,但在Python和Java之间进行操作时遇到了一些问题,主要是因为密钥文件格式的限制,以及我对加密术语的理解不够。
其中一个最大的限制是谷歌应用引擎对加密的支持。它只支持一个库,叫做PyCrypto,而这个库无法读取以PEM、DER或X509格式存储的公钥/私钥。根据我找到的信息,只有M2Crypto支持从这些文件中读取,但它不能在谷歌应用引擎中使用,因为它是对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代码所期望的不同。
所以我尝试去找出这个问题。
在Python这边
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
我在Java这边尝试了所有的SHA1值,但没有一个能帮助我验证tlslite生成的使用pkcs1-sha1算法的签名。关于这个映射,有什么想法吗?
2 个回答
Keyczar 在 App Engine 上应该能正常使用,并且有 Java 和 Python 两种版本。
这些是不同的操作。在Python中,你需要使用 hashAndSign
。默认情况下,它使用的是SHA1哈希算法。