RSA非对称加密(附工具类Util)

news2024/11/18 15:42:24

文章目录

  • 非对称加密是什么
  • 非对称加密通信流程
  • RSA非对称加密算法
  • 非对称加密工具类Util及案例演示

        之前写过一篇关于DES对称加密的帖子,感兴趣的小伙伴可以去看看:DES对称加密算法

今天主要聊聊什么是非对称加密,以及它是如何实现的。

一、非对称加密是什么?

非对称加密(asymmetric cryptography),也称为公开密钥加密(Public-key cryptography),是密码学的一种算法,它需要两个密钥,一个是公开密钥,另一个是私有密钥。顾名思义,公钥可以任意对外发布;而私钥必须由用户自行严格秘密保管,绝不透过任何途径向任何人提供,也不会透露给要通信的另一方,即使他被信任。

非对称加密的重要性质:

1.加密的双向性

加密具有双向性,即公钥和私钥中的任一个均可用作加密,此时另一个则用作解密。

使用其中一个密钥把明文加密后所得的密文,只能用相对应的另一个密钥才能解密得到原本的明文,甚至连最初用来加密的密钥也不能用作解密,这是非对称加密最重要的性质或者说特点。

2.公钥无法推导出私钥 

必须确保使用公钥无法推导出私钥,至少妄想使用公钥推导私钥必须在计算上是不可行的,否则安全性将不复存在。

虽然两个密钥在数学上相关,但如果知道了公钥,并不能凭此计算出私钥;因此公钥可以公开,任意向外发布;而私钥不公开,绝不通过任何途径向任何人提供。

在对称密码中,由于加密和解密的密钥是相同的,因此必须向接收者配送密钥。用于解密的密钥必须被配送给接收者,这一问题称为密钥配送问题。如果使用非对称加密,则无需向接收者配送用于解密的密钥,这样就解决了密钥配送的问题。

非对称加密中,密钥分为加密密钥和解密密钥两种。发送者用加密密钥对消息进行加密,接收者用解密密钥对密文进行解密。需理解公钥密码,清楚地分加密密钥和解密密钥是非常重要的。加密密钥是发送者加密时使用的,而解密密钥则是接收者解密时使用的。

3.加密密钥和解密密钥的区别

  • 发送者只需要加密密钥
  • 接收者只需要解密密钥
  • 解密密钥不可以被窃听者获取
  • 加密密钥被窃听者获取也没关系

也就是说,解密密钥从一开始就是由接收者自己保管的,因此只要将加密密钥发给发送者就可以解决密钥配送问题了,而根本不需要配送解密密钥。

非对称加密中,加密密钥一般是公开的。真是由于加密密钥可以任意公开,因此该密钥被称为公钥(pulickey)。相对地解密密钥是绝对不能公开的,这个密钥只能由你自己来使用,因此称为私钥(privatekey)。私钥不可以被别人知道,也不可以将它发送给别人。

公钥和私钥是"一一对应的",一对公钥和私钥统称为密钥对(keypair)。由公钥进行加密的密文,必须使用与该公钥配对的私钥才能解密。密钥对中的两个密钥之间具有非常密切的的关系(数学上的关系)。因此公钥和私钥不能分别单独生成。

PS:公钥密码的使用者需要生成一个包括公钥和私钥的密钥对,其中公钥会被发送给别人,而私钥则仅供自己使用。

二、非对称加密通信流程

举例:假设士兵A要给军官B发一条信息,A是发送者,B是接收者,黑客C想窃听A和B之间的通讯内容。

