一文详解 RSA 非对称加密算法

2023-10-29

RSA加密算法是一种非对称加密算法。RSA是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。

1973年,在英国政府通讯总部工作的数学家克利福德·柯克斯(Clifford Cocks)在一个内部文件中提出了一个相同的算法,但他的发现被列入机密,一直到1997年才被发表。

对极大整数做因数分解的难度决定了RSA算法的可靠性。 换言之,对一极大整数做因数分解愈困难,RSA算法愈可靠。假如有人找到一种快速因数分解的算法的话,那么用RSA加密的信息的可靠性就肯定会极度下降。 但找到这样的算法的可能性是非常小的。今天只有短的RSA钥匙才可能被强力方式解破。到目前为止,世界上还没有任何可靠的攻击RSA算法的方式。只要其钥匙的长度足够长,用RSA加密的信息实际上是不能被解破的。

一、举一个通俗易懂的例子

看一个数学小魔术:

让A写下一个任意3位数,并将这个数和91相乘;然后将积的最后三位数告诉B,这样B就可以计算出A写下的是什么数字了。

  • 比如A写下的是123,并且A计算出123 * 91等于11193,并把结果的末三位193告诉B ;
  • B只需要把193再乘以11,193 * 11 = 2123 末三位就是A写下的数字了;

道理很简单,91乘以11等于1001,而任何一个三位数乘以1001后,末三位显然都不变(例如123乘以1001就等于123123)。

知道原理后,可以构造一个定义域和值域更大的加密解密系统。
例如:

  • 任意一个数乘以400000001后,末8位都不变,而400000001 = 19801 * 20201。于是A来乘以19801,B来乘以20201,又一个加密解密不对称的系统就构造好了;
  • 甚至可以构造得更大一些 4000000000000000000000000000001 = 1199481995446957 * 3334772856269093,这样我们就成功构造了一个30位的加密系统;

如果仅仅按照上面的思路,如果对方知道原理,非常容易穷举出400000001这个目标值;RSA算法使用的是指数和取模运算,本质上就是上面这套思想。

此段落转载自:
如何用通俗易懂的话来解释非对称加密?

二、RSA加密算法

2.1、维基百科——RSA加密算法

先看一下维基百科的算法描述:

公钥与私钥的产生

  • 1、随意选择两个大的质数 p和 q,p不等于 q,计算 N=pq
  • 2、根据欧拉函数,求得 r
r = φ(N) = φ(p)φ(q) = (p-1)(q-1)
  • 3、选择一个小于r并与r互质的整数e,求得e关于r的模反元素,命名为d ( ed ≡ 1(mod r) 模反元素存在,当且仅当e与r互质 );
  • 4、销毁p和q,此时 (N , e)是公钥,(N, d)为私钥;

加密消息

假设Bob想给Alice发送一个消息 n,他知道Alice产生的 N和 e ;用下面这个公式他可以将 n加密为 c :

c ≡ n^e (mod N)

计算 c并不复杂。Bob算出 c后就可以将它传递给Alice。

解密消息

Alice得到Bob的消息 c后就可以利用她的密钥d来解码。可以用以下这个公式来将 c转换为 n

n ≡ c^d (mod N)

此段落转载自:
维基百科——RSA加密算法

2.2、依照算法公式举个例子

依照算法公式来举个例子

1、随意选择两个大的质数 p和 q,p不等于 q,计算 N=pq

质数 定义:

除了1和该数自身外,无法被其他自然数整除的数。

举例:

p = 3;
q = 5;
N = 3*5 = 15;

2、根据欧拉函数,求得 r

r = φ(N) = φ(p)φ(q) = (p-1)(q-1)。

欧拉函数 定义:

欧拉函数 φ(n)是小于或等于n的正整数中与n互质的数的数目。

例如:φ(8) = 4,因为1,3,5,7均和8互质。

举例:

r = φ(N) = φ(p)φ(q) = (p-1)(q-1) ;

