RSA加解密、签名及验签的原理及工具类

本文详细介绍了RSA非对称加密算法,包括加密、签名的区别及其应用场景。阐述了加解密与签名验签的过程,并提供了Java RSA工具类的实现,用于公钥加密、私钥解密、私钥签名及公钥验签操作。强调了实际应用中同时使用加密和签名的重要性,以确保信息安全。
摘要由CSDN通过智能技术生成

一、RSA简介

非对称加密算法,由一对密钥(公钥-私钥)来进行加密-解密、签名-验签的过程。公钥-私钥的生成与数学相关,算法的原理是依靠对极大整数做因数分解的困难性来保证安全性。

二、加密、签名区别

加密和签名都是为了信息传递途中的安全,原理略有不同,加密是防止信息明文传输被泄露,签名是防止信息被篡改。

三、加解密、签名及验签场景

加解密场景:A服务器向B服务器传递一指令。

过程如下:

  • (1)B生成一对密钥(公钥-私钥),私钥B自己保留,公钥任何人可以获取。

  • (2)B传递自己的公钥给A,A用B的公钥对消息进行加密。

  • (3)B接收到A加密的消息,利用B自己的私钥对消息进行解密。

整个流程含两次传递过程,第一次是B传递公钥给A,第二次是A传递加密消息给B,即使都被第三方非法截获,也没有危险性,因为只有B的私钥才能对消息进行解密,防止了消息内容的泄露。

签名及验签场景:B服务器收执行完A服务器发的指令后,向A回复执行结果。

过程如下:

  • (1)B用自己的私钥对回复的消息加签,形成签名,并将签名和消息本身一起传递给A。

  • (2)A收到回复后,使用B提供的公钥进行验签,如果验签解析出的内容与消息本身一致,证 明消息是B回复的。

即使回复的消息被第三方非法截获,也没有危险性,因为接收方A使用的是B的公钥进行验签,只有B的私钥生成的签名才能通过A的验签,即使第三方非法获取消息内容,也无法伪造带签名的回复给A,防止了消息内容被篡改。

但是不难发现,加密场景中,可以利用截获的公钥,将假指令进行加密,然后传递给B。验签场景中,虽然截获的消息不能被篡改,但是消息的内容可以利用公钥验签获得,并不能防止泄露。所以实际应用中要根据情况使用,最好同时使用加密和签名,比如A和B都有一套自己的公钥和私钥,当A要给B发送消息时,先用B的公钥对消息加密,再对加密的消息使用A的私钥加签名,达到既不泄露也不被篡改,从而保证消息的安全性(公钥加密、私钥解密、私钥签名、公钥验签)。

四、RSA工具类

package com.ahysf.common.utils;

import cn.hutool.core.codec.Base64;
import com.ahysf.controller.saas.SaaSDemo;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName: RSAUtil
 * @author: 〆、dyh
 * @since: 2022/3/3 10:38
 */
public class RSAUtil {

    public static final String KEY_ALGORITHM = "RSA";
    private static final String PUBLIC_KEY = "RSAPublicKey";
    private static final String PRIVATE_KEY = "RSAPrivateKey";
    public static final String SIGNATURE_INSTANCE = "SHA256WithRSA";

    /**
     * 获得公钥
     *
     * @param keyMap
     * @return java.lang.String
     * @MethodName: getPublicKey
     * @author: 〆、dyh
     * @since: 2022/3/4 10:30
     */
    public static String getPublicKey(Map<String, Object> keyMap) throws Exception {
        //获得map中的公钥对象 转为key对象
        Key key = (Key) keyMap.get(PUBLIC_KEY);
        //编码返回字符串
        return encryptBASE64(key.getEncoded());
    }

    /**
     * 获得私钥
     *
     * @param keyMap
     * @return java.lang.String
     * @MethodName: getPrivateKey
     * @author: 〆、dyh
     * @since: 2022/3/4 10:30
     */
    public static String getPrivateKey(Map<String, Object> keyMap) throws Exception {
        //获得map中的私钥对象 转为key对象
        Key key = (Key) keyMap.get(PRIVATE_KEY);
        //编码返回字符串
        return encryptBASE64(key.getEncoded());
    }

    /**
     * 解码返回byte
     *
     * @param key
     * @return byte[]
     * @MethodName: decryptBASE64
     * @author: 〆、dyh
     * @since: 2022/3/4 10:30
     */
    public static byte[] decryptBASE64(String key) throws Exception {
        return (new BASE64Decoder()).decodeBuffer(key);
    }

