第十二章 非对称加密算法-RSA

注意:本节内容主要参考自《Java加密与解密的艺术(第2版)》第8章“高等加密算法--非对称加密算法”

12.1、RSA(最经典的非对称加密算法)

特点:

  • 使用一套密钥即可完成加解密(与DH不同)
  • 与DH不同的第二点是,RSA自己可以完成加解密,而DH需要依赖于对称加密算法
  • “私钥加密,公钥解密”或“公钥加密,私钥解密”
  • 公钥长度远小于私钥长度(对下边的代码进行测试,自己比较结果)

加解密流程:

1)发送方(假设为甲方)构建密钥对,自己保留私钥,将公钥发送给接收方(假设为乙方)

2)甲方使用密钥对消息进行加密,乙方使用公钥对消息解密(“私钥加密,公钥解密”)或者乙方使用公钥对消息进行加密,甲方使用私钥对消息解密(“公钥加密,私钥解密”)

注意:公钥加密方式存在安全隐患,如果需要更加安全的方式,就需要甲乙双方均存一份密钥对,仅仅使用“私钥加密,公钥解密”的方式,这种方式与DH类似,但是不同,在DH中甲乙双方各自保留着自己的公钥+私钥,而更安全的RSA是甲乙方法均保存着自己的私钥与对方的公钥,这是RSA与DH的第三点不同。

实现方式:

  • JDK(工作模式只有ECB,填充方式可以采用PKCS1Padding,没有PKCS5Padding,密钥长度:512~65536(64的整数倍))
  • Bouncy Castle(BC,工作模式没有,填充方式可以采用PKCS1Padding,没有PKCS7Padding,密钥长度:512~65536(64的整数倍))