r = φ(15) = φ(3)φ(5) = (3-1)(5-1) ;
r = 8

3、选择一个小于r并与r互质的整数e,求得e关于r的模反元素,命名为d ( ed ≡ 1(mod r) 模反元素存在,当且仅当e与r互质 );

互质 定义:

如果两个或两个以上的整数的最大公约数是 1,则称它们为互质

例如:1,3,5,7均和8互质

模反元素 定义:

如果两个正整数a和n互质,那么一定可以找到整数b,使得 ab-1 被n整除,或者说ab被n除的余数是1。

例如:比如3和5互质,3关于5的模反元素就可能是2,因为 (3*2)%5=1 。

举例:

// 选择一个小于r并与r互质的整数e (1,3,5,7均和8互质):
e = 7;
// 求得e关于r的模反元素,命名为d (    ed ≡ 1(mod r)     ) 

ed ≡ 1(mod r) ;

7*d ≡ 1(mod 8) ;
7*d%8 = 1; 
// 这里取d = 15
d = 15;

4、销毁p和q,此时 (N , e)是公钥,(N, d)为私钥

// 公钥  (N , e)
( 15,7 )
// 私钥 (N, d)
( 15,15 )

5、加密

假设Bob想给Alice发送一个消息 n,他知道Alice产生的 N和 e ;用下面这个公式他可以将 n加密为 c

举例:

// 假设 
n = 2;
// 计算c
c ≡ n^e (mod N) ;

(c^-1 * n^e)%N = 1 ; 
(c^-1 * 2^7)%15 = 1 ;
// 
c = 8;

6、解密

Alice得到Bob的消息 c后就可以利用她的密钥d来解码。可以用以下这个公式来将 c转换为 n

举例:

// 计算n
n ≡ c^d (mod N)

n ≡ 8^15 (mod 15) ;
(n^-1 * 8^15)%15 = 1 ;
//
n = 2;

三、java中使用RSA:

1、示例1:

public class RsaTest {
    private static final Integer keySize = 1024;
    static BigInteger e = null;
    static BigInteger d = null;
    static BigInteger N = null;
    static {
        try {
            KeyPairGenerator kpGenerator = KeyPairGenerator.getInstance("RSA");
            kpGenerator.initialize(keySize.intValue());
            KeyPair keyPair = kpGenerator.generateKeyPair();
            RSAPublicKey pub = (RSAPublicKey) keyPair.getPublic();
            RSAPrivateKey priv = (RSAPrivateKey) keyPair.getPrivate();
            e = pub.getPublicExponent();
            d = priv.getPrivateExponent();
            N = pub.getModulus();
        } catch (Exception e) {} 
    }
    //下面两个函数只能对正整数进行加密、解密
    public static String encrypt(String msg) {
        return new BigInteger(msg).modPow(e, N).toString();
    }
    public static String decrypt(String msg) {
        return new BigInteger(msg).modPow(d, N).toString();
    }
    //下面两个函数可以对任何字符串加解密
    public static String encrypt1(String msg) {
        byte[] bytes = msg.getBytes();
        if (bytes.length < 8) {
            bytes = (Arrays.copyOf(bytes, 8));
        }
        long bytes2LongBig = bytes2LongBig(bytes);
        return new BigInteger(bytes2LongBig+"").modPow(e, N).toString();
    }
    public static String decrypt1(String msg) {
        long a = new BigInteger(msg).modPow(d, N).longValue();
        byte[] long2BytesBig = long2BytesBig(a);
        return new String(long2BytesBig);
    }
    private static long bytes2LongBig(byte[] array) {
        return ((((long) array[0] & 0xff) << 56)
                | (((long) array[1] & 0xff) << 48)
                | (((long) array[2] & 0xff) << 40)
                | (((long) array[3] & 0xff) << 32)
                | (((long) array[4] & 0xff) << 24)
                | (((long) array[5] & 0xff) << 16)
                | (((long) array[6] & 0xff) << 8)
                | (((long) array[7] & 0xff)));
    }
    private static byte[] long2BytesBig(long n) {
        byte[] b = new byte[8];
        b[7] = (byte) (n & 0xff);
        b[6] = (byte) (n >> 8 & 0xff);
        b[5] = (byte) (n >> 16 & 0xff);
        b[4] = (byte) (n >> 24 & 0xff);
        b[3] = (byte) (n >> 32 & 0xff);
        b[2] = (byte) (n >> 40 & 0xff);
        b[1] = (byte) (n >> 48 & 0xff);
        b[0] = (byte) (n >> 56 & 0xff);
        return b;
    }
    public static void main(String...strings) {
        String test = "123321111";
        String encrypt = encrypt(test);
        System.out.println(encrypt);
        System.out.println(decrypt(encrypt));

        test = "test";
        encrypt = encrypt1(test);
        System.out.println(encrypt);
        System.out.println(decrypt1(encrypt));
    }
}

