用Python实现RSA签名和验签

一、首先看下Java 的RSA签名和验签

package com.hjdk.huijiedaikuannew.utils;

import com.umeng.commonsdk.proguard.e;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;

public class RsaUtils {
    public static final String KEY_ALGORITHM = "RSA";
    private static final int KEY_MAX_LENGTH = 1024;
    public static final String PRIVATE_KEY = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKPTzFdkU5BqQev6ohBcSP5TDXx0w7DXnErbARr8XF4ltEn6NcStQtg5UqiQ/DrrH6bexnooVkBSy4fAAzY1G7Q5YVWs9pm13fJe38xXi4PlKbYciqvQq0K5sUr9IOovK6hQyb32E+Fz7NpGKZdb16nIzHYF0fdX9sCuN3VkCXbrAgMBAAECgYAmQu70ch/6GHbw8AYtoAAENc1uha62fISqDuABN3MzIccrh95K4tQ7v5eIeuQNtqAbzue32/fY6f1S5Qta+6hOXPOb7GKavnr1hAnJ5XFQmtpVpmzaNmUH0bkFAEcIzVfFBiHweAOHf7wtyGplDChdhgu9Mu+G7XyBrbAay0CRYQJBAOMyCIZObPOGG9KFY3GD+ctw55k/cqfEV+E4LNo9+o2keee2OWcDFavqTVyD3qDeN3S+mNn0dvbjeqxLfZtR/IMCQQC4mQ7/z8MJOwlxozM5AD8RNautgCHKSDBpM4cVZ7fcqOTJXYjf8zM5UExoypfwcFYn4LfDDSNNP5OTtF1I8d95AkAoFAZu8tzDZM/5pjAxsS9alRM19HxcXgWGpGs9IJvXasFaf8nGg0PKbO2yuUyHoku0G39JS5fE28IjLLn+sUrTAkEAhqHrFJu8zaCnNKAonawWU0DnozTOcC/STwfrv6rTqDXuFwcG6v7/Hw/3in4n7o6f55m3rKSKWK7DvXhQiQEPUQJBAMLqGejiiH9E18hDvDROp/KtaceqT7GFc0izJZ8Z9iUFWmAJVo3gy0CIvyvbjOPCTfm3QC8bI1/l7+zuFtKj9yQ=";
    public static final String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCj08xXZFOQakHr+qIQXEj+Uw18dMOw15xK2wEa/FxeJbRJ+jXErULYOVKokPw66x+m3sZ6KFZAUsuHwAM2NRu0OWFVrPaZtd3yXt/MV4uD5Sm2HIqr0KtCubFK/SDqLyuoUMm99hPhc+zaRimXW9epyMx2BdH3V/bArjd1ZAl26wIDAQAB";
    public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
    private static final String UTF8 = "UTF-8";

    public static Map<String, Object> genKeyPair() throws Exception {
        KeyPairGenerator instance = KeyPairGenerator.getInstance("RSA");
        instance.initialize(1024);
        KeyPair generateKeyPair = instance.generateKeyPair();
        HashMap hashMap = new HashMap(2);
        hashMap.put(PUBLIC_KEY, (RSAPublicKey) generateKeyPair.getPublic());
        hashMap.put(PRIVATE_KEY, (RSAPrivateKey) generateKeyPair.getPrivate());
        return hashMap;
    }

    public static String getPrivateKey(Map<String, Object> map) throws Exception {
        return Base64Utils.byteArrayToBase64(((Key) map.get(PRIVATE_KEY)).getEncoded());
    }

    public static String getPublicKey(Map<String, Object> map) throws Exception {
        return Base64Utils.byteArrayToBase64(((Key) map.get(PUBLIC_KEY)).getEncoded());
    }

