RSA加密解密签名加签验签RsaUtils工具类

引言


        RSA算法基于大数因子分解难题,提供了公钥加密和私钥解密的能力。公钥用于加密,私钥则负责解密。这种特性使得RSA成为保证数据传输安全的理想选择。

公钥加密私钥解密与私钥加签公钥验签是基于非对称加密技术的不同应用方式,两者在用途上有明显区别:

公钥加密私钥解密:

  • 目的:主要服务于信息的保密传输,确保只有预定的接收者才能解密信息。
  • 流程
    • 发送方获取接收方的公钥,用该公钥对敏感信息进行加密。
    • 加密后的信息被发送给接收方。
    • 接收方使用自己的私钥解密收到的信息,由于私钥只有接收方拥有,所以保证了信息的机密性。
  • 通俗理解:想象一个带锁的箱子,这个箱子有个特别之处,就是配有两个钥匙,一把“公钥”和一把“私钥”。任何人都可以用公钥把信息装进箱子里并锁上,但只有拥有私钥的人才能打开箱子取出里面的信息。所以,当你想给朋友发秘密消息时,你用他的公钥加密消息,这样全世界只有他知道的私钥才能解开这个消息,保证了消息的安全。

私钥加签公钥验签:

  • 目的:主要用于数据完整性和身份认证,确保信息没有被篡改,并且确实是由特定的发送者发出的。
  • 流程
    • 发送方使用自己的私钥对消息或消息的哈希值进行签名,生成数字签名。
    • 发送方将原始消息和数字签名一起发送给接收方。
    • 接收方使用发送方公布的公钥来验证数字签名的有效性。如果数字签名验证成功,这意味着消息在传输过程中未被篡改,并且确实是由持有对应私钥的实体(即发送方)发送的。
  • 通俗理解:现在换种场景,假设你要向大家证明某封信是你写的。你有一只特殊的笔(私钥),用这只笔在信末写上你的“签名”。任何人都可以拿到你公开给大家看的另一只配套印章(公钥),去检查这封信上的签名是否真是由你的私钥笔所写。如果印章能匹配上,那就说明这封信确实是出自你手,没有人能伪造你的签名,因为只有你才有那只私钥笔。这样一来,就实现了对消息真实来源的验证和防篡改功能。

简而言之,公钥加密是为了保密性,私钥解密则是恢复加密内容;而私钥签名是为了提供数据真实性和发送者身份的不可抵赖性,公钥验签则是确认签名的有效性,确保消息来源可靠。这两种机制共同构建了现代网络安全体系中的基础信任模型。

  • 公钥加密就像是给信息加上一把只有用私钥才能解开的锁,保证信息安全送达。
  • 私钥签名就像是用自己的专属笔签名,别人可以用对应的公钥印章来验证这份签名的真实性,从而确认信息的真实来源及完整性。

在这里插入图片描述

一、RsaUtils工具类代码

package com.example.test.rsa;

import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * @author xiaoxiaoyezhu
 * @date 2024/3/19
 * @desc default
 **/
public class RsaUtils {
    private static final String RSA = "RSA";
    private static final String PUBLIC_KEY = "公钥必须要和私钥是一对";
    private static final String PRIVATE_KEY = "公钥必须要和私钥是一对";
    private static final String SIGN_ALGORITHMS = "SHA1WithRSA";



    public static void main(String[] args) throws Exception {
        KeyPair keyPair = generateKeyPair();
        String publicKey = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
        String privateKey = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());

        System.out.println("公钥: " + publicKey);
        System.out.println("私钥: " + privateKey);

        String data = "今天天气很好!";

        String encryptedData = encryptByPublicKey(data, publicKey);
        System.out.println("原文: " + data + "\n加密后: " + encryptedData);

        String decryptedData = decryptByPrivateKey(encryptedData, privateKey);
        System.out.println("解密后: " + decryptedData);


        String sign = sign(data, privateKey);
        System.out.println("签名: " + sign);

        boolean verify = verify(data, sign, publicKey);
        System.out.println("验签结果: " + verify);
    }


   /**
     * 生成密钥对
     * 
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA);
        keyPairGenerator.initialize(2048);
        return keyPairGenerator.generateKeyPair();
    }

    /**
     * 公钥加密
     *
     * @param data
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static String encryptByPublicKey(String data, String publicKey) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(publicKey);
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA);
        PublicKey publicK = keyFactory.generatePublic(x509EncodedKeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicK);
        // 可以使用UTF_8编码
//        return Base64.getEncoder().encodeToString(cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)));
        return Base64.getEncoder().encodeToString(cipher.doFinal(data.getBytes()));
    }


    /**
     * 私钥解密
     *
     * @param data
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static String decryptByPrivateKey(String data, String privateKey) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(privateKey);
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA);
        PrivateKey privateK = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateK);
        // 可以使用UTF_8编码
//        return new String(cipher.doFinal(Base64.getDecoder().decode(data)), StandardCharsets.UTF_8);
        return new String(cipher.doFinal(Base64.getDecoder().decode(data)));
    }


    /**
     * 私钥加签
     *
     * @param data
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static String sign(String data, String privateKey) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(privateKey);
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA);
        PrivateKey privateK = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
        signature.initSign(privateK);
        signature.update(data.getBytes());
        return Base64.getEncoder().encodeToString(signature.sign());
    }


    /**
     * 公钥验签
     *
     * @param data
     * @param sign
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static boolean verify(String data, String sign, String publicKey) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(publicKey);
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA);
        PublicKey publicK = keyFactory.generatePublic(x509EncodedKeySpec);
        Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
        signature.initVerify(publicK);
        signature.update(data.getBytes());
        return signature.verify(Base64.getDecoder().decode(sign));
    }
}

二、优点

  • 安全性高:RSA基于数学上的大整数因子分解难题,只要密钥足够大(通常建议至少2048位),在现有的计算机技术和算法条件下,破解RSA加密的数据所需的时间极其漫长,从而确保了高度的安全性。

  • 公钥加密私钥解密:RSA采用了一对密钥体系,用户可以自由地分发公钥而不必担心安全问题,因为只有持有对应的私钥才能解密数据。这种机制特别适合于密钥管理和分布。

  • 数字签名:除了加密外,RSA还可用于数字签名,通过私钥对数据进行签名,然后接收方可以用公钥验证签名的真实性,确保数据完整性并确认发送者的身份。

  • 兼容性广泛:RSA算法已成为公认的国际标准,并被众多操作系统、网络协议、应用程序所支持,具有极高的兼容性和普适性。

  • 算法透明:虽然实际运算复杂,但RSA算法本身是公开的,这增强了人们对算法安全性的信任,因为任何潜在的漏洞都可以经过全球专家的审查和改进。

三、缺点

        在实际应用中,对于大数据量的加密,RSA并不适合直接加密整个数据块,因为其单次加密的数据长度有限制。这时常常会结合其他策略,比如使用AES等对称加密算法先对数据分块加密,再用RSA加密AES密钥的方式来处理大数据。

四、声明

本内容版权归属于CSDN-小小野猪,任何未经授权的复制、转载、传播、贩卖、转赠等均属违法行为,必将追究法律责任!!!

  • 30
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小野猪

若恰好解决你的问题,望打赏哦。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值