
RSA (Rivest–Shamir–Adleman)是一种公钥加密算法,用于数据的加密和解密,以及数字签名和密钥协商。Java 提供了许多内置的类和方法来实现 RSA 算法。下面是一个详细的步骤指南,以及一些代码示例。
1 生成密钥对
首先,需要生成一对公钥和私钥,以便用于加密和解密数据。Java 提供了一个 KeyPairGenerator 类来生成密钥对。以下代码生成了一个 RSA 密钥对:
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048); // key length
KeyPair keyPair = keyPairGenerator.generateKeyPair();
2 加密数据
使用公钥对数据进行加密。以下是一个示例:
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import javax.crypto.Cipher;
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
String plainText = "Hello, World!";
byte[] encryptedText = cipher.doFinal(plainText.getBytes());
3 解密数据
使用私钥对数据进行解密。以下是一个示例:
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import javax.crypto.Cipher;
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedText = cipher.doFinal(encryptedText);
String plainText = new String(decryptedText);
4 数字签名
RSA 还可用于数字签名。数字签名可确保数据的完整性和真实性。以下是一个示例:
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
byte[] message = "Hello, World!".getBytes();
signature.update(message);
byte[] signatureBytes = signature.sign();
signature.initVerify(publicKey);
signature.update(message);
boolean isVerified = signature.verify(signatureBytes);
以上是几个简单的使用 RSA 的示例。在实际应用中,可能还需要处理密钥存储、密钥交换、加密模式等其他问题,下面简单描述一下。
1 密钥存储
在实际应用中,生成的公钥和私钥需要被安全地存储。通常情况下,应该将私钥保存在一个受保护的地方,只允许受信任的用户访问。公钥可以安全地公开,供任何人使用。
Java 提供了一些 API 来处理密钥存储。例如,可以使用 KeyStore 类来保存和管理密钥。以下是一个示例:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
// create keystore
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(null, null);
keyStore.setKeyEntry("mykey", privateKey, "password".toCharArray(), new Key[]{publicKey});
// save keystore to file
FileOutputStream fos = new FileOutputStream(new File("mykeystore.jks"));
keyStore.store(fos, "password".toCharArray());
fos.close();
// load keystore from file
FileInputStream fis = new FileInputStream(new File("mykeystore.jks"));
keyStore.load(fis, "password".toCharArray());
fis.close();
// get private key from keystore
PrivateKey loadedPrivateKey = (PrivateKey) keyStore.getKey("mykey", "password".toCharArray());
2 密钥交换
在使用 RSA 进行通信时,需要将密钥交换给对方。一种常见的方法是使用 Diffie-Hellman 密钥交换协议。在这种协议中,两方通过一系列的步骤交换信息,最终得到一个共享密钥,该密钥可用于加密和解密数据。
Java 提供了一个 KeyAgreement 类来实现 Diffie-Hellman 密钥交换。以下是一个示例:
import java.security.AlgorithmParameterGenerator;
import java.security.AlgorithmParameters;
import java.security.Key;
import java.security.KeyAgreement;
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.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
// Alice generates a public-private key pair
KeyPairGenerator aliceKeyPairGenerator = KeyPairGenerator.getInstance("DiffieHellman");
aliceKeyPairGenerator.initialize(2048);
KeyPair aliceKeyPair = aliceKeyPairGenerator.generateKeyPair();
PublicKey alicePublicKey = aliceKeyPair.getPublic();
PrivateKey alicePrivateKey = aliceKeyPair.getPrivate();
// Bob generates a public-private key pair
KeyPairGenerator bobKeyPairGenerator = KeyPairGenerator.getInstance("DiffieHellman");
bobKeyPairGenerator.initialize(2048);
KeyPair bobKeyPair = bobKeyPairGenerator.generateKeyPair();
PublicKey bobPublicKey = bobKeyPair.getPublic();
PrivateKey
PrivateKey bobPrivateKey = bobKeyPair.getPrivate();
// Alice sends her public key to Bob
byte[] alicePubKeyBytes = alicePublicKey.getEncoded();
// Bob receives Alice's public key
X509EncodedKeySpec alicePubKeySpec = new X509EncodedKeySpec(alicePubKeyBytes);
KeyFactory bobKeyFactory = KeyFactory.getInstance("DiffieHellman");
PublicKey alicePubKey = bobKeyFactory.generatePublic(alicePubKeySpec);
// Bob generates shared secret
KeyAgreement bobKeyAgreement = KeyAgreement.getInstance("DiffieHellman");
bobKeyAgreement.init(bobPrivateKey);
bobKeyAgreement.doPhase(alicePubKey, true);
byte[] bobSharedSecret = bobKeyAgreement.generateSecret();
// Bob sends his public key to Alice
byte[] bobPubKeyBytes = bobPublicKey.getEncoded();
// Alice receives Bob's public key
X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(bobPubKeyBytes);
KeyFactory aliceKeyFactory = KeyFactory.getInstance("DiffieHellman");
PublicKey bobPubKey = aliceKeyFactory.generatePublic(bobPubKeySpec);
// Alice generates shared secret
KeyAgreement aliceKeyAgreement = KeyAgreement.getInstance("DiffieHellman");
aliceKeyAgreement.init(alicePrivateKey);
aliceKeyAgreement.doPhase(bobPubKey, true);
byte[] aliceSharedSecret = aliceKeyAgreement.generateSecret();
// verify that Alice and Bob have the same shared secret
System.out.println(Arrays.equals(aliceSharedSecret, bobSharedSecret)); // prints true
3 加密模式
在使用 RSA 进行加密时,可以使用不同的加密模式。Java 支持多种加密模式,包括 ECB、CBC、CFB 和 OFB 等。这些模式的主要区别在于加密方式不同,有些模式还提供了更好的安全性。
下面是一个使用 RSA 加密和解密数据的示例,使用 CBC 模式:
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
String plaintext = "Hello, world!";
String keyString = "mysecretkey12345";
byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
// encrypt
Cipher encryptCipher = Cipher.getInstance("RSA/CBC/PKCS5Padding");
encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey, new IvParameterSpec(iv));
byte[] ciphertext = encryptCipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
String encryptedText = Base64.getEncoder().encodeToString(ciphertext);
// decrypt
Cipher decryptCipher = Cipher.getInstance("RSA/CBC/PKCS5Padding");
decryptCipher.init(Cipher.DECRYPT_MODE, privateKey, new IvParameterSpec(iv));
byte[] decryptedBytes = decryptCipher.doFinal(Base64.getDecoder().decode(encryptedText));
String decryptedText = new String(decryptedBytes, StandardCharsets.UTF_8);
System.out.println(decryptedText); // prints "Hello, world!"
注意,使用 RSA 加密大量数据可能会比较慢,因为 RSA 的密钥长度通常比较大。因此,在实际应用中,通常会将 RSA 用于加密对称密钥,然后使用对称密钥加密实际数据,这样可以提高加密速度。