Skip to content

非对称加密算法

非对称密码算法,也称为公开密钥加密或公钥加密技术。

非对称加密算法分类

主要包括以下几种分类:

  1. RSA算法:
    • RSA算法是目前最广泛使用的非对称加密算法之一。
    • 其安全性主要基于大质数分解难题。
    • 公钥由两个参数组成:模数n和公钥指数e;私钥由模数n和私钥指数d组成。
    • RSA算法的安全性取决于密钥长度,一般需要使用较长的密钥长度以保证安全性。
  2. 椭圆曲线密码算法(ECC):
    • ECC是一种基于椭圆曲线数学理论的非对称加密算法。
    • 与RSA算法相比,ECC算法使用的密钥长度更短,但其安全性仍然很高。
    • ECC算法的安全性取决于选择的椭圆曲线,需要仔细选择和设计。
    • ECC算法特别适用于资源受限的移动设备。
  3. ElGamal算法:
    • ElGamal算法是一种基于离散对数问题的非对称加密算法。
    • 其公钥由两个参数组成:素数p和本原根α;私钥由一个整数x组成。
    • ElGamal算法的安全性也取决于密钥长度,一般需要使用较长的密钥长度以保证安全性。
  4. Diffie-Hellman算法:
    • 该算法主要用于密钥交换,允许两个用户在公开通道上创建一个共享的秘密密钥。
    • 虽然它本身不直接用于加密或解密数据,但它是许多非对称加密算法中的关键组成部分。
  5. 其他算法:
    • 还包括背包算法、Rabin、McEliece密码、零知识证明等非对称加密算法。

这些非对称加密算法各有特点和优势,适用于不同的应用场景。在选择加密算法时,需要综合考虑安全性、效率、可扩展性等因素。例如,在需要高安全性的场合可以选择RSA算法,而在资源受限的移动设备上可以选择ECC算法。

RSA算法

JAVA读取private、public key文件

JAVA RSA用法

JAVA RSA 签名校验用法

公钥和私钥的生成和使用

openSSL生成私钥,注意:这个钥匙不能用于作为应用的privateKey,需要使用下面的pkcs8格式作为privateKey

bash
openssl genrsa -out private.pem 1024

openSSL生成公钥

bash
openssl rsa -in private.pem -outform PEM -pubout -out public.pem

openSSL转换公钥PEM到PKCS8格式,注意:这个钥匙作为privateKey

参考链接

bash
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in private.pem -out private.pem.pkcs8

注意:使用公钥和密钥时,只需要复制除-----xxx-----外的内容即可,否则java在解析钥匙时报告错误。

加密和解密

示例详细用法请参考 链接

示例代码:

java
@Test
public void testEncryptDecrypt() throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
    String plainText = RandomStringUtils.random(16);

    String algorithm = "RSA";
    String plainSecretKey = RandomStringUtils.random(2048);
    int keySize = 512;

    // 生成秘钥对
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
    keyPairGenerator.initialize(keySize, new SecureRandom(plainSecretKey.getBytes()));
    KeyPair keyPair = keyPairGenerator.generateKeyPair();
    byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();
    byte[] publicKeyBytes = keyPair.getPublic().getEncoded();

    // 私钥加密,公钥解密
    KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
    // PKCS#8标准中定义的一个结构,用于表示私钥信息。它包含一个版本字段、一个私钥算法标识符、一个私钥字段以及一个可选的属性字段。这个结构允许私钥以独立于公钥或证书的格式进行存储和传输
    PrivateKey privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));
    Cipher cipher = Cipher.getInstance(algorithm);
    cipher.init(Cipher.ENCRYPT_MODE, privateKey);
    byte[] encryptBytes = cipher.doFinal(plainText.getBytes());

    keyFactory = KeyFactory.getInstance(algorithm);
    // 于将X.509证书中的公钥转换为Java的公钥对象
    PublicKey publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyBytes));
    cipher = Cipher.getInstance(algorithm);
    cipher.init(Cipher.DECRYPT_MODE, publicKey);
    byte[] decryptBytes = cipher.doFinal(encryptBytes);
    String plainTextDecrypt = new String(decryptBytes);
    Assert.assertEquals(plainText, plainTextDecrypt);

    // 公钥加密,私钥解密
    keyFactory = KeyFactory.getInstance(algorithm);
    publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyBytes));
    cipher = Cipher.getInstance(algorithm);
    cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    encryptBytes = cipher.doFinal(plainText.getBytes());

    keyFactory = KeyFactory.getInstance(algorithm);
    privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));
    cipher = Cipher.getInstance(algorithm);
    cipher.init(Cipher.DECRYPT_MODE, privateKey);
    decryptBytes = cipher.doFinal(encryptBytes);
    plainTextDecrypt = new String(decryptBytes);
    Assert.assertEquals(plainText, plainTextDecrypt);
}

