Java加解密技术系列之RSA详解_java

距离上一次写博客感觉已经很长时间了,先吐槽一下,这个月以来,公司一直在加班,又是发版、上线,又是新项目太紧,具体的就不多说了。今天来说说非对称加密真的是太重要了,我们的日常生活中,都离不开非对称加密。

概念

在说 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);
  }
}

加解密结果

结束语

其实,看似很复杂的过程,用一句话就可以描述:使用公钥加密、私钥解密,完成了乙方到甲方的一次数据传递,通过私钥加密、公钥解密,同时通过私钥签名、公钥验证签名,完成了一次甲方到乙方的数据传递与验证,两次数据传递完成一整套的数据交互。

非对称加密算法的出现,就是为了解决只有一把密钥的加解密,只要这一把密钥丢失或者被公开,那么加密数据就很容易被攻击。同时,也正是由于非对称加密算法的出现,才有了后面的数字签名、数字证书等等。

好了,今天就到这吧,下一篇继续非对称加密,至于哪一种,到时候就知道了,这里先保密

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索java
, rsa加密解密
, java
, rsa加密解密算法
rsa加密解密实现
java rsa 解密、java rsa加密解密算法、java rsa分段加密解密、java rsa 加密解密、java rsa加密解密实现,以便于您获取更多的相关知识。

时间: 2025-01-19 14:59:32

Java加解密技术系列之RSA详解_java的相关文章

Java I/O技术之文件操作详解_java

在java程序设计中,I/O操作是通过java.io包中的类和接口来实现的,因此,我们第一步要做的就是import这个包. java.io提供了一个File类,这是类很容易让人产生误会,它表示的是一个文件名或者目录名,而不是文件本身,所以通过这个类没法对文件里面的数据进行操作.File类提供了一序列对文件操作的功能:删除文件,创建目录,查询文件大小等等.要想对文件数据进行操作那就需要流对象了,在这里就暂时不做介绍. 下面通过一个叫做FileExtension类来对File类中的各种操作进行封装,

Java太阳系小游戏分析和源码详解_java

最近看了面向对象的一些知识,然后跟着老师的讲解做了一个太阳系各行星绕太阳转的小游戏,来练习巩固一下最近学的知识: 用到知识点:类的继承.方法的重载与重写.多态.封装等 分析: 1.需要加载图片.画图 2.建一个面板,主页面 3.行星类 效果图: 先看一下源码结构图: 现在逐步分析各个类的功能: 1)工具类-----util包中     --Constant类   封装了游戏中用到的常量     --GameUtil类  封装了游戏的图片加载功能     --MyFrame类  封装了游戏面板的构

JAVA中static方法的用法实例详解_java

本文实例讲述了JAVA中static方法的用法.分享给大家供大家参考,具体如下: static表示"全局"或者"静态"的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,但是Java语言中没有全局变量的概念. 被static修饰的成员变量和成员方法独立于该类的任何对象.也就是说,它不依赖类特定的实例,被类的所有实例共享.只要这个类被加载,Java虚拟机就能根据类名在运行时数据区或者方法区内找到他们.因此,static对象可以在它的任何对象创建之前访

Java的JSON处理器fastjson使用方法详解_java

fastjson 是一个性能很好的 Java 语言实现的 JSON 解析器和生成器,来自阿里巴巴的工程师开发. 主要特点: • 快速FAST (比其它任何基于Java的解析器和生成器更快,包括jackson) • 强大(支持普通JDK类包括任意Java Bean Class.Collection.Map.Date或enum) • 零依赖(没有依赖其它任何类库除了JDK) 示例代码: import com.alibaba.fastjson.JSON; Group group = new Group

java中哈希表及其应用详解_java

哈希表也称为散列表,是用来存储群体对象的集合类结构. 什么是哈希表 数组和向量都可以存储对象,但对象的存储位置是随机的,也就是说对象本身与其存储位置之间没有必然的联系.当要查找一个对象时,只能以某种顺序(如顺序查找或二分查找)与各个元素进行比较,当数组或向量中的元素数量很多时,查找的效率会明显的降低. 一种有效的存储方式,是不与其他元素进行比较,一次存取便能得到所需要的记录.这就需要在对象的存储位置和对象的关键属性(设为 k)之间建立一个特定的对应关系(设为 f),使每个对象与一个唯一的存储位置

Java 8 新特性终极版指南详解_java

前言: Java 8已经公布有一段时间了,种种迹象表明Java 8是一个有重大改变的发行版.在Java Code Geeks上已经有很多介绍Java 8新特性的文章,例如Playing with Java 8 – Lambdas and Concurrency.Java 8 Date Time API Tutorial : LocalDateTime和Abstract Class Versus Interface in the JDK 8 Era.本文还参考了一些其他资料,例如:15 Must

JAVA中的final关键字用法实例详解_java

本文实例讲述了JAVA中的final关键字用法.分享给大家供大家参考,具体如下: 根据上下文环境,java的关键字final也存在着细微的区别,但通常指的是"这是无法改变的."不想改变的理由有两种:一种是效率,另一种是设计.由于两个原因相差很远,所以关键子final可能被误用. 接下来介绍一下使用到final的三中情况:数据,方法,类 final数据 许多编程语言都有某种方法,来向编译器告知一块数据是恒定不变的.有时数据的恒定不变是很有用的,例如: 1. 一个编译时恒定不变的常量 2.

Java+MyBatis+MySQL开发环境搭建流程详解_java

主要搭建过程 1. pom.xml文件中加入mybatis和数据库依赖,这里使用mysql: <properties> <mybatis.version>3.2.3</mybatis.version> <mysql.version>5.1.26</mysql.version> <slf4j.api.version>1.7.5</slf4j.api.version> <testng.version>6.8.7&l

java提高篇(二三)-----HashMap详解_java

HashMap也是我们使用非常多的Collection,它是基于哈希表的 Map 接口的实现,以key-value的形式存在.在HashMap中,key-value总是会当做一个整体来处理,系统会根据hash算法来来计算key-value的存储位置,我们总是可以通过key快速地存.取value.下面就来分析HashMap的存取. 一.定义 HashMap实现了Map接口,继承AbstractMap.其中Map接口定义了键映射到值的规则,而AbstractMap类提供 Map 接口的骨干实现,以最