说明:利用了JDK中关于RSA的api,计算出e、d、n参数,然后使用BigInteger进行RSA的公式计算。由于bigInteger只能对数字进行运算,所以对于字符串需要先转成byte再转成对应的long型整数。(byte转long时,需要判断byte大小)

2、示例2:

public class RSAUtils {
    @Data
    public static class RSAKeyPair {
        String publicKey;
        String privateKey;
    }
    public static RSAKeyPair getKeyPair() throws Exception{
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
        keyPairGen.initialize(1024, new SecureRandom());
        KeyPair keyPair = keyPairGen.generateKeyPair();
        PrivateKey privateKey = keyPair.getPrivate();
        PublicKey publicKey = keyPair.getPublic();
        String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
        String privateKeyString = new String(Base64.encodeBase64(privateKey.getEncoded()));
        RSAKeyPair rsaKeyPair = new RSAKeyPair();
        rsaKeyPair.setPublicKey(publicKeyString);
        rsaKeyPair.setPrivateKey(privateKeyString);
        return rsaKeyPair;
    }
    public static String encrypt(String str, String publicKey) throws Exception {
        byte[] decoded = Base64.decodeBase64(publicKey);
        RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA")
                .generatePublic(new X509EncodedKeySpec(decoded));
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        return Base64.encodeBase64String(cipher.doFinal(str.getBytes(StandardCharsets.UTF_8)));
    }
    public static String decrypt(String str, String privateKey) throws Exception {
        byte[] inputByte = Base64.decodeBase64(str.getBytes(StandardCharsets.UTF_8));
        byte[] decoded = Base64.decodeBase64(privateKey);
        PrivateKey priKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, priKey);
        return new String(cipher.doFinal(inputByte));
    }
    public static void main(String...strings) throws Exception {
        RSAKeyPair keyPair = RSAUtils.getKeyPair();
        String encrypt = encrypt("test", keyPair.getPublicKey());
        System.out.println(encrypt);
        System.out.println(decrypt(encrypt, keyPair.getPrivateKey()));
    }
}

说明:也是利用了JDK中RSA的api,只是对公钥和私钥进行了Base64处理。 