    public static String encryptByPrivateKey(String str, byte[] bArr) {
        try {
            RSAPrivateKey privateKey = getPrivateKey(str);
            Cipher instance = Cipher.getInstance("RSA");
            instance.init(1, privateKey);
            return Base64Utils.byteArrayToBase64(instance.doFinal(bArr));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String encryptByPrivateKey(String str, String str2) {
        try {
            byte[] bytes = str2.getBytes("UTF-8");
            RSAPrivateKey privateKey = getPrivateKey(str);
            Cipher instance = Cipher.getInstance("RSA");
            instance.init(1, privateKey);
            return Base64Utils.byteArrayToBase64(instance.doFinal(bytes));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String encryptByPublicKey(String str, byte[] bArr) {
        try {
            RSAPublicKey publicKey = getPublicKey(str);
            Cipher instance = Cipher.getInstance("RSA");
            instance.init(1, publicKey);
            return Base64Utils.byteArrayToBase64(instance.doFinal(bArr));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String encryptByPublicKey(String str, String str2) {
        try {
            byte[] bytes = str2.getBytes("UTF-8");
            RSAPublicKey publicKey = getPublicKey(str);
            Cipher instance = Cipher.getInstance("RSA");
            instance.init(1, publicKey);
            return Base64Utils.byteArrayToBase64(instance.doFinal(bytes));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String decryptByPrivateKey(String str, byte[] bArr) {
        try {
            RSAPrivateKey privateKey = getPrivateKey(str);
            Cipher instance = Cipher.getInstance("RSA");
            instance.init(2, privateKey);
            return new String(instance.doFinal(bArr), "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String decryptByPrivateKey(String str, String str2) {
        try {
            byte[] Base64ToChar = Base64Utils.Base64ToChar(str2);
            RSAPrivateKey privateKey = getPrivateKey(str);
            Cipher instance = Cipher.getInstance("RSA");
            instance.init(2, privateKey);
            return new String(instance.doFinal(Base64ToChar), "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String decryptByPublicKey(String str, byte[] bArr) {
        try {
            RSAPublicKey publicKey = getPublicKey(str);
            Cipher instance = Cipher.getInstance("RSA");
            instance.init(2, publicKey);
            return new String(instance.doFinal(bArr), "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String decryptByPublicKey(String str, String str2) {
        try {
            byte[] Base64ToChar = Base64Utils.Base64ToChar(str2);
            RSAPublicKey publicKey = getPublicKey(str);
            Cipher instance = Cipher.getInstance("RSA");
            instance.init(2, publicKey);
            return new String(instance.doFinal(Base64ToChar), "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String sign(byte[] bArr, String str) throws Exception {
        PrivateKey generatePrivate = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(Base64Utils.Base64ToChar(str)));
        Signature instance = Signature.getInstance(SIGNATURE_ALGORITHM);
        instance.initSign(generatePrivate);
        instance.update(bArr);
        return Base64Utils.byteArrayToBase64(instance.sign());
    }

    public static boolean verify(byte[] bArr, String str, String str2) throws Exception {
        PublicKey generatePublic = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(Base64Utils.Base64ToChar(str)));
        Signature instance = Signature.getInstance(SIGNATURE_ALGORITHM);
        instance.initVerify(generatePublic);
        instance.update(bArr);
        return instance.verify(Base64Utils.Base64ToChar(str2));
    }

    public static void main(String[] strArr) throws UnsupportedEncodingException, Exception {
        System.out.println(verify("{\"timestamp\":1553052305209}".getBytes("UTF-8"), PUBLIC_KEY, sign("{\"timestamp\":1553052305209}".getBytes("UTF-8"), PRIVATE_KEY)));
    }

    public static Map<String, String> genJsKey(int i) {
        HashMap hashMap = new HashMap();
        try {
            KeyPairGenerator instance = KeyPairGenerator.getInstance("RSA");
            instance.initialize(i, new SecureRandom());
            KeyPair generateKeyPair = instance.generateKeyPair();
            RSAPrivateKey rSAPrivateKey = (RSAPrivateKey) generateKeyPair.getPrivate();
            BigInteger modulus = rSAPrivateKey.getModulus();
            BigInteger publicExponent = ((RSAPublicKey) generateKeyPair.getPublic()).getPublicExponent();
            BigInteger privateExponent = rSAPrivateKey.getPrivateExponent();
            String byteArrayToBase64 = Base64Utils.byteArrayToBase64(rSAPrivateKey.getEncoded());
            hashMap.put("n", modulus.toString(16));
            hashMap.put("e", publicExponent.toString(16));
            hashMap.put(e.am, privateExponent.toString(16));
            hashMap.put(e.ao, byteArrayToBase64);
        } catch (Exception unused) {
        }
        return hashMap;
    }

    public static String decryptJsData(String str, String str2) {
        try {
            byte[] bytes = str2.getBytes("UTF-8");
            RSAPrivateKey privateKey = getPrivateKey(str);
            Cipher instance = Cipher.getInstance("RSA");
            instance.init(2, privateKey);
            return new String(instance.doFinal(bytes), "UTF-8");
        } catch (Exception unused) {
            return null;
        }
    }

    private static RSAPrivateKey getPrivateKey(String str) {
        try {
            return (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(Base64Utils.Base64ToChar(str)));
        } catch (Exception unused) {
            return null;
        }
    }

    private static RSAPublicKey getPublicKey(String str) {
        try {
            return (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(Base64Utils.Base64ToChar(str)));
        } catch (Exception unused) {
            return null;
        }
    }
}

二、python实现 RSA签名

Java 签名

RSA是一种非对称加密算法,简单理解就是两个密钥:一个公钥,一个私钥。
同时它也可以用来签名和验签,正好与加密相反。

加密:公钥加密,私钥解密;
签名:私钥签名,公钥验签。
有意思的是有些人分不清公钥私钥的用处,这里提供一个思路:
用作加密时,密文泄露是无所谓的(相对而言),重要的是用于解密的密钥必须安全,所以用不公开的私钥来解密,用公钥来加密;
用作签名时,目的是防止别人伪造我的身份发信息,所以用私钥来签名,用公钥来验签。

对于加密及签名的讲解,看过一篇很棒的翻译,看完过后非常有助于理解,并且图文并茂,很生动:
http://www.ruanyifeng.com/blog/2011/08/what_is_a_digital_signature.html

from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import MD5
import base64


def RSA_sign(data):
    privateKey = '''MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAOG/8J9TP8cN7upNoZ+LoBs9xImv
4hHAwO/gq7TLGjZ5IoUIxWPJbGtUI+muXsFf8tBfjE3p86ava1R1Ji0c0Sh98bPT4lFMqGFWV5OJ
d2VbvLGG4DclFzkZxMuB4M7sSvXlKdfawHuFFG/HiEEzjuiROfqWlP3qZ6Ix0QLRhE9HAgMBAAEC
gYBdPujnBn3rfIfY4+QEgKnLVsIdlTat2o5XBtglv1a+dV6a0LqnswVDd+e1mD6vZTBofW74p8/q
Y77TjegM7kA90Nw9N4z2uuhn7kXFNI+RiA2MUXcqf4Vwb/64wRpqH70abZzCuyhxQYXqNqEmJuL4
jAxMoxztxj4BvXt5zk9ekQJBAPLwghERrLNgu+ty/Fmdk15NWE/Eoazig15THPEgrZ5Ruaq90U9O
4sTWbYgDLYJI75uDTgFoPE+VHkT40WspYZMCQQDt4tsPwVHtXEX4sYclEAbWzXEYDlNXCA3zvWf6
9cb9N+oY4FfMuThFdfpC5H2D+5bhqCRLZUzuvthS7i18ljv9AkEApJkFVvFFtIc+60iN513XAhaf
VfRgohUacqcXPdwpJdIzXJadIQHOrRSnQ3b7t4EZLqFpEZUA/96Fkq+Om+9+lwJBAK0fjwt9RrF2
mNmv4UnAyyliZC78pfxNuVGsg1LpsYKxQaYPBvbPyTsL7DDodswpuhnJs3hHZeDOdUKNYf8smsUC
QDhQqQHjf6Kf9ZI/zO6Ldvn0y5cMomzfFaH8ltRcjuNB8num1Vt0Oyk+k90q+OYak5twRvKGGsQD
8v+gOIQ8ZfA='''


    private_keyBytes = base64.b64decode(privateKey)
    priKey = RSA.importKey(private_keyBytes)
    #priKey = RSA.importKey(privateKey)
    signer = PKCS1_v1_5.new(priKey)
    hash_obj = MD5.new(data.encode('utf-8'))
    signature = base64.b64encode(signer.sign(hash_obj))
    print(signature)
    res_sign = signature.decode('utf8')
    print(res_sign)
    return signature


if __name__ == '__main__':
    encrData ='{"phone":17269558830,"password":LHoOVKha,"timestamp":1611749330857,"appName":"₩テᅠ¥タ゚│ᄡᄋ₩ᆲᄒ"}'
    print(RSA_sign(encrData))

几个注意事项:
1.密钥如果是读取自.pem文件,密钥会有开始行和结束行,叫做头标注信息和尾标注信息。常见的长这样:

'''-----BEGIN PRIVATE KEY-----
#密钥内容#
-----END PRIVATE KEY-----'''

2.此时直接priKey = RSA.importKey(privateKey)(见被注释掉的部分)即可,不用对私钥进行base64解码;
3.哈希算法可以采用MD5,也可以用别的比如SHA;
4.data是需要签名的数据,需要字节化后才能传进MD5.new()中。字节化有三种方法,示例中采用了第三种:

b'zifuchuang'
bytes('zifuchuang',encoding='utf-8')
'zifuchuang'.encode('utf-8')

三、python实现RSA验签

Java 验签

def verify(signature,encrData):
    publicKey = '''MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJ3haUf1Tj0/XuknJqsxg/N8nu3NqXhvo6Mdbw
UFuLYux0pjKlY2lCvV14Rlnl2bf0XoIaFcHZIvbexv8bXfakDhpQokyToKvK6kIlbkgKCqCzjVm0
ZthNou5cnqVyRurn3UXxELn1VfHkLc4nSZie+pMwiBRB4ViuAH1+w/gyvwIDAQAB'''
    public_keyBytes = base64.b64decode(publicKey)
    pubKey = RSA.importKey(public_keyBytes)
    #pubKey = RSA.importKey(publicKey)
    h = MD5.new(data.encode('utf-8'))
    verifier = PKCS1_v1_5.new(pubKey)
    return verifier.verify(h, base64.b64decode(signature))

注意事项:
1、因为签名时我们对RSA_sign()返回的签名值进行过过base64编码,所以验签时需要解码;
2、函数verifier.verify()返回的是bool值,在外层可以直接用作条件判断。

posted @ 2021-01-28 18:40  莫贞俊晗  阅读(1947)  评论(0编辑  收藏  举报