Java加解密技术系列之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);
  }
}

加解密结果

结束语

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

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

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

(0)

相关推荐

  • java实现MD5加密算法的实例代码

    复制代码 代码如下: package other; import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;/* * MD5 算法*/public class MD5 { // 全局数组    private final static String[] strDigits = { "0", "1", "2", "3", &

  • java不可逆加密算法之md5加密算法使用示例

    MD5的全称是Message-Digest Algorithm 5,Message-Digest泛指字节串(Message)的Hash变换,就是把一个任意长度的字节串变换成一定长的大整数.MD5将任意长度的"字节串"变换成一个128bit的大整数,并且它是一个不可逆的字符串变换算法,换句话说就是,即使你看到源程序和算法描述,也无法将一个MD5的值变换回原始的字符串,从数学原理上说,是因为原始的字符串有无穷多个,这有点象不存在反函数的数学函数. 复制代码 代码如下: import jav

  • java加密算法分享(rsa解密、对称加密、md5加密)

    复制代码 代码如下: import java.io.UnsupportedEncodingException;import java.security.InvalidKeyException;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.security.PrivateKey;import java.security.PublicKey;import jav

  • java开发之MD5加密算法的实现

    先看看代码再说: 复制代码 代码如下: package com.b510.note; import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /**  * MD5加密  *   * @author Hongten  *   */ public class MD5 { public static void main(String[]

  • Java OpenSSL生成的RSA公私钥进行数据加解密详细介绍

    Java中使用OpenSSL生成的RSA公私钥进行数据加解密 RSA是什么:RSA公钥加密算法是1977年由Ron Rivest.Adi Shamirh和LenAdleman在(美国麻省理工学院)开发的.RSA取名来自开发他们三者的名字.RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的所有密码攻击,已被ISO推荐为公钥数据加密标准.目前该加密方式广泛用于网上银行.数字签名等场合.RSA算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但那时想要对其乘积进行因式分解却极其困

  • java实现的RSA加密算法详解

    本文实例讲述了java实现的RSA加密算法.分享给大家供大家参考,具体如下: 一.什么是非对称加密 1.加密的密钥与加密的密钥不相同,这样的加密算法称之为非对称加密 2.密钥分为:公钥,私钥 公钥:可以对外给任何人的加密和解密的密码,是公开的 私钥:通过私钥可以生成公钥,但从公钥被认为无法生成公钥(被推导出的概率小到不考虑) 3.当将要加密的内容用公钥加密的时候,只能用私钥来解密 当将要加密的内容用私钥加密的时候,只能用公钥来解密 4.公钥与私钥的关系,利用一个简单的公式来生成公钥和私钥,即非对

  • JAVA加密算法- 非对称加密算法(DH,RSA)的详细介绍

    非对称密码概念 1.与对称加密算法的主要差别在于,加密和解密的密钥不相同,一个公开(公钥),一个保密(私钥).主要解决了对称加密算法密钥分配管理的问题,提高了算法安全性. 2.非对称加密算法的加密.解密的效率比较低.在算法设计上,非对称加密算法对待加密的数据长度有着苛刻的要求.例如RSA算法要求待加密的数据不得大于53个字节. 3.非对称加密算法主要用于 交换对称加密算法的密钥,而非数据交换 4.java6提供实现了DH和RSA两种算法.Bouncy Castle提供了E1Gamal算法支持.除

  • 利用JAVA实现DES加密算法

    DES加密介绍DES是一种对称加密算法,所谓对称加密算法即:加密和解密使用相同密钥的算法.DES加密算法出自IBM的研究,后来被美国政府正式采用,之后开始广泛流传,但是近些年使用越来越少,因为DES使用56位密钥,以现代计算能力,24小时内即可被破解.虽然如此,在某些简单应用中,我们还是可以使用DES加密算法,本文简单讲解DES的JAVA实现. JAVA实现加密代码有详细解释,不多废话.注意:DES加密和解密过程中,密钥长度都必须是8的倍数 复制代码 代码如下: public byte[] de

  • Java实现AES加密算法的简单示例分享

    高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准.这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用. 大多数AES计算是在一个特别的有限域完成的. AES加密过程是在一个4×4的字节矩阵上运作,这个矩阵又称为"状态(state)",其初值就是一个明文区块(矩阵中一个元素大小就是明文区块中的一个Byte).(Rijndael加密法因支持更大的区块,其矩阵行

  • RSA加密算法java简单实现方法(必看)

    简单完整的代码,通过这个代码你将对RSA加密算法在Java中的实现方法有一个初步的了解,这个类,你可以直接使用,水平高的,就自己修改完善下代码. package security; import java.security.*; import java.security.spec.*; import java.security.interfaces.*; import javax.crypto.spec.*; import javax.crypto.interfaces.*; import ja

  • 使用java自带des加密算法实现文件加密和字符串加密

    复制代码 代码如下: import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.InputStream;import java.io.OutputStream;import java.security.SecureR

随机推荐