抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

1977年,三位数学家Rivest、Shamir 和 Adleman 设计了一种算法,可以实现非对称加密。这种算法用他们三个人的名字命名,叫做RSA算法。从那时直到现在,RSA算法一直是最广为使用的”非对称加密算法”。毫不夸张地说,只要有计算机网络的地方,就有RSA算法。

一、概念

非对称加密有公钥和私钥两个概念,私钥自己拥有,不能给别人,公钥公开。根据应用的不同,我们可以选择使用不同的密钥加密:

  • 签名:使用私钥加密,公钥解密。用于让所有公钥所有者验证私钥所有者的身份并且用来防止私钥所有者发布的内容被篡改,但是不用来保证内容不被他人获得。
  • 加密:用公钥加密,私钥解密。用于向公钥所有者发布信息,这个信息可能被他人篡改,但是无法被他人获得。

这种算法非常可靠,密钥越长,它就越难破解。根据已经披露的文献,目前被破解的最长RSA密钥是768个二进制位。也就是说,长度超过768位的密钥,还无法破解(至少没人公开宣布)。因此可以认为,1024位的RSA密钥基本安全,2048位的密钥极其安全。

二、使用

本文基于jdk8实现RSA加密封装(源码在文末),以及解决因长度问题的加解密报错。

1. 实例化

RSA rsa = new RSA();
//RSA rsa = new RSA(publicKey,privateKey);
//RSA rsa = new RSA(publicKey,null);  可以只传入某一个密钥,例如传入公钥,只使用公钥的加解密方法

2. 获取公私钥

RSA rsa = new RSA();
System.out.println(rsa.getPublicKey());
System.out.println(rsa.getPrivateKey());

3. 公钥加密、私钥解密

RSA rsa = new RSA();
String secret = rsa.publicEncrypt("im am seepine");
System.out.println(secret);
System.out.println(rsa.privateDecrypt(secret));

4. 私钥加密、公钥解密

RSA rsa = new RSA();
String secret = rsa.privateEncrypt("im am seepine");
System.out.println(secret);
System.out.println(rsa.publicDecrypt(secret));

三、JAVA源码

源码基于jdk8

1.RSA.java

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * RSA加解密封装
 *
 * @author seepine
 */
public class RSA {
  private static final Base64.Encoder base64Encoder = Base64.getEncoder();
  private static final Base64.Decoder base64Decoder = Base64.getDecoder();

  private static final String RSA = "RSA";

  String publicKeyBase64;
  String privateKeyBase64;

  Cipher publicEncodeCipher;
  Cipher publicDecodeCipher;

  Cipher privateEncodeCipher;
  Cipher privateDecodeCipher;

  int PRIVATE_DECODE_BLOCK_SIZE;
  int PRIVATE_ENCODE_BLOCK_SIZE;
  int PUBLIC_DECODE_BLOCK_SIZE;
  int PUBLIC_ENCODE_BLOCK_SIZE;

  public RSA() {
    genKeyPair();
  }

  public RSA(String publicKey, String privateKey) {
    this.publicKeyBase64 = publicKey;
    this.privateKeyBase64 = privateKey;
    initKey();
  }

  /**
   * 获取公钥base64
   *
   * @return 返回公钥base64
   */
  public String getPublicKey() {
    return this.publicKeyBase64;
  }

  /**
   * 获取私钥base64
   *
   * @return 返回私钥base64
   */
  public String getPrivateKey() {
    return this.privateKeyBase64;
  }