基于JDK实现的RSA加解密代码:

  1 package RSAJDK;
  2
  3 import java.io.UnsupportedEncodingException;
  4 import java.security.InvalidKeyException;
  5 import java.security.KeyFactory;
  6 import java.security.KeyPair;
  7 import java.security.KeyPairGenerator;
  8 import java.security.NoSuchAlgorithmException;
  9 import java.security.PrivateKey;
 10 import java.security.PublicKey;
 11 import java.security.spec.InvalidKeySpecException;
 12 import java.security.spec.PKCS8EncodedKeySpec;
 13 import java.security.spec.X509EncodedKeySpec;
 14
 15 import javax.crypto.BadPaddingException;
 16 import javax.crypto.Cipher;
 17 import javax.crypto.IllegalBlockSizeException;
 18 import javax.crypto.NoSuchPaddingException;
 19
 20 import org.apache.commons.codec.binary.Base64;
 21
 22 /**
 23  * 基于JDK的RSA算法,工作模式采用ECB
 24  */
 25 public class RSAJDK {
 26     private static final String ENCODING = "UTF-8";
 27     private static final String KEY_ALGORITHM = "RSA";//非对称加密密钥算法
 28     private static final String CIPHER_ALGORITHM = "RSA/ECB/PKCS1Padding";//加解密算法 格式:算法/工作模式/填充模式
 29     private static final int KEY_SIZE = 512;//非对称密钥长度(512~1024之间的64的整数倍)
 30
 31     /**
 32      * 还原公钥
 33      * @param pubKey 二进制公钥
 34      */
 35     public static PublicKey toPublicKey(byte[] pubKey) throws NoSuchAlgorithmException,
 36                                                               InvalidKeySpecException{
 37         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);//密钥工厂
 38         return keyFactory.generatePublic(new X509EncodedKeySpec(pubKey));//还原公钥
 39     }
 40
 41     /**
 42      * 还原私钥
 43      * @param priKey 二进制私钥
 44      */
 45     public static PrivateKey toPrivateKey(byte[] priKey) throws NoSuchAlgorithmException,
 46                                                                 InvalidKeySpecException{
 47         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);//密钥工厂
 48         return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(priKey));//还原私钥
 49     }
 50
 51     /**
 52      * 生成甲方密钥对
 53      */
 54     public static KeyPair initKey() throws NoSuchAlgorithmException{
 55         KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);//密钥对生成器
 56         keyPairGenerator.initialize(KEY_SIZE);//指定密钥长度
 57         KeyPair keyPair = keyPairGenerator.generateKeyPair();//生成密钥对
 58         return keyPair;
 59     }
 60
 61     /**
 62      * 私钥加密
 63      * @param data     待加密数据
 64      * @param keyByte  私钥
 65      */
 66     public static byte[] encryptPriKey(String data, byte[] keyByte) throws NoSuchAlgorithmException,
 67                                                                            InvalidKeySpecException,
 68                                                                            NoSuchPaddingException,
 69                                                                            InvalidKeyException,
 70                                                                            IllegalBlockSizeException,
 71                                                                            BadPaddingException,
 72                                                                            UnsupportedEncodingException {
 73         PrivateKey priKey = toPrivateKey(keyByte);//还原私钥
 74
 75         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
 76         cipher.init(Cipher.ENCRYPT_MODE, priKey);//设置加密模式并且初始化key
 77         return cipher.doFinal(data.getBytes(ENCODING));
 78     }
 79
 80     /**
 81      * 公钥加密
 82      * @param data        待加密数据
 83      * @param keyByte    公钥
 84      */
 85     public static byte[] encryptPubKey(String data, byte[] keyByte) throws NoSuchAlgorithmException,
 86                                                                            InvalidKeySpecException,
 87                                                                            NoSuchPaddingException,
 88                                                                            InvalidKeyException,
 89                                                                            IllegalBlockSizeException,
 90                                                                            BadPaddingException,
 91                                                                            UnsupportedEncodingException {
 92         PublicKey pubKey = toPublicKey(keyByte);//还原公钥
 93
 94         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
 95         cipher.init(Cipher.ENCRYPT_MODE, pubKey);//设置加密模式并且初始化key
 96         return cipher.doFinal(data.getBytes(ENCODING));
 97     }
 98
 99     /**
100      * 私钥解密
101      * @param data        待解密数据
102      * @param keyByte    私钥
103      */
104     public static byte[] decryptPriKey(byte[] data, byte[] keyByte) throws NoSuchAlgorithmException,
105                                                                            InvalidKeySpecException,
106                                                                            NoSuchPaddingException,
107                                                                            InvalidKeyException,
108                                                                            IllegalBlockSizeException,
109                                                                            BadPaddingException {
110         PrivateKey priKey = toPrivateKey(keyByte);//还原私钥
111
112         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
113         cipher.init(Cipher.DECRYPT_MODE, priKey);
114         return cipher.doFinal(data);
115     }
116
117     /**
118      * 公钥解密
119      * @param data
120      * @param keyByte    公钥
121      */
122     public static byte[] decryptPubKey(byte[] data, byte[] keyByte) throws NoSuchAlgorithmException,
123                                                                            InvalidKeySpecException,
124                                                                            NoSuchPaddingException,
125                                                                            InvalidKeyException,
126                                                                            IllegalBlockSizeException,
127                                                                            BadPaddingException {
128         PublicKey pubKey = toPublicKey(keyByte);//还原公钥
129
130         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
131         cipher.init(Cipher.DECRYPT_MODE, pubKey);
132         return cipher.doFinal(data);
133     }
134
135     /**
136      * 获取公钥
137      */
138     public static byte[] getPublicKey(KeyPair keyPair){
139         return keyPair.getPublic().getEncoded();
140     }
141
142     /**
143      * 获取私钥
144      */
145     public static byte[] getPrivateKey(KeyPair keyPair){
146         return keyPair.getPrivate().getEncoded();
147     }
148
149     /**
150      * 测试
151      */
152     public static void main(String[] args) throws NoSuchAlgorithmException,
153                                                   InvalidKeyException,
154                                                   InvalidKeySpecException,
155                                                   NoSuchPaddingException,
156                                                   IllegalBlockSizeException,
157                                                   BadPaddingException,
158                                                   UnsupportedEncodingException{
159         byte[] pubKey1;//甲方公钥
160         byte[] priKey1;//甲方私钥
161
162         /*********************测试是否可以正确生成以上2个key*********************/
163         KeyPair keyPair1 = RSAJDK.initKey();//生成甲方密钥对
164         pubKey1 = RSAJDK.getPublicKey(keyPair1);
165         priKey1 = RSAJDK.getPrivateKey(keyPair1);
166
167         System.out.println("甲方公钥pubKey1-->"+Base64.encodeBase64String(pubKey1)+"@@pubKey1.length-->"+pubKey1.length);
168         System.out.println("甲方私钥priKey1-->"+Base64.encodeBase64String(priKey1)+"@@priKey1.length-->"+priKey1.length);
169
170         /*********************测试甲方使用私钥加密数据向乙方发送,乙方使用公钥解密数据*********************/
171         System.out.println("甲方-->乙方");
172         String data = "找一个好姑娘啊!";
173         byte[] encodeStr = RSAJDK.encryptPriKey(data, priKey1);
174         System.out.println("甲方加密后的数据-->"+Base64.encodeBase64String(encodeStr));
175         byte[] decodeStr = RSAJDK.decryptPubKey(encodeStr, pubKey1);
176         System.out.println("乙方解密后的数据-->"+new String(decodeStr,"UTF-8"));
177
178         /*********************测试乙方使用私钥加密数据向甲方发送,甲方使用公钥解密数据*********************/
179         System.out.println("乙方-->甲方");
180         String data2 = "找一个好姑娘啊!";
181         byte[] encodeStr2 = RSAJDK.encryptPubKey(data2, pubKey1);
182         System.out.println("乙方加密后的数据-->"+Base64.encodeBase64String(encodeStr2));
183         byte[] decodeStr2 = RSAJDK.decryptPriKey(encodeStr2, priKey1);
184         System.out.println("甲方解密后的数据-->"+new String(decodeStr2,"UTF-8"));
185     }
186 }

