Summer Blog

Java中使用Rsa

什么RSA

RSA是非对称加密的一种方式,对极大数做因数分解的复杂性决定了其安全性。RSA有一对密钥,公钥和私钥。公钥是公开的用于加密,私钥是用户需要保护的用于解密。

计算过程

  1. 选择两个不相等的质数p q
  2. 计算乘积n
    • n的二进制表示的长度就是密钥的长度
    • 最大(公布的)可破解的RSA密钥长度是768位
  3. 计算欧拉函数
    • φ(n) = (p-1)(q-1)
  4. 选择一个随机整数e
    • 1 < e < φ(n)
    • eφ(n)互质
  5. 计算e对于φ(n)模反元素d
    • d使得edφ(n)除余1,即ed ≡ 1 (mod φ(n))
    • d实际就是求二元一次方程的解ed + φ(n)k = 1
  6. ne封装成公钥,将nd封装成私钥

至此,所有需要的参数都已求得

破解

由于公钥是暴露的,所以ne是公开的,如果d暴露则会引起安全问题。由上面的计算过程可以看出

d -> ed + φ(n)k = 1
φ(n) -> (p-1)(q-1)
p,q -> n=qp

所以,只要n能被分解因数,则RSA算法就被破解了。(期待量子计算机ing)

加密

解密

Java实现

import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

public class RsaTest {

  private static final String ALGORITHM = "RSA";

  public static void main(String[] args)
      throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {

    KeyPairGenerator generator = KeyPairGenerator.getInstance(ALGORITHM);
    generator.initialize(1024); // 初始化长度

    KeyPair keyPair = generator.generateKeyPair();

    PrivateKey privateKey = keyPair.getPrivate();
    String privateKeyStr = Base64.getEncoder().encodeToString(privateKey.getEncoded());

    PublicKey publicKey = keyPair.getPublic();
    String publicKeyStr = Base64.getEncoder().encodeToString(publicKey.getEncoded());

    // 输出
    System.out.println(privateKeyStr);
    System.out.println(publicKeyStr);

    // 由字符串变回KeyPair
    KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
    PublicKey publicKey1 = keyFactory.generatePublic(
        new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyStr.getBytes())));
    PrivateKey privateKey1 = keyFactory.generatePrivate(
        new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyStr.getBytes())));

    System.out.println(publicKey1.equals(publicKey)); // 返回true
    System.out.println(privateKey1.equals(privateKey));

    String msg = "123xx";
    // 加密
    Cipher cipher = Cipher.getInstance(ALGORITHM);
    cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    byte[] code = cipher.doFinal(msg.getBytes());

    // 解密
    cipher.init(Cipher.PRIVATE_KEY, privateKey);
    String msg1 = new String(cipher.doFinal(code));

    System.out.println(msg.equals(msg1));
  }
}

comments powered by Disqus