  /** 生成公私密钥 */
  private void genKeyPair() {
    try {
      KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(RSA);
      keyPairGen.initialize(2048, new SecureRandom());
      KeyPair keyPair = keyPairGen.generateKeyPair();
      RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
      RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
      publicKeyBase64 = base64Encoder.encodeToString(publicKey.getEncoded());
      privateKeyBase64 = base64Encoder.encodeToString((privateKey.getEncoded()));
      initCipher(publicKey, privateKey);
    } catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
    }
  }

  private void initKey() {
    try {
      RSAPublicKey publicKey = null;
      RSAPrivateKey privateKey = null;
      if (publicKeyBase64 != null) {
        publicKey =
            (RSAPublicKey)
                KeyFactory.getInstance(RSA)
                    .generatePublic(new X509EncodedKeySpec(base64Decoder.decode(publicKeyBase64)));
      }
      if (privateKeyBase64 != null) {
        privateKey =
            (RSAPrivateKey)
                KeyFactory.getInstance("RSA")
                    .generatePrivate(
                        new PKCS8EncodedKeySpec(base64Decoder.decode(privateKeyBase64)));
      }
      initCipher(publicKey, privateKey);
    } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
      e.printStackTrace();
    }
  }
  /** 初始化公私钥Cipher */
  private void initCipher(RSAPublicKey publicKey, RSAPrivateKey privateKey) {
    try {
      if (privateKey != null) {
        PRIVATE_DECODE_BLOCK_SIZE = privateKey.getModulus().bitLength() / 8;
        PRIVATE_ENCODE_BLOCK_SIZE = PRIVATE_DECODE_BLOCK_SIZE - 11;
        privateEncodeCipher = getCipher(Cipher.ENCRYPT_MODE, privateKey);
        privateDecodeCipher = getCipher(Cipher.DECRYPT_MODE, privateKey);
      }
      if (publicKey != null) {
        PUBLIC_DECODE_BLOCK_SIZE = publicKey.getModulus().bitLength() / 8;
        PUBLIC_ENCODE_BLOCK_SIZE = PUBLIC_DECODE_BLOCK_SIZE - 11;
        publicEncodeCipher = getCipher(Cipher.ENCRYPT_MODE, publicKey);
        publicDecodeCipher = getCipher(Cipher.DECRYPT_MODE, publicKey);
      }
    } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException e) {
      e.printStackTrace();
    }
  }

  public Cipher getCipher(int var1, Key key)
      throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException {
    Cipher cipher = Cipher.getInstance(RSA);
    cipher.init(var1, key);
    return cipher;
  }
  /**
   * 私钥加密
   *
   * @param origin 明文
   * @return 密文
   * @throws RSAException 异常信息
   */
  public String privateEncrypt(String origin) throws RSAException {
    return encodeDoFinal(origin, privateEncodeCipher, PRIVATE_ENCODE_BLOCK_SIZE);
  }
  /**
   * 私钥解密
   *
   * @param secret 密文
   * @return 明文
   * @throws RSAException 异常信息
   */
  public String privateDecrypt(String secret) throws RSAException {
    return decodeDoFinal(secret, privateDecodeCipher, PRIVATE_DECODE_BLOCK_SIZE);
  }

  /**
   * 公钥加密
   *
   * @param origin 明文
   * @return 密文
   * @throws RSAException 异常信息
   */
  public String publicEncrypt(String origin) throws RSAException {
    return encodeDoFinal(origin, publicEncodeCipher, PUBLIC_ENCODE_BLOCK_SIZE);
  }
  /**
   * 公钥解密
   *
   * @param secret 密文
   * @return 明文
   * @throws RSAException 异常信息
   */
  public String publicDecrypt(String secret) throws RSAException {
    return decodeDoFinal(secret, publicDecodeCipher, PUBLIC_DECODE_BLOCK_SIZE);
  }

  private static String encodeDoFinal(String str, Cipher cipher, int maxBlock) throws RSAException {
    if (str == null) {
      throw new RSAException("加密对象不能为空");
    }
    return base64Encoder.encodeToString(
        divisionDoFinal(str.getBytes(StandardCharsets.UTF_8), cipher, maxBlock));
  }

  private static String decodeDoFinal(String str, Cipher cipher, int maxBlock) throws RSAException {
    if (str == null) {
      throw new RSAException("解密对象不能为空");
    }
    return new String(
        divisionDoFinal(
            base64Decoder.decode(str.getBytes(StandardCharsets.UTF_8)), cipher, maxBlock),
        StandardCharsets.UTF_8);
  }

  private static byte[] divisionDoFinal(byte[] inputArray, Cipher cipher, int maxBlock)
      throws RSAException {
    try {
      if (cipher == null) {
        throw new RSAException("公钥或私钥为空时,不能使用其进行加解密");
      }
      int inputLength = inputArray.length;
      int offSet = 0;
      final ByteArrayOutputStream out = new ByteArrayOutputStream();
      while (inputLength - offSet > 0) {
        if (inputLength - offSet > maxBlock) {
          out.write(cipher.doFinal(inputArray, offSet, maxBlock));
          offSet += maxBlock;
        } else {
          out.write(cipher.doFinal(inputArray, offSet, inputLength - offSet));
          offSet = inputLength;
        }
      }
      return out.toByteArray();
    } catch (IllegalBlockSizeException | BadPaddingException | IOException e) {
      e.printStackTrace();
      throw new RSAException(e.getMessage());
    }
  }
}

2.RSAException.java

/** @author seepine */
public class RSAException extends Exception {

  public RSAException(String message) {
    super(message);
  }

  @Override
  public String getMessage() {
    return super.getMessage();
  }
}

评论