注意:

自己若看了DH算法,试着比较一下RSA算法与DH的区别,并使这些一下更安全的RSA算法(生成两个密钥对,其实就是在上述的代码中再添加一个乙方的密钥对生成方法即可)

疑问:在我配置非对称密钥为512的时候,测出来的公钥长度是96位,私钥长度是345位,与512差很远,那这里的512到底是怎么计算的?(希望知道的朋友给解释一下)

时间: 2024-12-04 21:34:58

第十二章 非对称加密算法-RSA的相关文章

第十二章、软件包管理

第十二章.软件包管理 本章内容 ?软件运行环境 ?软件包基础 ?rpm包管理 ?yum管理 ?定制yum仓库 ?编译安装 软件运行和编译 ABI:Application Binary Interface Windows与Linux不兼容 ELF(Executable and Linkable Format) PE(Portable Executable) 库级别的虚拟化: Linux: WINE Windows: Cywin API:Application Programming Interfa

【.NET Core项目实战-统一认证平台】第十二章 授权篇-深入理解JWT生成及验证流程

原文:[.NET Core项目实战-统一认证平台]第十二章 授权篇-深入理解JWT生成及验证流程 [.NET Core项目实战-统一认证平台]开篇及目录索引 上篇文章介绍了基于Ids4密码授权模式,从使用场景.原理分析.自定义帐户体系集成完整的介绍了密码授权模式的内容,并最后给出了三个思考问题,本篇就针对第一个思考问题详细的讲解下Ids4是如何生成access_token的,如何验证access_token的有效性,最后我们使用.net webapi来实现一个外部接口(本来想用JAVA来实现的,

2014年软考-信息技术处理员-模拟试题及答案【第十二章】

51CTO学院,在软考备考季特别整理了"2014年软考信息技术处理员模拟试题及答案[汇总篇]",帮助各位学院顺利过关!更多软件水平考试辅导及试题,请关注51CTO学院-软考分类吧! 查看汇总:2014年软考-信息技术处理员-模拟试题及答案[汇总篇]  ●在主存和CPU之间增加Cache的目的是____(26)____. A.增加内存容量 B.为程序员编程提供方便 C.解决CPU与内存间的速度匹配问题 D.提高内存工作的可靠性 ●ADSL对应的中文术语是____(27)____. A.分

C和指针 (pointers on C)——第十二章:使用结构和指针

第十二章 使用结构和指针 这章就是链表.先单链表,后双向链表. 总结: 单链表是一种使用指针来存储值的数据结构.链表中的每个节点包含一个字段,用于指向链表的下一个节点. 有一个独立的根指针指向链表的第1个节点.单链表只能从一个方向遍历. 如何insert单链表:1.新节点的link字段必须设置为指向它的后面节点.2.前一个节点的link字段必须指向这个新节点. 为了防止可能会插入链表的起始位置这种情况,在C中,可以保存一个指向必须进行修改的link字段的指针,而不是保存一个指向前一个节点的指针.

《构建之法》第十一、十二章学习总结

第十一章的内容是软件设计与实现. 在第一节中,讲的是关于分析和设计方法,向我们介绍在"需求分析"."设计与实现"阶段."测试""发布"阶段该搞清楚的问题. 在第二节中,讲的是关于图形建模和分析方法.在表达实体和实体之间的关系时,可以用到思维导图(Mind Map).实体关系图(ERD).UCD ;在表达数据的流动时,可以用到DFD工具:在表达控制流的时候可以用到FSM工具:前面提到的这些图形建模方法各有特点,UML却可以有一个

C primer plus 第五版十二章习题

看完C prime plus(第五版)第十二章,随带完成了后面的习题. 1.不使用全局变量,重写程序清单12.4的程序. 先贴出12.4的程序,方便对照: 1 /* global.c --- 使用外部变量 */ 2 #include <stdio.h> 3 int units = 0; //一个外部变量 4 void critic(void); 5 int main(void) 6 { 7 extern int units; 8 9 printf ("How many pounds

构造之法第十一、十二章

第十一章 软件设计与实现 图形建模和分析方法 1表达实体和实体之间的关系(思维导图) 2实体关系图 3Use Case Diagram 表达数据的流动 (1)和管理机构相关的数据流 (2)和读者相关的数据流 (3)和新书入库相关的数据流 (4)和时间相关的数据流 表达数据的流动 (1)和管理机构相关的数据流 (2)和读者相关的数据流 (3)和新书入库相关的数据流 (4)和时间相关的数据流 其他设计方法 1.形式化的方法 2.文学化编程 第十二章 用户体验 用户体验的要素 1.用户的第一印象 2.

Java 第十二章 继承 笔记

Java 第十二章  继承 笔记 一.使用继承:     1)方便修改代码     2)减少代码量 二.super 继承object 类:super 访问父类的无参构造:super 指的是object 的无参构造.     例:子类调用父类:super.属性 / super.方法    注意:子类不能继承父类私有属性:得用set.get方法来调用:    super只能写在代码块的第一句:super只能调用非私有的方法:    super只能出现在子类的方法和构造方法中. 三.不能被继承的父类成

JavaScript DOM编程艺术-学习笔记(第十二章)

第十二章 1.本章是综合前面章节的所有东西的,一个综合实例 2.流程:①项目简介:a.获取原始资料(包括文本.图片.音视频等) b.站点结构(文件目录结构) c.页面(文件)结构 ②设计(切图) ③css -  base.css用于引入使用的css文件 color.css  - 用于设置样式 layout.css - 用于设置布局 Typography.css - 用于设置版式 3.题外话:①在实际开发中,即使是一个空白项目也往往不会从一无所有做起,而借助的平台一般会提供目录结构,所以需要把自己