1.军官B生成一个包含公钥和私钥的密钥对(私钥由B自行妥善保管

2.军官B将自己的公钥发送给士兵A,表示B请A用这个公钥对消息进行加密并发送给他。但此时公钥被黑客C截获(没关系,无伤大雅)。

3.士兵A用军官B的公钥对消息进行加密(加密后的消息只有B的私钥才能够解密。虽然A拥有B的公钥,但用B的公钥是无法对密文进行解密的)

4.士兵A将密文发送给军官B(密文也被黑客C截获,不过也没关系,C虽然拥有B的公钥,但是B的公钥是无法进行解密的)

5.军官B用自己的私钥对密文进行解密,获得最终的明文,详细可参考下图: 

A和B之间传输的信息有两个,一个是B的公钥,一个是B公钥加密的密文,由于B的私钥没有出现在通信内容中,因此C无法对密文进行解密。

三、RSA非对称加密算法

RSA是一种非对称加密算法,它的名字由三位开发者。即RonRivest、AdiShamir和LeonardAdleman 的姓氏的首字母组成的(Rivest-Shamir-Leonard)。

1.RSA加密

RSA的加密工程可以用下来公式来表达,如下:

也就是说,RSA的密文是对代表明文的数字的E次方求modN的结果。换句话说,就是将明文自己做E次乘法,然后将其结果除以N求余数,这个余数就是密文。 

RSA的加密是求明文的E次方modN,因此只要知道E和N这两个数,任何人都可以完成加密的运算。所以说E和N是RSA加密的密钥。也就是说E和N的组合就是公钥。

有一个很容易引起误解的地方需要大家注意一一E和N这两个数并不是密钥对(公钥和私钥的密钥对)。E和N两个数才组成了一个公钥,因此我们一般会写成 “公钥是(E,N)” 或者 “公钥是{E, N}" 这样的形式,将E和N用括号括起来。

2.RSA解密

RSA的解密和加密一样简单,可以用下面的公式来表达:

也就是说,对表示密文的数字的D次方求modN就可以得到明文。换句话说,将密文自己做D次乘法,在对其结果除以N求余数,就可以得到明文。

这里所使用的数字N和加密时使用的数字N是相同的。数D和数N组合起来就是RSA的解密密钥,因此D和N的组合就是私钥。只有知道D和N两个数的人才能够完成解密的运算。

大家应该已经注意到,在RSA中,加密和解密的形式是相同的。加密是求 "E次方的mod N”,而解密则是求 "D次方的modN”,这真是太美妙了。

当然,D也并不是随便什么数都可以的,作为解密密钥的D,和数字E有着相当紧密的联系。否则,用E加密的结果可以用D来解密这样的机制是无法实现的。

PS:顺便说一句,D是解密〈Decryption)的首字母,N是数字(Number)的首字母

 

四、RSA工具类Util

RsaTestUtils.java
package com.st.microservice.billcenter.infrastructure.util;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * @description: RSA加密工具类
 * @author: admin
 */
public class RsaTestUtils {

    public static void main(String[] args) {
        //生成公钥和私钥
        Map<Integer, String> keyMap = genKeyPair();
        //加密字符串
        String content = "我是原文啊!132456789";
        System.out.println("加密前内容:" + content);
        System.out.println("随机生成的公钥为:" + keyMap.get(0));
        System.out.println("随机生成的私钥为:" + keyMap.get(1));
        String messageEn = encrypt(content, keyMap.get(0));
        System.out.println("加密后的内容为:" + messageEn);
        String messageDe = decrypt(messageEn, keyMap.get(1));
        System.out.println("还原后的内容为:" + messageDe);
    }

    /**
     * 随机生成密钥对
     */
    public static Map<Integer, String> genKeyPair() {
        // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
        KeyPairGenerator keyPairGen = null;

        try {
            keyPairGen = KeyPairGenerator.getInstance("RSA");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        // 初始化密钥对生成器,密钥大小为96-1024位
        assert keyPairGen != null;
        keyPairGen.initialize(1024, new SecureRandom());
        // 生成一个密钥对,保存在keyPair中
        KeyPair keyPair = keyPairGen.generateKeyPair();
        // 得到私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        // 得到公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
        // 得到私钥字符串
        String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));
        // 将公钥和私钥保存到Map
        Map<Integer, String> keyMap = new HashMap<>();
        // 0表示公钥
        keyMap.put(0, publicKeyString);
        // 1表示私钥
        keyMap.put(1, privateKeyString);
        return keyMap;
    }

    /**
     * RSA公钥加密
     *
     * @param str       加密字符串
     * @param publicKey 公钥
     * @return 密文
     */
    public static String encrypt(String str, String publicKey) {
        // base64编码的公钥
        byte[] decoded = Base64.decodeBase64(publicKey);
        RSAPublicKey pubKey;
        String outStr = null;

        try {
            pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes(StandardCharsets.UTF_8)));
        } catch (InvalidKeySpecException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException |
                 NoSuchPaddingException | NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        // RSA加密
        return outStr;
    }

    /**
     * RSA私钥解密
     *
     * @param str        加密字符串
     * @param privateKey 私钥
     * @return 明文
     */
    public static String decrypt(String str, String privateKey) {
        //64位解码加密后的字符串
        byte[] inputByte = Base64.decodeBase64(str.getBytes(StandardCharsets.UTF_8));
        //base64编码的私钥
        byte[] decoded = Base64.decodeBase64(privateKey);
        RSAPrivateKey priKey;
        //RSA解密
        Cipher cipher;
        String outStr = null;

        try {
            priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
            cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, priKey);
            outStr = new String(cipher.doFinal(inputByte));
        } catch (InvalidKeySpecException | NoSuchAlgorithmException | NoSuchPaddingException | BadPaddingException |
                 IllegalBlockSizeException | InvalidKeyException e) {
            e.printStackTrace();
        }
        return outStr;
    }

}

