RSA公私钥和签名、验签过程

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RSA公私钥和签名、验签过程相关的知识,希望对你有一定的参考价值。

参考技术A RSA又叫非对称加密算法,这类加密算法有2个秘钥,你可以选择一个作为私钥(自己保存,重要),另一个作为公钥(对外公开,谁都可以知道)。其中用私钥加密的内容只能用对应的公钥解密,同理用公钥加密的内容也只能用对应的私钥解密。

假设A生成了一对秘钥,私钥自己保存,公钥对外公开,且B获得了A的公钥。在A和B通信的过程中:
A向B发送信息:A用自己的私钥加密,B可以用其公钥解密;
B向A发送信息:B用(A给的)公钥加密数据,A可以用自己的私钥解密;
这样就保证了数据的安全传输;但是这中间存在问题,如果B向A发送数据的过程中被C拦截了,且C也获得了A的公钥,这样C就可以用公钥重新加密一份数据发送给A,这样就篡改了B发送给A的数据。为了辨别这种情况,就要说到数字签名的作用了。

因为在数据传输过程中有可能被篡改,因此我们要使用数字签名技术来校验发送方的身份,并且事后发送方无法抵赖。这里还以A和B为例,来看下数字签名的主要过程:

数字签名是什么?

java RSA实现私钥签名公钥验签私钥加密数据公钥解密数据

通过OpenSSL生成公私钥文件(如果没有OpenSSL工具建议下载Cmder工具自带OpenSSL指令)

1、生成RSA密钥的方法 

 genrsa -out private-rsa.key 2048

2、获取客户端公钥文件

openssl  req -new -x509 -key private-rsa.key -days 750 -out public-rsa.cer

3、获取服务器私钥文件

openssl pkcs12 -export -name zhangsan -in public-rsa.cer -inkey private-rsa.key -out user-rsa.pfx

Java实现私钥签名、公钥验签、私钥加密数据、公钥解密数据

import javax.crypto.Cipher;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;

public class Sha1withRSAUtil {
    private static final String publicKeyFileName = System.getProperty("user.dir") + File.separator + "pubkey.cer";
    private static final String privateKeyFileName = System.getProperty("user.dir") + File.separator + "private.pfx";
    private static final String pfxPassword = "123";//私钥文件获取时设置的密钥
    private static String aliasName = "003";//alias名称

    /**
     * 签名
     *
     * @return 签名后经过base64处理的字符串
     * @throws Exception
     */
    public static String sign(String str) {
        String base64Sign = "";
        InputStream fis = null;
        try {
            fis = new FileInputStream(privateKeyFileName);
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            char[] pscs = pfxPassword.toCharArray();
            keyStore.load(fis, pscs);
            PrivateKey priKey = (PrivateKey) (keyStore.getKey(aliasName, pscs));
            // 签名
            Signature sign = Signature.getInstance("SHA1withRSA");
            sign.initSign(priKey);
            byte[] bysData = str.getBytes("UTF-8");
            sign.update(bysData);
            byte[] signByte = sign.sign();
            BASE64Encoder encoder = new BASE64Encoder();
            base64Sign = encoder.encode(signByte);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return base64Sign;
    }

    /**
     * 数据验证
     *
     * @param signStr 加密后的数据
     * @param verStr  原始字符
     * @return
     */
    public static boolean verify(String signStr, String verStr)
            throws Exception {
        boolean verfy = false;
        InputStream fis = null;
        try {
            fis = new FileInputStream(publicKeyFileName);
            CertificateFactory cf = CertificateFactory.getInstance("x509");
            Certificate cerCert = cf.generateCertificate(fis);
            PublicKey pubKey = cerCert.getPublicKey();
            BASE64Decoder decoder = new BASE64Decoder();
            byte[] signed = decoder.decodeBuffer(signStr);
            Signature sign = Signature.getInstance("SHA1withRSA");
            sign.initVerify(pubKey);
            sign.update(verStr.getBytes("UTF-8"));
            verfy = sign.verify(signed);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return verfy;
    }


    /**
     * 通过公钥文件进行加密数据
     *
     * @return 加密后经过base64处理的字符串
     */
    public static String encrypt(String source) throws Exception {
        InputStream fis = null;
        try {
            fis = new FileInputStream(publicKeyFileName);
            CertificateFactory cf = CertificateFactory.getInstance("x509");
            Certificate cerCert = cf.generateCertificate(fis);
            PublicKey pubKey = cerCert.getPublicKey();
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            byte[] sbt = source.getBytes();
            byte[] epByte = cipher.doFinal(sbt);
            BASE64Encoder encoder = new BASE64Encoder();
            String epStr = encoder.encode(epByte);
            return epStr;
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 通过私钥文件进行解密数据
     *
     * @return 解密后的明文字符串
     */
    public static String decode(String source) throws Exception {
        BASE64Decoder b64d = new BASE64Decoder();
        byte[] keyByte = b64d.decodeBuffer(source);
        InputStream fis = null;
        try {
            fis = new FileInputStream(privateKeyFileName);
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            char[] pscs = pfxPassword.toCharArray();
            keyStore.load(fis, pscs);
            PrivateKey priKey = (PrivateKey) (keyStore.getKey(aliasName, pscs));
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, priKey);
            byte[] epByte = cipher.doFinal(keyByte);
            return new String(epByte, "UTF-8");
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

使用方法

import com.util.rsa.Sha1withRSAUtil;

public class Main {

    public static void main(String[] args) {
        String data = "name123456789";
        String signData = Sha1withRSAUtil.sign(data);
        System.out.println(signData);

        try {
            boolean flag = Sha1withRSAUtil.verify(signData, data);
            System.out.println(flag);

            String eData = Sha1withRSAUtil.encrypt(data);
            System.out.println(eData);
            String dData = Sha1withRSAUtil.decode(eData);
            System.out.println(dData);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

以上是关于RSA公私钥和签名、验签过程的主要内容,如果未能解决你的问题,请参考以下文章

移动平台商家支付宝如何获取商户私钥,支付宝公钥

用mac的terminal通过公私钥和ssh登录Linux

java RSA实现私钥签名公钥验签私钥加密数据公钥解密数据

RSA 非对称加解密 公私钥的生成

RSA加密——go语言版

RSA加密——go语言版