python RSA签名

发布时间: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签名出来的东西一样了, 但是最后多了一个“=”。 这个我不知道为什么会多了一个“=”。  如果哪位高手知道,解释一下。


    写的有点凌乱啊,望看的见谅。

关键字