实例结果:

简单的应用场景: 先生成一对公私钥匙对,前端拿公钥加密,后端拿私钥解密。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/485443.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

f(x)与|f(x)|,f ‘ (x),F(x)常见关系。

1.f(x)与|f(x)|关系。 1.连续关系。(f(x)在"[a,b]上连续" > |f(x)|在"[a,b]连续") ①如果f(x)在[a,b]上连续。则|f(x)|在[a,b]上连续. &#xff08;因为f(x)在x0的连续点>x0必为|f(x)|的连续点&#xff09; 注&#xff1a;”[a,b]连续“包括&#…

PUBG绝地求生的制作公司计划今年推出NFT元宇宙游戏

欢迎来到Hubbleverse &#x1f30d; 关注我们 关注宇宙新鲜事 &#x1f4cc; 预计阅读时长&#xff1a;5分钟 本文仅代表作者个人观点&#xff0c;不代表平台意见&#xff0c;不构成投资建议。 近年来&#xff0c;元宇宙的概念在游戏界获得了极大的关注。元宇宙指的是一个虚…

武汉大学惯性导航课程合集【2021年秋】2.1 惯导机械编排算法

Vrb是客观存在的&#xff0c;b相对于r的速度&#xff08;从R到b的变化&#xff09;&#xff0c;右上角的b表示投影到p坐标系&#xff0c;只是表达数值的不同。 &#xff08;工程上5-10&#xff0c;50倍&#xff09;奈奎斯特采样率&#xff0c;香农采样定理&#xff0c;又称奈…

Synthesys:语音合成和视频生成平台

【产品介绍】 Synthesys是一个基于人工智能的语音合成和视频生成平台&#xff0c;可以让你用几分钟的时间&#xff0c;就能制作出专业的音频和视频内容&#xff0c;无需花费大量的金钱和时间去雇佣演员、摄像机或音频设备。Synthesys的技术可以把你的文本转换成逼真的人声和人像…

《花雕学AI》AI时代来临,互联网教父凯文·凯利给你50条生存指南:5000天后的世界会是什么样?

你知道凯文凯利吗&#xff1f;他是《连线》杂志的创始人之一&#xff0c;被誉为“世界互联网教父”&#xff0c;他的预言和观点影响了无数人的思考和行动。他曾经预言过互联网、社交媒体、区块链等技术的发展和变革&#xff0c;而现在&#xff0c;他又给我们带来了一个全新的预…

Vue电商项目--防抖节流应用

演示卡顿现象 正常&#xff1a;事件触发非常频繁&#xff0c;而且每一次的触发&#xff0c;回调函数都要去执行&#xff08;如果时间很短&#xff0c;而回调函数内部有计算&#xff0c;那么很容易出现浏览器卡顿&#xff09; 正常情况下&#xff08;用户慢慢的操作&#xff0…

基于Transformer的DETR的注意力权重可视化,非CAM可视化技术

神经网络的可视化可以客观的解释 “黑盒” &#xff0c;所以一直以来都是论文中必不可少的工作。对于深度卷积神经网络&#xff0c;一般用CAM进行可视化研究。遗憾的是&#xff0c;基于Transformer的神经网络可视化&#xff0c;CAM并不奏效。所以&#xff0c;本文章提供一套基于…

考研机试刷题第二天:任意进制转任意进制【高进度短除法】

理一下思路&#xff1a; 看了y总的视频之后我觉得这道题其实只需要对上次写的进制转换微微做一下调整即可。 于是我写出了下面的代码 #include <iostream> #include <vector> #include <algorithm> #include <cstring>using namespace std;vector<…

SpringCloud微服务如何进行权限校验?

一、概述&#xff1a; 1、什么是Spring Cloud&#xff1f; SpringCloud, 基于SpringBoot提供了一套微服务解决方案&#xff0c;包括服务注册与发现&#xff0c;配置中心&#xff0c;全链路监控&#xff0c;服务网关&#xff0c;负载均衡&#xff0c;熔断器等组件&#xff0c;…

数据结构(六)—— 二叉树(4)回溯