读取公钥和私钥密钥对进行加密和解密

示例详细用法请参考 链接

参考上面的公钥和私钥的生成和使用生成密钥对

示例代码:

java
@Test
public void testOpenSSLKeyPair() throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
    String publicKeyString = System.getenv("publicKey");
    String privateKeyString = System.getenv("privateKey");

    String plainText = RandomStringUtils.random(16);

    String algorithm = "RSA";

    byte[] privateKeyBytes = Base64.decode(privateKeyString);
    byte[] publicKeyBytes = Base64.decode(publicKeyString);

    // 私钥加密,公钥解密
    KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
    PrivateKey privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));
    Cipher cipher = Cipher.getInstance(algorithm);
    cipher.init(Cipher.ENCRYPT_MODE, privateKey);
    byte[] encryptBytes = cipher.doFinal(plainText.getBytes());

    keyFactory = KeyFactory.getInstance(algorithm);
    PublicKey publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyBytes));
    cipher = Cipher.getInstance(algorithm);
    cipher.init(Cipher.DECRYPT_MODE, publicKey);
    byte[] decryptBytes = cipher.doFinal(encryptBytes);
    String plainTextDecrypt = new String(decryptBytes);
    Assert.assertEquals(plainText, plainTextDecrypt);

    // 公钥加密,私钥解密
    keyFactory = KeyFactory.getInstance(algorithm);
    publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyBytes));
    cipher = Cipher.getInstance(algorithm);
    cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    encryptBytes = cipher.doFinal(plainText.getBytes());

    keyFactory = KeyFactory.getInstance(algorithm);
    privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));
    cipher = Cipher.getInstance(algorithm);
    cipher.init(Cipher.DECRYPT_MODE, privateKey);
    decryptBytes = cipher.doFinal(encryptBytes);
    plainTextDecrypt = new String(decryptBytes);
    Assert.assertEquals(plainText, plainTextDecrypt);
}

数字签名和验签

示例详细用法请参考 链接

参考上面的公钥和私钥的生成和使用生成密钥对

示例代码:

java
@Test
public void testDigitalSignAndVerify() throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
    String publicKeyString = System.getenv("publicKey");
    String privateKeyString = System.getenv("privateKey");

    String plainText = RandomStringUtils.random(16);

    byte[] privateKeyBytes = Base64.decode(privateKeyString);
    byte[] publicKeyBytes = Base64.decode(publicKeyString);

    // 签名
    PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(privateKeyBytes);
    KeyFactory keyf = KeyFactory.getInstance("RSA");
    PrivateKey priKey = keyf.generatePrivate(priPKCS8);
    java.security.Signature signature = java.security.Signature.getInstance("SHA256WithRSA");
    signature.initSign(priKey);
    signature.update(plainText.getBytes());
    byte[] signed = signature.sign();
    String contentSigned = Base64.encode(signed);

    // 签名验证
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyBytes));
    signature = java.security.Signature.getInstance("SHA256WithRSA");
    signature.initVerify(pubKey);
    // 使用公钥验证数字签名是否是对应的密钥签发的
    signature.update(plainText.getBytes());
    boolean bverify = signature.verify(Base64.decode(contentSigned));
    Assert.assertTrue(bverify);
}