# 如果我们把a看成甲的私钥,A看成甲的公钥,b看成乙的私钥,B看成乙的公钥
# DH算法的本质就是双方各自生成自己的私钥和公钥,私钥仅对自己可见,然后交换公钥,并根据自己的私钥和对方的公钥,生成最终的密钥secretKey
# DH算法通过数学定律保证了双方各自计算出的secretKey是相同的
import java.math.BigInteger;
import java.security.*;
import java.security.spec.*;
import javax.crypto.KeyAgreement;
public class Main {
public static void main(String[] args) {
// Bob和Alice:
Person bob = new Person("Bob");
Person alice = new Person("Alice");
// 各自生成KeyPair:
bob.generateKeyPair();
alice.generateKeyPair();
// 双方交换各自的PublicKey:
// Bob根据Alice的PublicKey生成自己的本地密钥:
bob.generateSecretKey(alice.publicKey.getEncoded());
// Alice根据Bob的PublicKey生成自己的本地密钥:
alice.generateSecretKey(bob.publicKey.getEncoded());
// 检查双方的本地密钥是否相同:
bob.printKeys();
alice.printKeys();
// 双方的SecretKey相同,后续通信将使用SecretKey作为密钥进行AES加解密...
}
}
class Person {
public final String name;
public PublicKey publicKey;
private PrivateKey privateKey;
private byte[] secretKey;
public Person(String name) {
this.name = name;
}
// 生成本地KeyPair:
public void generateKeyPair() {
try {
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("DH");
kpGen.initialize(512);
KeyPair kp = kpGen.generateKeyPair();
this.privateKey = kp.getPrivate();
this.publicKey = kp.getPublic();
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
}
}
public void generateSecretKey(byte[] receivedPubKeyBytes) {
try {
// 从byte[]恢复PublicKey:
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(receivedPubKeyBytes);
KeyFactory kf = KeyFactory.getInstance("DH");
PublicKey receivedPublicKey = kf.generatePublic(keySpec);
// 生成本地密钥:
KeyAgreement keyAgreement = KeyAgreement.getInstance("DH");
keyAgreement.init(this.privateKey); // 自己的PrivateKey
keyAgreement.doPhase(receivedPublicKey, true); // 对方的PublicKey
// 生成SecretKey密钥:
this.secretKey = keyAgreement.generateSecret();
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
}
}
public void printKeys() {
System.out.printf("Name: %s\n", this.name);
System.out.printf("Private key: %x\n", new BigInteger(1, this.privateKey.getEncoded()));
System.out.printf("Public key: %x\n", new BigInteger(1, this.publicKey.getEncoded()));
System.out.printf("Secret key: %x\n", new BigInteger(1, this.secretKey));
}
}
# 控制台
Name: Bob
Private key: 3081d202010030819706092a864886f70d010301308189024100fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e170240678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4020201800433023100c357c532edcd57209f23e75fd6817b7ee285275de2f5f52b2dfafaa5c312765161115251938f51f3d42404d5f72181ba
Public key: 3081df30819706092a864886f70d010301308189024100fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e170240678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca402020180034300024027bdc2d77084fbc4f7d43c561d0ddedb7f5213df9c22205da446a7f6c882979e099c3408dfc06d99bb96615dc76892d398620d0a16a7bf4e893d6a2aa58d88e3
Secret key: 6c0293377588bf404464859ccdc3daace562ae28e9f57a8b8902fe8236922db358de5c3c0d10d2aad96f82415b0d0b67d5cd3892424b7eaa627b3cc2d7bde42f
Name: Alice
Private key: 3081d202010030819706092a864886f70d010301308189024100fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e170240678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4020201800433023100b5a2be00c11885fb86f27a14b0fd6490e233bc9377706074a13b78cc5bfceb02d3187e0acb5a2b57175837032b8d4315
Public key: 3081df30819706092a864886f70d010301308189024100fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e170240678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4020201800343000240271b19a0db8ee723824a3f19d0383b0d8aaffe26e4c075b8f2a5808d4d76029d4734f1eb8979f8ae7df6163dc0bca8486a76ddef63b6b422da807970a97e9bdf
Secret key: 6c0293377588bf404464859ccdc3daace562ae28e9f57a8b8902fe8236922db358de5c3c0d10d2aad96f82415b0d0b67d5cd3892424b7eaa627b3cc2d7bde42f
# 非对称加密总是和对称加密一起使用
# 假设小明需要给小红需要传输加密文件,他俩首先交换了各自的公钥;
# 小明生成一个随机的AES口令,然后用小红的公钥通过RSA加密这个口令,并发给小红;
# 小红用自己的RSA私钥解密得到AES口令;
# 双方使用这个共享的AES口令用AES加密通信。
import java.math.BigInteger;
import java.security.*;
import javax.crypto.Cipher;
public class Main {
public static void main(String[] args) throws Exception {
// 明文:
byte[] plain = "Hello,使用RSA非对称加密算法对数据进行加密!".getBytes("UTF-8");
// 创建公钥/私钥对:
Person alice = new Person("Alice");
// 用Alice的公钥加密:
byte[] pk = alice.getPublicKey();
System.out.println(String.format("public key: %x", new BigInteger(1, pk)));
byte[] encrypted = alice.encrypt(plain);
System.out.println(String.format("encrypted: %x", new BigInteger(1, encrypted)));
// 用Alice的私钥解密:
byte[] sk = alice.getPrivateKey();
System.out.println(String.format("private key: %x", new BigInteger(1, sk)));
byte[] decrypted = alice.decrypt(encrypted);
System.out.println(new String(decrypted, "UTF-8"));
}
}
class Person {
String name;
// 私钥:
PrivateKey sk;
// 公钥:
PublicKey pk;
public Person(String name) throws GeneralSecurityException {
this.name = name;
// 生成公钥/私钥对:
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
kpGen.initialize(1024);
KeyPair kp = kpGen.generateKeyPair();
this.sk = kp.getPrivate();
this.pk = kp.getPublic();
}
// 把私钥导出为字节
public byte[] getPrivateKey() {
return this.sk.getEncoded();
}
// 把公钥导出为字节
public byte[] getPublicKey() {
return this.pk.getEncoded();
}
// 用公钥加密:
public byte[] encrypt(byte[] message) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, this.pk);
return cipher.doFinal(message);
}
// 用私钥解密:
public byte[] decrypt(byte[] input) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, this.sk);
return cipher.doFinal(input);
}
}
# 控制台
public key: 30819f300d06092a864886f70d010101050003818d003081890281810089660a2d7d6fce9cacca4b6c31e7815dbd3b25109c9f54776f00fef6cd5e6b6e68237cbfa8fd5476a19ad2ab19f3c393e9a14ab65aca68b4c2bac2499613710b6c2af2d3243c7af7f03829c8a4512626529c0b887740d07ef9c2c10c454d9c971619eb307df092122cb27f36396eeae828e777e97ff38c27cb87ba5936a4db1b0203010001
encrypted: 184a4bd4faa5d3ceae2c08d393ab48b928f6ace0086a2d4a7715fff012b6c0d3483ab842e8cf476ed6df0aa9cd0161c7c04d6c02e1a44a8f013c27a653bb4fe74cf1b1220f23caeb78ea5dec39b9ec842a4a16a3a532400ff6253723574624ebfb213e028dc12164a531cbee34db9df66ff2b883600de8526d3bf5b19ee9e642
private key: 30820276020100300d06092a864886f70d0101010500048202603082025c0201000281810089660a2d7d6fce9cacca4b6c31e7815dbd3b25109c9f54776f00fef6cd5e6b6e68237cbfa8fd5476a19ad2ab19f3c393e9a14ab65aca68b4c2bac2499613710b6c2af2d3243c7af7f03829c8a4512626529c0b887740d07ef9c2c10c454d9c971619eb307df092122cb27f36396eeae828e777e97ff38c27cb87ba5936a4db1b02030100010281810087a4d14f6f92bdeb373acf9315017459d2c35d283537a6eff20a8daba1bc215b723bf6a0507928b5a57d6f95b39d4febeaae6d4ff1f9f9bcdab1fdb52010397c9634aa3e87003afe4a2cc6f2169fcf6e163d3d3593b22fc08585a9822f887b0b28a0a721ff119ff3408dd6ad040373fffdb4d6264ce70bee95338bbe52d9bf21024100c8cd1d32bb0c06d275041d6fb5bf11b25957f63d4ed93ffef110d8cd1e8a6c5c9fc138bfea49fe448db0f6138605acd0405ba3398dcc3b86cd868fb50538933f024100af2b1f92b32b4946f76282f567fcae8533dc1a48a34508487e0aeff479dbe24c55081773cbf6daf10e379e85aff98d5741b62f2432bce03439ade9d2a68aad2502400db47a2eb13783ebaf52e5936f4b28310d0a04e37053419bebe62375f484ac1ab248a4cfec74ba670168b792e38dd59aad19d40d249170eaa5726eb28335b64f02403c9f47010542f0cc3fa7773d292cd8d53e9a68fa448f0a8bd41b42ea30163a1e42bb572a7b2746a470502d6b84f86fc307f9de1cbff67ffd730cce4459e0da8502404c0e26dd68bc647f65d74480e048204c898a1e2a3fcd0bb46c87354c4c97bd92c03820616c924c1998913c43d91e74b54be3ce2530627cda19e32f348180c246
Hello,使用RSA非对称加密算法对数据进行加密!