文章目录 一、题1 257 二叉树的所有路径1.1 写法11.2 写法2 一、题 1 257 二叉树的所有路径 1.1 写法1 递归回溯&#xff1a;回溯是递归的副产品&#xff0c;只要有递归就会有回溯 首先考虑深度优先搜索&#xff1b;而题目要求从根节点到叶子的路径&#xff0c;所以需要前序…

第一章 算法概述

第1章-算法概述 总分&#xff1a;100分 得分&#xff1a;30.0分 1 . 填空题 简单 10分 递归算法必须具备的两个条件是___和___ 回答错误 答案 边界条件或停止条件、递推方程或递归方程 2 . 填空题 中等 10分 冒泡排序时间复杂度是___&#xff0c;堆排序时…

深度学习笔记--本地部署Mini-GPT4

目录 1--前言 2--配置环境依赖 3--下载权重 4--生成 Vicuna 权重 5--测试 6--可能出现的问题 1--前言 本机环境&#xff1a; System: Ubuntu 18.04 GPU: Tesla V100 (32G) CUDA: 10.0 项目地址&#xff1a;https://github.com/Vision-CAIR/MiniGPT-4 2--配置环境依赖 …

18.考虑阶梯式碳交易机制与电制氢的综合能源系统热电优化

说明书 MATLAB代码&#xff1a;考虑阶梯式碳交易机制与电制氢的综合能源系统热电优化 关键词&#xff1a;碳交易 电制氢 阶梯式碳交易 综合能源系统 热电优化 参考文档&#xff1a;《考虑阶梯式碳交易机制与电制氢的综合能源系统热电优化》基本复现 仿真平台&#xff1a;M…

洞车常见问题解决指南

洞车常见问题解决指南 1.研发脚本处理问题1.1 WMS出库单无法审核1.2 OMS入库单无法提交&#xff0c;提示更新中心库存失败1.3 当出现OMS下发成功WMS/TMS/DMS还没有任务的情况时处理方案1.4 调度波次生成或者添加任务系统异常1.5 东鹏出库单部分出库回传之后要求重传1.6 更新订单…

表情符号(emoji)大全,只此一文便够了

本文由 大侠(AhcaoZhu)原创&#xff0c;转载请声明。 链接: https://blog.csdn.net/Ahcao2008 表情符号&#xff08;emoji&#xff09;大全、只此一文便够了 摘要集中展示笑脸和动物人庆贺和物品食品和物交通和地点符号 符号表smileys_and_peopleanimals_and_naturefood_and_dr…

Spring Boot集成ShardingSphere实现数据分片(三) | Spring Cloud 42

一、前言 在前面我们通过以下章节对数据分片有了基础的了解&#xff1a; Spring Boot集成ShardingSphere实现数据分片&#xff08;一&#xff09; | Spring Cloud 40 Spring Boot集成ShardingSphere实现数据分片&#xff08;二&#xff09; | Spring Cloud 41 知道数据分片…

Sentinel --- 简介、流量控制

一、Sentinel 1.1、雪崩问题及解决方案 雪崩问题 微服务中&#xff0c;服务间调用关系错综复杂&#xff0c;一个微服务往往依赖于多个其它微服务。 如图&#xff0c;如果服务提供者I发生了故障&#xff0c;当前的应用的部分业务因为依赖于服务I&#xff0c;因此也会被阻塞。此…

Spring AOP(重点、难点)

Spring AOP&#xff08;重点、难点&#xff09; 文章目录 Spring AOP&#xff08;重点、难点&#xff09;1.aop引入1.1 使用场景与概念引入1.2 以数据校验记录操作日志为例 写一组代码进行递推初始阶段 老老实实一个一个写&#xff1a;阶段一 **将日志和验证方法包装到一个类里…

海洋测绘设备使用总结快讯(2023年5月)

本文主要记录最近海洋测绘设备使用过程中遇到一些小问题和解决方法。 1、侧扫声纳绞车的事情 从去年10月到今年3月一直有一个困扰我们的问题&#xff1a;我们侧扫声纳的铠装缆在租用广西北海渔船且用发电机发电的情况下&#xff0c;能连接Klein3000和Klein4000拖鱼&#xff0…

通过Date类学习面向对象

通过手撸这个类的实现&#xff0c;我们可以学习到构造、析构、运算符重载&#xff0c;拷贝构造等面向对象中重要的知识。 首先先看头文件中类的定义&#xff1a; class Date { public:// 获取某年某月的天数int GetMonthDay(int year, int month);// 全缺省的构造函数Date(in…