Java:实现RSA加密与验证的方法详解

1 RSA简介

RSA加密是一种非对称加密。可以在不直接传递密钥的情况下,完成解密。这能够确保信息的安全性,避免了直接传递密钥所造成的被破解的风险。是由一对密钥来进行加解密的过程,分别称为公钥和私钥。两者之间有数学相关,该加密算法的原理就是对一极大整数做因数分解的困难性来保证安全性。通常个人保存私钥,公钥是公开的(可能同时多人持有)。

主要特点如下:

  • 非对称加密: RSA是一种非对称加密算法,意味着它使用不同的密钥进行加密和解密。公钥用于加密数据,只有拥有相应私钥的用户才能解密它。这种非对称性使得RSA在安全通信中非常有用,因为公钥可以公开分享,而私钥必须保密。
  • 数字签名和验证: RSA还可以用于数字签名和验证。发送方可以使用其私钥对消息进行签名,接收方可以使用发送方的公钥来验证签名。这确保了消息的完整性和来源认证。数字签名在网络安全、电子邮件认证和电子商务中广泛使用。
  • 密钥交换: RSA可用于安全地交换对称密钥。在两个通信方之间建立安全连接时,可以使用RSA加密传输对称密钥,然后使用该对称密钥进行快速的数据加密和解密。这提高了性能并确保了密钥的安全交换。
  • 安全通信: RSA可用于保护通信的机密性和完整性。通信双方可以使用对方的公钥来加密数据,以确保只有持有私钥的一方能够解密它。这在保护敏感信息传输时非常重要,例如,网上银行、电子商务和VPN连接。
  • 数字证书: RSA也与数字证书一起使用,以验证网站的身份和安全性。数字证书中包含了网站的公钥,通过验证证书的签名,用户可以确保他们正在与合法的网站通信,而不是受到中间人攻击。
  • 安全存储: RSA可以用于加密敏感数据,然后将其存储在不安全的环境中,只有持有私钥的用户才能解密和访问数据。这对于存储密码、加密钱包和数据库等敏感数据非常有用。

总的来说,RSA是一种强大且多用途的加密算法,广泛应用于网络通信、数据安全、数字签名、身份验证和加密存储等领域。然而,需要注意的是,RSA的性能较低,特别是对于长消息,因此在某些情况下,可能需要与对称加密算法结合使用,以提高性能。

2 使用场景举例

加密和签名都是为了安全性考虑,但略有不同。常有人问加密和签名是用私钥还是公钥?其实都是对加密和签名的作用有所混淆。简单的说,加密是为了防止信息被泄露,而签名是为了防止信息被篡改。这里举2个例子说明。

场景一:

战场上,B要给A传递一条消息,内容为某一指令。

RSA的加密过程如下:

  • A生成一对密钥(公钥和私钥),私钥不公开,A自己保留。公钥为公开的,任何人可以获取。
  • A传递自己的公钥给B,B用A的公钥对消息进行加密。
  • A接收到B加密的消息,利用A自己的私钥对消息进行解密。

在这个过程中,只有2次传递过程,第一次是A传递公钥给B,第二次是B传递加密消息给A,即使都被敌方截获,也没有危险性,因为只有A的私钥才能对消息进行解密,防止了消息内容的泄露。

场景二:

A收到B发的消息后,需要进行回复“收到”。

RSA签名的过程如下:

  • A生成一对密钥(公钥和私钥),私钥不公开,A自己保留。公钥为公开的,任何人可以获取。
  • A用自己的私钥对消息加签,形成签名,并将加签的消息和消息本身一起传递给B。
  • B收到消息后,在获取A的公钥进行验签,如果验签出来的内容与消息本身一致,证明消息是A回复的。

在这个过程中,只有2次传递过程,第一次是A传递加签的消息和消息本身给B,第二次是B获取A的公钥,即使都被敌方截获,也没有危险性,因为只有A的私钥才能对消息进行签名,即使知道了消息内容,也无法伪造带签名的回复给B,防止了消息内容的篡改。

但是,综合两个场景你会发现,第一个场景虽然被截获的消息没有泄露,但是可以利用截获的公钥,将假指令进行加密,然后传递给A。第二个场景虽然截获的消息不能被篡改,但是消息的内容可以利用公钥验签来获得,并不能防止泄露。所以在实际应用中,要根据情况使用,也可以同时使用加密和签名,比如A和B都有一套自己的公钥和私钥,当A要给B发送消息时,先用B的公钥对消息加密,再对加密的消息使用A的私钥加签名,达到既不泄露也不被篡改,更能保证消息的安全性。

3 代码实现

3.1 生成公私钥

要实现加密和验证,首先你需要生成一对RSA密钥对,包括公钥和私钥。你可以使用Java的KeyPairGenerator类来生成密钥对。实现代码如下:

package com.example.demo;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;

public class GenerateRSAKeys {
    public static void main(String[] args) throws Exception {
        // 创建一个RSA密钥对生成器
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        // 设置密钥长度,通常为2048位
        keyPairGenerator.initialize(2048);

        // 生成RSA密钥对
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();

        System.out.println("公钥: " + Base64.getEncoder().encodeToString(publicKey.getEncoded()));
        System.out.println("私钥: " + Base64.getEncoder().encodeToString(privateKey.getEncoded()));
    }
}

3.2 基础的公钥加密私钥解密

package com.example.demo;

