跨Java和Python的PKI验证 [英] PKI verification across Java and Python
问题描述
我试图实现一个PKI验证方案,其中消息字符串使用服务器上的私钥签名,签名与消息字符串一起存储在客户端上。然后客户端使用公共密钥验证签名。
我的环境的限制是,服务器是Google App Engine,客户端是Java程序。我使用的是Java-only和Python-only的PKI验证解决方案,并让他们工作,但是当在Python中的一个操作和另一个在Java中提出问题,主要是由于密钥文件格式限制和我有限的理解加密术语。
最大的限制之一是GAE中的加密支持。唯一支持的库是PyCrypto,并且此库不能读取以PEM,DER或X509格式存储的公钥/私钥。就我可以找到,只有M2Crypto支持从这些文件读取,但它不能在GAE内使用,因为它是一个包装openssl,所以不是一个纯python解决方案。即使我可以找到一种方法来将公共/私有密钥从PEM / DER / X509转换为PyCrypto所了解的格式,这对我也有效。但我找不到任何办法。有任何想法吗?
我发现一个可能的解决方案tlslite的形式。 tlslite可以从PEM文件中读取私钥并创建签名。这是代码。
从tlslite.utils.cryptomath导入bytesToBase64
从tlslite.utils.keyfactory import parsePEMKey
s = open('private.pem')。read()
key = parsePEMKey(s)
doc ='Sample text'
bytes = array ')
bytes.fromstring(doc)
print bytesToBase64(key.sign(bytes))
我用来验证签名的相应Java代码是。
String signAlgo =SHA1WithRSAEncryption ;
//从public.der读取公共密钥
byte [] encodedKey = new byte [294]; // shortcut hardcoding
getAssets()。open(public.der)。read(encodedKey);
//创建公钥对象
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedKey);
KeyFactory kf = KeyFactory.getInstance(RSA);
PublicKey pk = kf.generatePublic(publicKeySpec);
//读签名(由上面的python代码创建)
byte [] encodedSig = new byte [345];
getAssets()。open(signature.txt)。read(encodedSig);
byte [] decodedSig = Base64.decodeBase64(encodedSig);
//验证
签名verifyalg = Signature.getInstance(signAlgo);
verifyalg.initVerify(pk);
verifyalg.update(message.getBytes());
Log.d(TAG,Verif:+ verifyalg.verify(decodedSig));
验证失败。
如果tlslite使用不同于java代码预期的签名创建的算法。
所以我试着找到了。
在python端
print key.getSigningAlgorithm()
/ pre>
给了我
pkcs1-sha1
在Java端,我尝试使用此代码查找所有支持的算法:
设置< 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 algo生成的签名。关于此映射的任何想法?
解决方案这些是不同的操作。在Python中,您需要使用
hashAndSign
。默认发生的是SHA1哈希。I am trying to implement a PKI verification scheme, where a message string is signed with a private key on server, the signature is stored on the client along with the message string. The client then verifies the signature using a public key.
The restrictions of my environment are, the server is Google App Engine and the client is a Java program. I have played with Java-only and Python-only solutions of PKI verification and got them to work, however when doing one operation in Python and another in Java is posing problem, mainly due to Key file format restrictions and my limited understanding of cryptography terminology.
One of the biggest limitations is crypto support in GAE. The only library supported is PyCrypto and this library can't read public/private keys stored in PEM, DER or X509 formats. As far as I could find, only M2Crypto supports reading from these files, but it can't be used inside GAE because it's a wrapper around openssl, so not a pure python solution. Even if I could find a way to translate the public/private keys from PEM/DER/X509 to the format that PyCrypto understands, that will work for me. But I couldn't find any way to do it. Any ideas there?
I found one possible solution in the form of tlslite. tlslite could read a private key from PEM file and create a signature. Here is the code.
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))
The corresponding Java code I used to verify the signature is.
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));
The verification fails.
I suspected if the tlslite is using different algorithm for signature creation than what the java code expects.
So I tried to find that out.
On python side
print key.getSigningAlgorithm()
gave me
pkcs1-sha1
on Java side, I tried to find all supported algorithms with this code:
Set<String> algos = java.security.Security.getAlgorithms("Signature"); for(String algo : algos) { Log.d(TAG, algo); }
That gave me
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
I tried all the SHA1 values on the Java side. But none helped to verify the signature generated by tlslite with pkcs1-sha1 algo. Any idea about this mapping?
解决方案These are different operations. In Python, you need to use
hashAndSign
. The default happens to be SHA1 hash.这篇关于跨Java和Python的PKI验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!