Java 加解密技术系列之 RSA

  • 概念
  • 工作流程
  • RSA
  • 代码实现
  • 加解密结果
  • 结束语


离上一次写博客感觉已经很长时间了,先吐槽一下,这个月以来,公司一直在加班,又是发版、上线,又是新项目太紧,具体的就不多说了,想听我吐槽的小伙伴,
可以私信给我(*^__^*)
。上一篇文章,已经把对称加密的算法讲完了。从今天开始,要说说非对称加密了。因为,非对称加密真的是太重要了,我们的日常生活中,都离不开非对称加密。
概念

在说 RSA 之前,首先聊聊什么是非对称加密。在讲对称加密的时候,就曾经说过,对称加密算法在加密和解密时使用的是同一个秘钥,加解密双方必须使用同一个密钥才能进行正常的沟通。而非对称加密则不然,非对称加密算法需要两个密钥来进行加密和解密,分别是公钥和私钥。
需要注意的一点,这个公钥和私钥必须是一对的,如果用公钥对数据进行加密,那么只有使用对应的私钥才能解密,反之亦然。由于加密和解密使用的是两个不同的密钥,因此,这种算法叫做非对称加密算法。

工作过程

如下图,甲乙之间使用非对称加密的方式传输数据。
在非对称加密中使用的主要算法有:RSA、Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)等。今天主要是介绍 RSA ,至于其他的算法,后续会选择几个进行介绍。

RSA

其实,在早在 1978 年的时候,RSA就已经出现了,它是第一个既能用于数据加密也能用于数字签名的算法。它易于理解和操作,也很流行。其原理就如上面的工作过程所述。
RSA 算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。

代码实现