参考:一文详解 RSA 非对称加密算法 - xiaxueliang - 博客园

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一文详解 RSA 非对称加密算法 的相关文章

  • 如何根据 JComboBox 选择动态地将控件添加到表单?

    我正在尝试使用 Swing 创建一个简单的 java 表单 这个想法的基本思想是用户将在 JComboBox 中选择 0 到 5 然后 通过 ItemStateChanged 侦听器 将动态添加几个面板 每个面板包含 4 个控件 因此 如果
  • 完整的 C++ i18n gettext()“hello world”示例

    我正在寻找完整的 i18ngettext 你好世界的例子 我已经开始了一个基于的脚本使用 GNU gettext 的本机语言支持教程 https web archive org web 20130330233819 http oriya s
  • SimpleDateFormat 无法正确处理 DD

    我正在尝试获得这样的格式 2013 06 15 17 45 我在代码中执行以下操作 Date d new Date SimpleDateFormat ft new SimpleDateFormat YYYY MM DD HH mm Stri
  • 使用 Thymeleaf 时我们应该删除 HTML 属性吗?

    我正在研究 Thymeleaf 发现几乎所有示例中都有 Thymeleaf 的标签值以及标准 HTML 值 例如 这些
  • Java Swing JEditorPane:操作样式文档

    我的模型是与枚举类型关联的字符串队列 我试图在 JEditorPane 中显示该模型 队列中的每个元素作为一个单独的 HTML 段落 其属性基于关联的枚举类型 但是 我的更新方法并没有达到我想要的效果 我尝试将 HTML 字符串直接写入文档
  • EasyMock : java.lang.IllegalStateException: 1 个匹配器预期,2 个记录

    我在使用 EasyMock 2 5 2 和 JUnit 4 8 2 通过 Eclipse 运行 时遇到问题 我已阅读此处所有类似的帖子 但尚未找到答案 我有一个包含两个测试的类 它们测试相同的方法 我正在使用匹配器 每个测试单独运行时都会通
  • 添加和完成 PHP 源代码文档的工具 [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我有几个已完成的较旧的 PHP 项目 其中有很多内容 我想以 javadoc phpDocumentor
  • 在 Java/GWT 中解析用户时间输入

    解析用户在 GWT 中的文本字段中键入的时间的最佳方法是什么 默认时间格式要求用户完全按照区域设置指定的时间格式输入时间 我想要更加灵活 因为用户可以通过多种不同的方式输入时间 例如 8 8p 8pm 8 15pm 13 15 1315 1
  • 运行 shell 命令并将输出发送到文件?

    我需要能够通过 php 脚本修改我的 openvpn 身份验证文件 我已将我的 http 用户设置为免通 sudoer 因为这台机器仅在我的家庭网络中可用 我目前有以下命令 echo shell exec sudo echo usernam
  • APACHE POI 从 Java 中的 Excel 获取精确的字体颜色

    在 Excel 工作表中 如何使用 Java 中的 Apache POI 获取准确的字体颜色值 我试图通过使用来获取字体颜色 org apache poi ss usermodel Font f book getFontAt style g
  • 使用 Lint 和 SonarQube 分析 Android 项目

    我真的 溢出 了试图让这些东西一起工作 我按照这里的指示进行操作 http docs sonarqube org display PLUG Android Lint Plugin http docs sonarqube org displa
  • 从字符串中提取文本 Java

    使用此字符串 ADACADABRA 如何从java中的字符串 ADACADABRA 中提取 CADA 以及如何提取 和 之间的id从下面的链接 http www youtube nocookie com embed zaaU9lJ34c5
  • JSF“总”变量类似于 JSTL 中的 c:set

    我不喜欢 JSF 但我需要用它来解决这个问题 我正在 纯 JSF 中工作 所以这就是我基本上需要的 但我不知道如何用 JSF 来实现它
  • System.out.println("嗨"+6+10);打印Hi610?

    为什么要这样做 太令人困惑了 运算符优先级和结合性 两点 操作员 如果一个或两个参数都是字符串 则进行字符串连接 操作员 从左到右工作 所以在你的例子中 Hi 6 is Hi6 and Hi6 10 is Hi610 编辑 正如您在对另一个
  • SecurityContextHolder.getContext().getAuthentication() 返回 null

    我想使用以下代码手动绕过 spring Security 的用户 User localeUser new User UsernamePasswordAuthenticationToken auth new UsernamePasswordA
  • 如何设置 commons-logging 来使用 logback?

    我们使用 slf4j logback 并且碰巧有一些使用 commons logging 的第三方库 如何设置它以使用 logback 答案是不要使用 commons logging jar 因为 SLF4J 的设计目的与 commons
  • 从 IntelliJ 运行 JavaFX 应用程序

    Versions openjdk版本 11 0 11 2021 04 20 OpenJDK 运行时环境 build 11 0 11 9 Ubuntu 0ubuntu2 20 10 OpenJDK 64 位服务器虚拟机 内部版本 11 0 1
  • 如何使用 Kafka 发送大消息(超过 15MB)?

    我发送字符串消息到Kafka V 0 8使用 Java Producer API 如果消息大小约为 15 MB 我会得到MessageSizeTooLargeException 我尝试过设置message max bytes到 40 MB
  • 丰富:数据表行跨度问题

    我需要创建一个 rich dataTable 甚至扩展 具有以下功能 我有一个公司类 其中包含产品对象的集合 我想展示下表 我仍然没有弄清楚如何使用子表执行此操作 在所有示例中 我发现子表具有与主表完全相同的列 据推测 我需要在前两列中使用
  • 如何获取 res.drawable 文件夹的路径来复制文件?

    我正在编写我的应用程序AndroidStudio 我的里面有gif文件drawable gifs文件夹 我希望将该文件复制到MediaStore Images Media单击按钮后的文件夹 目前 即使使用发布的一些答案 我也无法获取我的 g

随机推荐

  • kylin在hadoop 中的架构图_kylin跨集群配置实现读写分离

    社区提供的读写分离架构图如下 通过架构图可以看到Kylin会访问两个集群的HDFS 建议两个集群的NameService务必不能相同 尤其是集群启用NameNode HA时 相同的NameService会导致组件在跨集群访问HDFS时因无法
  • nginx配置ssl证书https解决公网ip可以访问但是域名不行的问题

    进入nginx文件夹 将下载得到的crt和key文件放到这个目录下 以下来自腾讯云官方 https cloud tencent com document product 400 35244 server SSL 访问端口号为 443 lis
  • 警告:[SetPropertiesRule]Setting property 'source' to xxx did not find a matching property.的消除

    启动JSP页面时报错 全文如下 九月 25 2016 7 47 39 下午 org apache tomcat util digester SetPropertiesRule begin 警告 SetPropertiesRule Serve
  • Python(练习七)

    一 max 0 count 0 while True num int input Enter a number 0 for end of input if num 0 break if num gt max max num count 1
  • mongodb如何使用授权登录

    前言 mongodb默认是不需要授权登录的 这样在实际生产环境中是非常危险的一件事情 接下来就来讲一下如何开启安全授权访问 1 第一次登录不启动授权 默认就是不启动 我们先来创建admin和root账号 他们是用来开启授权后操作用户 创建数
  • PWNHUB 一场新鲜赛事速达【六月内部赛】 web - login game + Misc - 伏羲八卦

    PWNHUB 一场新鲜赛事速达 六月内部赛 web login game Misc 伏羲八卦 web login game Misc 伏羲八卦 本文来自csdn的 shu天 平时会记录ctf 取证和渗透相关的文章 欢迎大家来我的主页 shu
  • thinkpad笔记本如何进bios设置u盘启动步骤

    thinkpad笔记本从u盘启动有两种方法 一种是使用u盘启动快捷键直接进入u盘装系统 另一种则需要进bios设置u盘为第一启动项 但首先要下载个u盘启动盘制作工具制作成启动u盘在进行 下面详细为大家介绍如何操作 方法一 使用u盘启动快捷键
  • 脚本一:编写一个脚本要求检测文件类型(简化版)

    要求 1 命名为check file sh 2 检测判断它是否存在 3 判断它是否为普通文件 4 判断其是否为目录 5 判断其是否为软链接 6 如没有文件名则报错 编写脚本如下 验证文件如下 可见如果文件不存在 直接报错 如果符合条件直接给
  • 《Web安全基础》05. XSS · CSRF · SSRF · RCE

    web 1 XSS 1 1 简介 1 2 防护与绕过 1 2 1 HttpOnly 1 2 2 WAF 绕过 1 3 相关资源 2 CSRF 3 SSRF 4 RCE 本系列侧重方法论 各工具只是实现目标的载体 命令与工具只做简单介绍 其使
  • 行人属性识别的一个调研

    行人属性识别的一个调研 知乎 前言 我感觉我掌握了财富密码 从知乎的后台数据来看 大家貌似更喜欢看综述多一点 因此这次给大家整个 行人属性识别 PAR 的综述 同样的 这次的综述比较老 是19年的 大家酌情看 适合入门用 首先还是保命时刻
  • 【会议分享】2022年智能车国际会议(ICoIV 2022)

    2022年智能车国际会议 ICoIV 2022 重要信息 会议网址 www icoiv org 会议时间 2022年10月14 16日 召开地点 中国成都 截稿时间 2022年8月30日 录用通知 投稿后2周内 收录检索 EI Scopus
  • 爬虫从入门到精通(8)

    文章目录 一 多进程和多线程介绍 二 普通爬虫 三 多线程爬虫 1 普通方法调用 2 线程类调用 四 多进程爬虫 1 普通方法调用 2 进程类写法 五 gevent协程爬虫 1 gevent模块简介 2 安装和依赖 3 gevent协程爬虫
  • 【深度学习】AlexNet

    从AlexNet开始 一 不可否认 深度学习的热潮正是由2012年AlexNet的出现而引发的 因此 学习AlexNet网络的结构 对于CNN的学习与理解是不可或缺的 在本篇博客中 将会对AlexNet的论文进行翻译与解读 并在下一篇博客中
  • android 壁纸服务,Android-Service实现手机壁纸自动更换

    本文实例为大家分享了Android Service实现自动更换手机壁纸的具体代码 供大家参考 具体内容如下 先看下效果 使用界面 划重点 使用service前别忘了给相应的service添加服务 具体实现 首先定义ChangeService
  • Dialog的exec和open

    今天在使用窗口时 发现了这样一个问题 抽象代码如下 结果第一次调用窗口时 一切正常 但是第二次调用时 窗口里的内容全部消失了 只有一个空白窗口 解决方法 调用open 函数 exec 函数会将程序卡到那里 open 函数生成窗口后立即返回
  • 祭旗之作

    渺小的我 一如原来那样的懒散 我拼命的使自己跟的牛人学习 但是 我总是掉队 我不愿意平庸 但是对于任何事情感觉都是没有坚持到最后 应该更加的坚持 犹豫与多虑 是我的性格 我渴望一直坚持下去 但好多时候 由于时间的关系 选择了放弃 我依然是我
  • SGL基本思路讲解

    SGL图形库是为Windows图形界面编程服务的 而且一切都是考虑到对新手友好的 在具体介绍提供给用户的函数之前 需要先说明一下应该以什么样的思路来构思我们的SGL程序 作为C语言程序 main函数总是需要在最开始就了解一下的 在SGL库中
  • STM32的中断与事件

    这张图是一条外部中断线或外部事件线的示意图 图中信号线上划有一条斜线 旁边标志19字样的注释 表示这样的线路共有19套 图中的蓝色虚线箭头 标出了外部中断信号的传输路径 首先外部信号从编号1的芯片管脚进入 经过编号2的边沿检测电路 通过编号
  • 多线程-单例模式 - Double Check Lock - Volatile

    单例模式 Singleton 保证一个类在程序中仅有一个实例 并提供一个访问该实例的全局访问点 单例模式的实现 饿汉模式 设计思想 在类加载时就创建一个不可变的静态的单例对象 如果该对象不被使用 则浪费了堆空间的资源 问题1 为什么加fin
  • 一文详解 RSA 非对称加密算法

    RSA加密算法是一种非对称加密算法 RSA是1977年由罗纳德 李维斯特 Ron Rivest 阿迪 萨莫尔 Adi Shamir 和伦纳德 阿德曼 Leonard Adleman 一起提出的 当时他们三人都在麻省理工学院工作 RSA就是他