    /**
     * 编码返回字符串
     *
     * @param key
     * @return java.lang.String
     * @MethodName: encryptBASE64
     * @author: 〆、dyh
     * @since: 2022/3/4 10:30
     */
    public static String encryptBASE64(byte[] key) throws Exception {
        return (new BASE64Encoder()).encodeBuffer(key);
    }

    /**
     * map对象中存放公私钥
     *
     * @param
     * @return java.util.Map<java.lang.String, java.lang.Object>
     * @MethodName: initKey
     * @author: 〆、dyh
     * @since: 2022/3/4 10:31
     */
    public static Map<String, Object> initKey() throws Exception {
        //获得对象 KeyPairGenerator 参数 RSA 1024个字节
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        keyPairGen.initialize(1024);
        //通过对象 KeyPairGenerator 获取对象KeyPair
        KeyPair keyPair = keyPairGen.generateKeyPair();

        //通过对象 KeyPair 获取RSA公私钥对象RSAPublicKey RSAPrivateKey
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        //公私钥对象存入map中
        Map<String, Object> keyMap = new HashMap<String, Object>(2);
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

    /**
     * 实例化公钥
     *
     * @param publicKey
     * @return java.security.PublicKey
     * @MethodName: getPublicKey
     * @author: 〆、dyh
     * @since: 2022/3/4 10:31
     */
    public static PublicKey getPublicKey(String publicKey) throws Exception {
        byte[] publicKeyBytes = java.util.Base64.getMimeDecoder().decode(publicKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        return keyFactory.generatePublic(keySpec);
    }

    /**
     * 实例化私钥
     *
     * @param privateKey
     * @return java.security.PrivateKey
     * @MethodName: getPrivateKey
     * @author: 〆、dyh
     * @since: 2022/3/4 10:31
     */
    public static PrivateKey getPrivateKey(String privateKey) throws Exception {
        byte[] privateKeyBytes = java.util.Base64.getMimeDecoder().decode(privateKey);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        return keyFactory.generatePrivate(keySpec);
    }

    /**
     * 公钥加密
     *
     * @param content
     * @param publicKey
     * @return byte[]
     * @MethodName: encryptByPublicKey
     * @author: 〆、dyh
     * @since: 2022/3/4 10:31
     */
    public static byte[] encryptByPublicKey(byte[] content, String publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, getPublicKey(publicKey));
        return cipher.doFinal(content);
    }

    /**
     * 私钥解密
     *
     * @param content
     * @param privateKey
     * @return byte[]
     * @MethodName: decryptByPrivateKey
     * @author: 〆、dyh
     * @since: 2022/3/4 10:32
     */
    public static byte[] decryptByPrivateKey(byte[] content, String privateKey) throws Exception {
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, getPrivateKey(privateKey));
        return cipher.doFinal(content);
    }

    /**
     * 私钥签名
     *
     * @param content
     * @param privateKey
     * @return byte[]
     * @MethodName: sign
     * @author: 〆、dyh
     * @since: 2022/3/4 10:33
     */
    public static byte[] sign(byte[] content, String privateKey) throws Exception {
        Signature signature = Signature.getInstance(SIGNATURE_INSTANCE);
        signature.initSign(getPrivateKey(privateKey));
        signature.update(content);
        return signature.sign();
    }

    /**
     * 公钥验签
     *
     * @param content
     * @param sign
     * @param publicKey
     * @return boolean
     * @MethodName: verify
     * @author: 〆、dyh
     * @since: 2022/3/4 10:33
     */
    public static boolean verify(byte[] content, byte[] sign, String publicKey) throws Exception {
        Signature signature = Signature.getInstance(SIGNATURE_INSTANCE);
        signature.initVerify(getPublicKey(publicKey));
        signature.update(content);
        return signature.verify(sign);
    }

    public static void main(String[] args) throws Exception {
        Map<String, Object> keyMap;
        try {
            //初始化公私钥
            keyMap = initKey();
            //获得公钥
            String publicKey = getPublicKey(keyMap);

            System.out.println("rsa公钥:" + publicKey);
            //获得私钥
            String privateKey = getPrivateKey(keyMap);

            System.out.println("rsa私钥:" + privateKey);
            String content = "我爱你你却爱着他";
            //公钥加密
            byte[] encrypt = encryptByPublicKey(content.getBytes(StandardCharsets.UTF_8), publicKey);
            //私钥解密
            byte[] decryp = decryptByPrivateKey(encrypt, privateKey);
            System.out.println("明文:" + new String(decryp));
            //私钥签名
            byte[] sign = sign(content.getBytes(StandardCharsets.UTF_8), privateKey);
            System.out.println("私钥签名:" + sign);
            //公钥验签
            boolean verify = verify(content.getBytes(StandardCharsets.UTF_8), sign, publicKey);
            System.out.println("验签结果:" + verify);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值