import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class RSAEncryptionDecryption {
    public static void main(String[] args) throws Exception {
        String originalText = "Hello, RSA encryption and decryption!";

        // 将公钥和私钥的Base64编码字符串转换为PublicKey和PrivateKey对象
        String publicKeyBase64 = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApzRwXn03DL1Hf7rEuElyaY9UrDnB87VFoPkTj743bxkhrXmuFuuk3JkSDPBY6IGwbFwaVIHMsMiMEh4ZVq7m/dOYBlWnAzZnZk/uWxF1zUJ2C6xe92R97m/4ySOYypg9SI9sPscOyYY4rw/vGaos+uhsoyt26chFbU/BdtFzq7+843gjUzzHR/kpD61c/IeWiYoB6RFKoMgmzKlPXMGsmfrsQynUuCK+xuRj22Xf38XLjQXh+t5l1x3Q/MbixyPf0zWCrCxFDdvAy/BQwt7X5TEui//epGK+g3JC504EGcxGVkAZdwPCo9swqxQvTdVYLIR0QWPUCIFEmvaZRSvyNQIDAQAB";
        String privateKeyBase64 = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCnNHBefTcMvUd/usS4SXJpj1SsOcHztUWg+ROPvjdvGSGtea4W66TcmRIM8FjogbBsXBpUgcywyIwSHhlWrub905gGVacDNmdmT+5bEXXNQnYLrF73ZH3ub/jJI5jKmD1Ij2w+xw7JhjivD+8Zqiz66GyjK3bpyEVtT8F20XOrv7zjeCNTPMdH+SkPrVz8h5aJigHpEUqgyCbMqU9cwayZ+uxDKdS4Ir7G5GPbZd/fxcuNBeH63mXXHdD8xuLHI9/TNYKsLEUN28DL8FDC3tflMS6L/96kYr6DckLnTgQZzEZWQBl3A8Kj2zCrFC9N1VgshHRBY9QIgUSa9plFK/I1AgMBAAECggEBAJ3xkBABsgWrqqWCdJ8sahJC3ZYOvSKMYmiLwCmxYkXk9IYdAhEOqV3kjkOAqkt/bnr9ibW4IvX/iyj2G7NhZjvxK5MYR7pmIshnyt1loeSx2jZurgp9d+PLC7RcltERfBpVuMeYW2SMEHF12MNimDivYyfDQAHYN5TpmPO3KM/buRkIZsfmXp3pf/55UCAbm0x5+i4g2080dpcmaPoVEuUOhU8DJkPEy1/hyCPLDkFO8EVfaJ+3AaeIdSvLcznv93KupxwcG2FaMSIfxIajEDOp8XUfXIqL97v/CaV42qgxHXBKVo+93Yf/3TK6f8POcQvNXJ9xffQo9Do9OxXQL+UCgYEA0VbLR3qTq4ODFL61tLtHGSmGs94eCrjq2MAeWaCU8US1dc/taEmSvBVF+F0q5B0BvEM3zCbIONtZYu6m/G8PF6QgxyhnpaSayStQJljbe8jblCssPeYVWSHQZ1UCJ37zj6xaynw3HKoEQm+2BcBE2kQytoMAZ1xsC1yfJwkVHfcCgYEAzHlnKQATt4Hqo74tfcvz9ACP8QUtYHdf5oy/XG+LYyxoy/kN8k5rSw2yjNVGuz/n0Z9Uzp6EJHqsTmDTpV2SbORLes67D1zKvSmE1U4fZsjsBY8iP5YePrJHT1fyM3cdavh7kBndnCWkecw7AbNRecAl33NoZtSe+ZbL58/KVjMCgYByo+d644PPH5w/VhlIOm87NmSQSAmHsbDatotoZeprHkeJly7aN8Blw/inhM4iUkhLAzyhTnPDv0v6Q9uqzl8jgTx6FIR+T+B8Xn3sIilAZsTpJaN62m/CeiQZEpK1cm6LtcWasd+0kN74SxkRmTObnFFxZdhowlJg/n4h8HViDQKBgGUDNKtUlmj5jWkG8oJK12GbRYDUBe66Cm5i6cZIdJuxvLPHfdROWULiqWpZkm++yk8MX2ETfkRnNegifWwcJdIVlhQ9PLwCI0X/1NdrmKe2aqL0av7uslJW0FOqJsS1+5p01tYBcTFKh06ETkIwy/dRrWQOJ21lbIPwsxr51ANxAoGAHyPG/NJ73dN8uyaOlxckg7GHUKWGtQ2neEj6PGJCf/sQyByb6fGMUEKoRmbXqx/L73Muki8/ibrx5qWvrV7+jrQc7xQf14BSG/bgFiB4vua3RtrCJ14xhfsYaEzXcn+WZ8+EtD0fgPSZoWeBhKg9jmvkoaOHwjWXRWC8fHw55rw=";

        PublicKey publicKey = KeyFactory.getInstance("RSA")
                .generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyBase64)));
        PrivateKey privateKey = KeyFactory.getInstance("RSA")
                .generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyBase64)));

        // 使用公钥加密数据
        Cipher encryptCipher = Cipher.getInstance("RSA");
        encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptedBytes = encryptCipher.doFinal(originalText.getBytes());

        // 使用私钥解密数据
        Cipher decryptCipher = Cipher.getInstance("RSA");
        decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] decryptedBytes = decryptCipher.doFinal(encryptedBytes);

        String decryptedText = new String(decryptedBytes);
        System.out.println("加密后的数据: " + Base64.getEncoder().encodeToString(encryptedBytes));
        System.out.println("解密后的数据: " + decryptedText);
    }
}

结果如下:

  • 26
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不死鸟.亚历山大.狼崽子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值