发布时间:2019-09-14 09:23:04编辑:auto阅读(2725)
这周一个项目客户提供了一份对接文档要求用RSA数字签名,客户提供的是java的demo,但是自己不想用java来做,想用python来实现,就自己研究了下python下RSA签名。
先是研究了java-demo的流程和逻辑(因为是公司项目客户提供的,不便对外公开),基本的流程是这样的:
1)先根据私钥KEY字符串,获取私钥对象(PrivateKey)
私钥KEY----------就是一个长字符串
比如下面这个是我自己用openssl生成的(MIIEpQIBAAKCAQEA9JPHRFaWOhi7PXZz/Kmun/ldJrd+YQy6diU2eFijVooL8NDG
4dsOojUpT9FhAUedXcDZrYN3BstFcaGRJQouyXZsbJjyFL8WNLLGFIwdcv1pTGve
cLOEdU1Rl+E4wCznYflxcUN3ngZQo7cN/la2poM1k/epR8UsWiH8wQj+v7FHMrt4
XMhVSVAqslfhs6yqJQuQwu3YiaspZVySAywaFFveLCcedKPrlZYoN9Q1Qg7hyXZ+
hqIPIyXBHFU721GqlDJ8K6lCXxjNK7xFWwo1QzLAwdfLA0ZJ1K00+4nv9E1JUcbX
emhDJHvyZ9O/ExRqdykkE6CAJD3tZkjhQwERnwIDAQABAoIBABQVxrl/+tpOiaHk
hmXrcWHF0raJPyGtL+rf53c+oDtNHunp20tU+ACuKPRbF4JJZUz7t2SedTnjm5JX
WFoYWftFdGX+sXKutp4hSE8Lqqd01B7ohN3wgCI59UdpwYVWqrHLEFvi1IHvttOb
BtUqPdmy0MWUAxzXvmqwe9dGa9VGCp55HezZo0nDkwg8s7h/CKndxmGCvFX/O5iV
RaJgUOkQ9iRp8v1M3ri/XBvt1BmAUzFvXs3RNmF3/fKsvOCINFIGnZt+zyW7s7XA
RBgOluorDLdMusvxy9qrGspc3U8L6Uf7xsHKwvaAVD/RLP03FopNkg8HPphikbQA
naoWzKECgYEA/giQ3qSJfNH/0TELayYVzEq3MYOEc/tiI1YrUUXLTJ7rQ3yZSjt7
HMIgjPzO6Ek4iVdVX0QnNNvD9To40blr5KykeIoAOyta7hEAvZS4uMue1YXkW8i2
YpQJ9BzNho0SpHyB13/7TT9l9kyNSqemOVrDfvo24d4S7YafhBiNXOkCgYEA9nh4
+GCmV6+XR7lwbMrp3JLE/xpyiGK8P27COT22pT9Q3in8BSgjMa+vmJnGase6oQr6
xcd5Odqg5YmCs+T2MLoJg0sSBfCJxASRZPDnpz2MjTordm09PkauOCSsoq1IhH5E
xkDw97zIm1m1h87W8Zd+E500E687vRBanEzFxUcCgYEAwdwNmiqcVWn4vE6eNSW6
Ss3V4W5JPS1g5jCTHBGUJKO+TCEg5hpgSEEJEC65Q2DlSUIhf3MGLHttno3Q4JOM
99ScKvS9WmoqmTTWiNae5T9WtgHYlAam0LHCqsz0NzMfP/FYMPmU8I1qJTykMo2f
93MBb7xI97M+ZI9w2iDWeEkCgYEAu5G1ZjiPfv3XYDNE1taZoU5k80taTGbvokqV
LuDDZgDIdzp2XCpOllqAhN7KPKshYbusWuXSYO/8MJM0z9j4bt61rKBt5+1FutJL
IAmiEglqNHRHbUn3KLS7k2h9pRPAs2wwxLvZZn/aHzfnSaJku9kxjpW9cxmRmfGf
M4HNpLMCgYEAppL5J9jja2DrkRXoS9d4MvwaTlF/HsY2QRVRmlcvZddKXECcJ/fI
wmP7V/NNegLBsMukdrPez28bK1ci0iigO6dCjxnUZF1KDPzLwgsNG2Z9i54nsmOT
7xwfITqzE3gA2NSRNVY7oo8pwfGU1kEeySrMUxrRZ3EaerTS0JSIdSg=)
注意java提供的私钥KEY字符串是不包括开头-----BEGIN RSA PRIVATE KEY-----和结尾-----END RSA PRIVATE KEY-----的。
因为openssl默认产生的PEM格式的是包括开头-----BEGIN RSA PRIVATE KEY-----和结尾-----END RSA PRIVATE KEY-----的
根据提供的私钥KEY字符,demo中得到一个私钥对象(PrivateKey)。
下面是java得到私钥对象的代码:
public static PrivateKey getPrivateKey(String key) {
try {
byte[] keyBytes = (Base64.decodeBase64(key));
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
return privateKey;
} catch (Exception e) {
e.printStackTrace();
return null;
}
2)根据得到的私钥对象(PrivateKey),得到给定字符串的签名
public String sign(byte[] data, PrivateKey priKey) {
try {
Signature signature = Signature.getInstance("MD5WithRSA");
signature.initSign(priKey);
signature.update(data);
return Base64.encodeBase64URLSafeString(signature.sign());
} catch (Exception e) {
return null;
}
}
上面是java中的RSA的基本的流程,这里还有个验签的步骤,这里就不说了。
下面讲一下我在python中的使用,网上找了很多,也吸取了很多有用的东西,一开始用M2Crypto来做,这个库可以用pip install M2Crypto获取,但是这个库是依赖openssl的,先得安装openssl,我下得得官网得openssl-0.9.8-stable-SNAP-20150609.tar.gz,然后还得安装Perl,具体教程可以参考(http://www.cnblogs.com/ZhouL3777/archive/2012/10/21/2732890.html),我M2Crypto完全安装成功后,后面可能是我使用的问题,签名出来的字符串跟java签名出来的不一样,这个地方以后有空再深入研究下。后面讲下重点,使用pycrypto库。
使用pycrypto来做RSA签名:
1.因为pyCrypto库不依赖openssl库,所以直接pip install pycrypto 就可以安装成功(我的python2.7.9,pycrypto版本是2.6.1)
2.签名函数:
''' RSA签名 ''' def sign(signdata): ''' @param signdata: 需要签名的字符串 ''' h=MD5.new(signdata) signer = pk.new(RSA.importKey(p)) signn=signer.sign(h) # signn=base64.b64encode(signn,["-","_"]) signn=base64.urlsafe_b64encode(signn) return signn
关键介绍下函数中p,这个是私钥字符串,但是开头-----BEGIN RSA PRIVATE KEY-----和结尾-----END RSA PRIVATE KEY-----得加上。
我用客户提供的私钥字符串(不含开头-----BEGIN RSA PRIVATE KEY-----和结尾-----END RSA PRIVATE KEY-----的),然后p是加上开头-----BEGIN RSA PRIVATE KEY-----和结尾-----END RSA PRIVATE KEY-----的值。
# signn=base64.b64encode(signn,["-","_"]) signn=base64.urlsafe_b64encode(signn)这两个其实是一样的效果,把“+”转成“-”,把“/”转成“_”而已。
这样签名出来的跟java签名出来的东西一样了, 但是最后多了一个“=”。 这个我不知道为什么会多了一个“=”。 如果哪位高手知道,解释一下。
写的有点凌乱啊,望看的见谅。
上一篇: Sublime Text 3 多行游标
下一篇: Python 同行输出
47848
46399
37285
34737
29318
25975
24918
19954
19548
18031
5795°
6419°
5931°
5964°
7070°
5917°
5948°
6441°
6405°
7782°