下面来看一下具体的代码实现。
import com.google.common.collect.Maps;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder; import javax.crypto.Cipher;
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.util.Map; /**
* Created by xiang.li on 2015/3/3.
* RSA 加解密工具类
*/
public class RSA {
/**
* 定义加密方式
*/
private final static String KEY_RSA = "RSA";
/**
* 定义签名算法
*/
private final static String KEY_RSA_SIGNATURE = "MD5withRSA";
/**
* 定义公钥算法
*/
private final static String KEY_RSA_PUBLICKEY = "RSAPublicKey";
/**
* 定义私钥算法
*/
private final static String KEY_RSA_PRIVATEKEY = "RSAPrivateKey"; /**
* 初始化密钥
* @return
*/
public static Map<String, Object> init() {
Map<String, Object> map = null;
try {
KeyPairGenerator generator = KeyPairGenerator.getInstance(KEY_RSA);
generator.initialize(1024);
KeyPair keyPair = generator.generateKeyPair();
// 公钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
// 私钥
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
// 将密钥封装为map
map = Maps.newHashMap();
map.put(KEY_RSA_PUBLICKEY, publicKey);
map.put(KEY_RSA_PRIVATEKEY, privateKey);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return map;
} /**
* 用私钥对信息生成数字签名
* @param data 加密数据
* @param privateKey 私钥
* @return
*/
public static String sign(byte[] data, String privateKey) {
String str = "";
try {
// 解密由base64编码的私钥
byte[] bytes = decryptBase64(privateKey);
// 构造PKCS8EncodedKeySpec对象
PKCS8EncodedKeySpec pkcs = new PKCS8EncodedKeySpec(bytes);
// 指定的加密算法
KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
// 取私钥对象
PrivateKey key = factory.generatePrivate(pkcs);
// 用私钥对信息生成数字签名
Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE);
signature.initSign(key);
signature.update(data);
str = encryptBase64(signature.sign());
} catch (Exception e) {
e.printStackTrace();
}
return str;
} /**
* 校验数字签名
* @param data 加密数据
* @param publicKey 公钥
* @param sign 数字签名
* @return 校验成功返回true,失败返回false
*/
public static boolean verify(byte[] data, String publicKey, String sign) {
boolean flag = false;
try {
// 解密由base64编码的公钥
byte[] bytes = decryptBase64(publicKey);
// 构造X509EncodedKeySpec对象
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
// 指定的加密算法
KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
// 取公钥对象
PublicKey key = factory.generatePublic(keySpec);
// 用公钥验证数字签名
Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE);
signature.initVerify(key);
signature.update(data);
flag = signature.verify(decryptBase64(sign));
} catch (Exception e) {
e.printStackTrace();
}
return flag;
} /**
* 私钥解密
* @param data 加密数据
* @param key 私钥
* @return
*/
public static byte[] decryptByPrivateKey(byte[] data, String key) {
byte[] result = null;
try {
// 对私钥解密
byte[] bytes = decryptBase64(key);
// 取得私钥
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
PrivateKey privateKey = factory.generatePrivate(keySpec);
// 对数据解密
Cipher cipher = Cipher.getInstance(factory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
result = cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return result;
} /**
* 私钥解密
* @param data 加密数据
* @param key 公钥
* @return
*/
public static byte[] decryptByPublicKey(byte[] data, String key) {
byte[] result = null;
try {
// 对公钥解密
byte[] bytes = decryptBase64(key);
// 取得公钥
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
PublicKey publicKey = factory.generatePublic(keySpec);
// 对数据解密
Cipher cipher = Cipher.getInstance(factory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, publicKey);
result = cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return result;
} /**
* 公钥加密
* @param data 待加密数据
* @param key 公钥
* @return
*/
public static byte[] encryptByPublicKey(byte[] data, String key) {
byte[] result = null;
try {
byte[] bytes = decryptBase64(key);
// 取得公钥
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
PublicKey publicKey = factory.generatePublic(keySpec);
// 对数据加密
Cipher cipher = Cipher.getInstance(factory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
result = cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return result;
} /**
* 私钥加密
* @param data 待加密数据
* @param key 私钥
* @return
*/
public static byte[] encryptByPrivateKey(byte[] data, String key) {
byte[] result = null;
try {
byte[] bytes = decryptBase64(key);
// 取得私钥
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
PrivateKey privateKey = factory.generatePrivate(keySpec);
// 对数据加密
Cipher cipher = Cipher.getInstance(factory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
result = cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return result;
} /**
* 获取公钥
* @param map
* @return
*/
public static String getPublicKey(Map<String, Object> map) {
String str = "";
try {
Key key = (Key) map.get(KEY_RSA_PUBLICKEY);
str = encryptBase64(key.getEncoded());
} catch (Exception e) {
e.printStackTrace();
}
return str;
} /**
* 获取私钥
* @param map
* @return
*/
public static String getPrivateKey(Map<String, Object> map) {
String str = "";
try {
Key key = (Key) map.get(KEY_RSA_PRIVATEKEY);
str = encryptBase64(key.getEncoded());
} catch (Exception e) {
e.printStackTrace();
}
return str;
} /**
* BASE64 解密
* @param key 需要解密的字符串
* @return 字节数组
* @throws Exception
*/
public static byte[] decryptBase64(String key) throws Exception {
return (new BASE64Decoder()).decodeBuffer(key);
} /**
* BASE64 加密
* @param key 需要加密的字节数组
* @return 字符串
* @throws Exception
*/
public static String encryptBase64(byte[] key) throws Exception {
return (new BASE64Encoder()).encodeBuffer(key);
} /**
* 测试方法
* @param args
*/
public static void main(String[] args) {
String privateKey = "";
String publicKey = "";
// 生成公钥私钥
Map<String, Object> map = init();
publicKey = getPublicKey(map);
privateKey = getPrivateKey(map);
System.out.println("公钥: \n\r" + publicKey);
System.out.println("私钥: \n\r" + privateKey);
System.out.println("公钥加密--------私钥解密");
String word = "你好,世界!";
byte[] encWord = encryptByPublicKey(word.getBytes(), publicKey);
String decWord = new String(decryptByPrivateKey(encWord, privateKey));
System.out.println("加密前: " + word + "\n\r" + "解密后: " + decWord);
System.out.println("私钥加密--------公钥解密");
String english = "Hello, World!";
byte[] encEnglish = encryptByPrivateKey(english.getBytes(), privateKey);
String decEnglish = new String(decryptByPublicKey(encEnglish, publicKey));
System.out.println("加密前: " + english + "\n\r" + "解密后: " + decEnglish);
System.out.println("私钥签名——公钥验证签名");
// 产生签名
String sign = sign(encEnglish, privateKey);
System.out.println("签名:\r" + sign);
// 验证签名
boolean status = verify(encEnglish, publicKey, sign);
System.out.println("状态:\r" + status);
}
}

加解密结果

结束语

其实,看似很复杂的过程,用一句话就可以描述:使用公钥加密、私钥解密,完成了乙方到甲方的一次数据传递,通过私钥加密、公钥解密,同时通过私钥签名、公钥验证签名,完成了一次甲方到乙方的数据传递与验证,两次数据传递完成一整套的数据交互。
非对称加密算法的出现,就是为了解决只有一把密钥的加解密,只要这一把密钥丢失或者被公开,那么加密数据就很容易被攻击。同时,也正是由于非对称加密算法的出现,才有了后面的数字签名、数字证书等等。
好了,今天就到这吧,下一篇继续非对称加密,至于哪一种,到时候就知道了,这里先保密,(*^__^*) 嘻嘻。

9.Java 加解密技术系列之 RSA的更多相关文章

  1. Java 加解密技术系列文章

    Java 加解密技术系列之 总结 Java 加解密技术系列之 DH Java 加解密技术系列之 RSA Java 加解密技术系列之 PBE Java 加解密技术系列之 AES Java 加解密技术系列 ...

  2. 10.Java 加解密技术系列之 DH

    Java 加解密技术系列之 DH 序 概念 原理 代码实现 结果 结束语 序 上一篇文章中简单的介绍了一种非对称加密算法 — — RSA,今天这篇文章,继续介绍另一种非对称加密算法 — — DH.当然 ...

  3. 11.Java 加解密技术系列之 总结

    Java 加解密技术系列之 总结 序 背景 分类 常用算法 原理 关于代码 结束语 序 上一篇文章中简单的介绍了第二种非对称加密算法 — — DH,这种算法也经常被叫做密钥交换协议,它主要是针对密钥的 ...

  4. 8.Java 加解密技术系列之 PBE

    Java 加解密技术系列之 PBE 序 概念 原理 代码实现 结束语 序 前 边的几篇文章,已经讲了几个对称加密的算法了,今天这篇文章再介绍最后一种对称加密算法 — — PBE,这种加密算法,对我的认 ...

  5. 7.java 加解密技术系列之 AES

    java 加解密技术系列之 AES 序 概念 原理 应用 代码实现 结束语 序 这篇文章继续介绍对称加密算法,至于今天的主角,不用说,也是个厉害的角色 — — AES.AES 的出现,就是为了来替代原 ...

  6. 6. Java 加解密技术系列之 3DES

    Java 加解密技术系列之 3DES 序 背景 概念 原理 代码实现 结束语 序 上一篇文章讲的是对称加密算法 — — DES,这篇文章打算在 DES 的基础上,继续多讲一点,也就是 3 重 DES ...

  7. 5.Java 加解密技术系列之 DES

    Java 加解密技术系列之 DES 序 背景 概念 基本原理 主要流程 分组模式 代码实现 结束语 序 前 几篇文章讲的都是单向加密算法,其中涉及到了 BASE64.MD5.SHA.HMAC 等几个比 ...

  8. 4.Java 加解密技术系列之 HMAC

    Java 加解密技术系列之 HMAC 序 背景 正文 代码 结束语 序 上一篇文章中简单的介绍了第二种单向加密算法 — —SHA,同时也给出了 SHA-1 的 Java 代码.有这方面需求的童鞋可以去 ...

  9. 3.Java 加解密技术系列之 SHA

    Java 加解密技术系列之 SHA 序 背景 正文 SHA-1 与 MD5 的比较 代码实现 结束语 序 上一篇文章中介绍了基本的单向加密算法 — — MD5,也大致的说了说它实现的原理.这篇文章继续 ...

随机推荐

  1. 使用SharedPreferences存储用户配置信息

    用SharedPreferences来保存用户的基本配置信息非常的方便,实现起来也很容易:以下是一个简单的例子: 效果截图:    主要代码: public class MainActivity ex ...

  2. idea2015的使用心得

    今天打开myeclipse感觉里面全是project,也懒着换地方了,因为这些代码还要时常看,索性安装了idea试试水,感觉还不错,用起来并不比myeclipse差,跟webstorm差不多,他俩就是 ...

  3. MySQL一个简单的存储过程demo

    使用的工具是Navicat for MySQL. 首先创建一个学生表 mysql) ) ) auto_increment,age ) ) not null,primary key(s_no)); Qu ...

  4. Hbuilder开发移动App(1)

    奇妙的前端,奇妙的js 众所周知,自从js有nodejs后,前端人员可以华丽的转身,去开发高并发非阻塞的服务端程序, 随着html5的出现,伴随一些amazing的特性,h5开发app的技术越发的成熟 ...

  5. 初学 Java Script (数据类型)

    简介:JavaScript是一种属于网络的脚本语言,已经被广泛用于Web应用开发,常用来为网页添加各式各样的动态功能,为用户提供更流畅美观的浏览效果.Javascript脚本语言同其他语言一样,有它自 ...

  6. Unity 相机的聚焦功能

    摘要:本文原创,转载请注明出处 需求: 在游戏的任务编辑场景进行编辑的时候,摄像机需要在多个需要编辑的物体之间来回切换,如果只是用摄像机的移动旋转,对于相对位置较近的物体还好说,当相对位置过远的时候, ...

  7. 【转载】 stm32之PWM

    发现这位博主的博客被大量的转发,我也转载一篇,谁叫人家写的好呢. 原文地址:http://blog.sina.com.cn/s/blog_49cb42490100s6uh.html 脉冲宽度调制(PW ...

  8. 【Windows 10 应用开发】输入模拟

    ---恢复内容开始--- Input Injection 直译为:输入注入.通俗的译法为:模拟输入.此注入行为可以模拟以下几种输入行为: 1.键盘按键. 2.鼠标. 3.触控. 4.书写笔输入. 5. ...

  9. JS比较思维模型

    在这里,要分享的JS中两种思维方式: 1)面向对象风格示例: function Foo(who){ this.me = who; } Foo.prototype.identify = function ...

  10. SELECT中的多表连接

    MySQL多表连接查询 连接(join):将一张表中的行按照某个条件(连接条件)和另一张表中的行连接起来形成一个新行的过程. 根据连接查询返回的结果,分3类: 内连接(inner join) 外连接( ...