1.hash算法
package main.com.wyz.test;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
//hash算法 java8 API:https://docs.oracle.com/javase/8/docs/api/
public class HashTest {
public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException {
//算法名称
String algorithm[] ={"MD5","SHA-1","SHA-256","SHA-512"};
// MessageDigest: https://blog.csdn.net/hudashi/article/details/8394158
// MessageDigest instance = MessageDigest.getInstance(algorithm[0]);
// MessageDigest instance = MessageDigest.getInstance(algorithm[1]);
// MessageDigest instance = MessageDigest.getInstance(algorithm[2]);
MessageDigest instance = MessageDigest.getInstance(algorithm[3]);
String msg1="Hello";
String msg2 ="World";
instance.update(msg1.getBytes(StandardCharsets.UTF_8));
instance.update(msg2.getBytes(StandardCharsets.UTF_8));
byte[] digest = instance.digest();
System.out.println("算法名:"+instance.getAlgorithm() +"<====>输出的摘要长度:"+instance.getDigestLength()+"字节<====>16进制摘要值:"+new BigInteger(1,digest).toString(16));
// 算法名:MD5<====>输出的摘要长度:16字节<====>16进制摘要值:68e109f0f40ca72a15e05cc22786f8e6
// 算法名:SHA-1<====>输出的摘要长度:20字节<====>16进制摘要值:db8ac1c259eb89d4a131b253bacfca5f319d54f2
// 算法名:SHA-256<====>输出的摘要长度:32字节<====>16进制摘要值:872e4e50ce9990d8b041330c47c9ddd11bec6b503ae9386a99da8584e9bb12c4
// 算法名:SHA-512<====>输出的摘要长度:64字节<====>16进制摘要值:8ae6ae71a75d3fb2e0225deeb004faf95d816a0a58093eb4cb5a3aa0f197050d7a4dc0a2d5c6fbae5fb5b0d536a0a9e6b686369fa57a027687c3630321547596
// 注意:MD5因为输出长度较短,短时间内破解是可能的,目前已经不推荐使用。
}
}
2.Hmac算法
package main.com.wyz.test;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
//Hmac算法 java8 API:https://docs.oracle.com/javase/8/docs/api/
public class HmacTest {
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
//算法名称
String algorithm[] ={"HmacMD5"};
//KeyGenerator此类提供(对称加密算法:AES,DES 等等)密钥生成器的功能
// 参考:https://blog.csdn.net/kzcming/article/details/80095114
//1.通过名称HmacMD5获取KeyGenerator实例;
KeyGenerator keyGen = KeyGenerator.getInstance(algorithm[0]);
//2.通过KeyGenerator创建一个SecretKey实例;
SecretKey key = keyGen.generateKey();
//打印随机生成的key
byte[] skey = key.getEncoded();
System.out.println("算法名称:"+key.getAlgorithm()+"<====>16进制的秘钥值:"+new BigInteger(1,skey).toString(16));
//3.通过名称HmacMD5获取Mac实例
Mac mac = Mac.getInstance(algorithm[0]);
//4.用SecretKey初始化Mac实例;
mac.init(key);
//5.对Mac实例反复调用update(byte[])输入数据
mac.update("HelloWorld".getBytes(StandardCharsets.UTF_8));
//6.调用Mac实例的doFinal()获取最终的哈希值。
byte[] result = mac.doFinal();
System.out.println("算法名称:"+mac.getAlgorithm()+"<====>输出长度:"+mac.getMacLength()+"字节<====>16进制的秘钥值:"+new BigInteger(1,result).toString(16));
System.out.println("验证前哈希值:"+Arrays.toString(result));
//通过Hmac计算的哈希和SecretKey 进行验证
System.out.println("<====验证=====>");
SecretKeySpec keySpec = new SecretKeySpec(result, algorithm[0]);
byte[] skey1 = keySpec.getEncoded();
System.out.println("算法名称:"+keySpec.getAlgorithm()+"<====>16进制的秘钥值:"+new BigInteger(1,skey1).toString(16));
Mac mac1 = Mac.getInstance(algorithm[0]);
mac1.init(keySpec);
mac1.update("HelloWorld".getBytes(StandardCharsets.UTF_8));
byte[] bytes = mac1.doFinal();
System.out.println("算法名称:"+mac1.getAlgorithm()+"<====>输出长度:"+mac1.getMacLength()+"字节<====>16进制的秘钥值:"+new BigInteger(1,bytes).toString(16));
System.out.println("验证后哈希值:"+Arrays.toString(bytes));
// 算法名称:HmacMD5<====>16进制的秘钥值:396ed8fe32ab6eea619a28440393d7bb13b2ff3a6044ae1ca4a685e24f7a28e5b81d2f11557fd9984ea47d150c307ab90dbc0b6b921d465bd766c9847a431ca9
// 算法名称:HmacMD5<====>输出长度:16字节<====>16进制的秘钥值:6483704bc4d8076158c0f96cc58cbf79
// 验证前哈希值:[100, -125, 112, 75, -60, -40, 7, 97, 88, -64, -7, 108, -59, -116, -65, 121]
//<====验证=====>
// 算法名称:HmacMD5<====>16进制的秘钥值:6483704bc4d8076158c0f96cc58cbf79
// 算法名称:HmacMD5<====>输出长度:16字节<====>16进制的秘钥值:c16caa5c3265f1127a01c9be8848670f
// 验证后哈希值:[-63, 108, -86, 92, 50, 101, -15, 18, 122, 1, -55, -66, -120, 72, 103, 15]
}
}
3.对称加密算法-ECB模式
package main.com.wyz.test;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.Base64;
//对称加密算法 --ECB模式
public class SymmetricalECBTest {
public static void main(String[] args) throws Exception {
// 原文:
String message = "Hello, world!";
System.out.println("原文:Message: " + message);
// 128位密钥 = 16 bytes Key:
byte[] key = "1234567890abcdef".getBytes(StandardCharsets.UTF_8);
// 加密:
byte[] data = message.getBytes(StandardCharsets.UTF_8);
byte[] encrypt = encrypt(key, data);
System.out.println("加密后:Message: " + Base64.getEncoder().encodeToString(encrypt));
//解密:
byte[] decrypt = decrypt(key, encrypt);
System.out.println("解密后:Message: " + new String(decrypt,StandardCharsets.UTF_8));
// 原文:Message: Hello, world!
// 加密后:Message: 2xiGROlFBhC57b7EGu5c3g==
// 解密后:Message: Hello, world!
}
// ECB模式加密
//Cipher: https://www.cnblogs.com/caizhaokai/p/10944667.html
public static byte[] encrypt(byte[] key,byte[] input) throws GeneralSecurityException {
//1.根据算法名称/工作模式/填充模式获取Cipher实例;
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
//2.根据算法名称初始化一个SecretKey实例,密钥必须是指定长度;
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
//3.使用SerectKey初始化Cipher实例,并设置加密或解密模式;
cipher.init(Cipher.ENCRYPT_MODE,keySpec);//加密模式
//4.传入明文,获得密文。
return cipher.doFinal(input);
}
//ECB模式解密
public static byte[] decrypt(byte[] key,byte[] input) throws GeneralSecurityException{
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
cipher.init(Cipher.DECRYPT_MODE,keySpec);//解密模式
//传入密文,获得明文。
return cipher.doFinal(input);
}
}
4.对称加密算法-CBC模式
package main.com.wyz.test;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Arrays;
import java.util.Base64;
//对称加密算法 CBC模式:
//ECB模式是最简单的AES加密模式,它只需要一个固定长度的密钥,固定的明文会生成固定的密文,这种一对一的加密方式会导致安全性降低,更好的方式是通过CBC模式,它需要一个随机数作为IV参数,这样对于同一份明文,每次生成的密文都不同
public class SymmetricalCBCTest {
public static void main(String[] args) throws Exception {
// 原文:
String message = "Hello, world!";
System.out.println("原文:Message: " + message);
// 128位密钥 = 16 bytes Key:
byte[] key = "1234567890abcdef".getBytes(StandardCharsets.UTF_8);
// 加密:
byte[] data = message.getBytes(StandardCharsets.UTF_8);
byte[] encrypt = encrypt(key, data);
System.out.println("加密后:Message: " + Base64.getEncoder().encodeToString(encrypt));
//解密:
byte[] decrypt = decrypt(key, encrypt);
System.out.println("解密后:Message: " + new String(decrypt,StandardCharsets.UTF_8));
//原文:Message: Hello, world!
//加密时iv数组:[-100, -73, -103, -13, -22, 112, 105, -24, 82, 40, 110, -87, 12, 120, -38, 8]加密后的密文:9cQ1XTxgPinj/uYpBLBB4A==
//合并后的iv和密文:nLeZ8+pwaehSKG6pDHjaCPXENV08YD4p4/7mKQSwQeA=
//加密后:Message: nLeZ8+pwaehSKG6pDHjaCPXENV08YD4p4/7mKQSwQeA=
//解密时iv:[-100, -73, -103, -13, -22, 112, 105, -24, 82, 40, 110, -87, 12, 120, -38, 8]
//解密后的明文:Hello, world!
//解密后:Message: Hello, world!
}
//CBC模式加密
public static byte[] encrypt(byte[] key,byte[] input) throws
GeneralSecurityException{
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
//CBC模式需要生成一个16 bytes的initialization vector:
SecureRandom secureRandom = SecureRandom.getInstanceStrong();
byte[] iv = secureRandom.generateSeed(16);
System.out.printf("加密时iv数组:"+ Arrays.toString(iv));
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE,keySpec,ivSpec);
byte[] data = cipher.doFinal(input);
System.out.println("加密后的密文:"+Base64.getEncoder().encodeToString(data));
//IV不需要保密,把IV和密文一起返回
return join(iv,data);
}
//CBC模式解密
public static byte[] decrypt(byte[] key,byte[] input) throws GeneralSecurityException{
//把input分割成IV 和密文
byte[] iv = new byte[16];
byte[] data = new byte[input.length - 16];
System.arraycopy(input,0,iv,0,16);
System.arraycopy(input,16,data,0,data.length);
System.out.println("解密时iv:"+Arrays.toString(iv));
//解密
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivPesc = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE,keySpec,ivPesc);
byte[] result = cipher.doFinal(data);
System.out.println("解密后的明文:"+new String(result));
return result;
}
//合并
public static byte[] join(byte[] bs1,byte[] bs2){
byte[] r = new byte[bs1.length + bs2.length];
System.arraycopy(bs1,0,r,0,bs1.length);
System.arraycopy(bs2,0,r,bs1.length,bs2.length);
System.out.println("合并后的iv和密文:"+Base64.getEncoder().encodeToString(r));
return r;
}
}
5.对称加密算法-口令加密算法(PBE)
package main.com.wyz.test;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Base64;
//口令加密算法
public class SymmetricalEPBETest {
public static void main(String[] args) throws Exception {
// 把BouncyCastle作为Provider添加到java.security:
Security.addProvider(new BouncyCastleProvider()); todo 待引入BouncyCastle 的jar
// 原文:
String message = "Hello, world!";
// 加密口令:
String password = "hello12345";
// 16 bytes随机Salt:
byte[] salt = SecureRandom.getInstanceStrong().generateSeed(16);
System.out.printf("salt: %032x\n", new BigInteger(1, salt));
// 加密:
byte[] data = message.getBytes("UTF-8");
byte[] encrypted = encrypt(password, salt, data);
System.out.println("encrypted: " + Base64.getEncoder().encodeToString(encrypted));
// 解密:
byte[] decrypted = decrypt(password, salt, encrypted);
System.out.println("decrypted: " + new String(decrypted, "UTF-8"));
}
// 加密:
public static byte[] encrypt(String password, byte[] salt, byte[] input) throws GeneralSecurityException {
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
SecretKeyFactory skeyFactory = SecretKeyFactory.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
SecretKey skey = skeyFactory.generateSecret(keySpec);
PBEParameterSpec pbeps = new PBEParameterSpec(salt, 1000);
Cipher cipher = Cipher.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
cipher.init(Cipher.ENCRYPT_MODE, skey, pbeps);
return cipher.doFinal(input);
}
// 解密:
public static byte[] decrypt(String password, byte[] salt, byte[] input) throws GeneralSecurityException {
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
SecretKeyFactory skeyFactory = SecretKeyFactory.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
SecretKey skey = skeyFactory.generateSecret(keySpec);
PBEParameterSpec pbeps = new PBEParameterSpec(salt, 1000);
Cipher cipher = Cipher.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
cipher.init(Cipher.DECRYPT_MODE, skey, pbeps);
return cipher.doFinal(input);
}
}
6.秘钥交换算法(DH算法)
package main.com.wyz.test;
import javax.crypto.KeyAgreement;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.X509EncodedKeySpec;
//密钥交换算法-DH算法没有解决中间人攻击(即甲乙双方并不能确保与自己通信的是否真的是对方)。
//DH算法解决了密钥在双方不直接传递密钥的情况下完成密钥交换,这个神奇的交换原理完全由数学理论支持。
public class DHTest {
public static void main(String[] args) {
//ZhangSan 和 LiSi
Person zhangSan = new Person("ZhangSan");
Person liSi = new Person("LiSi");
// 各自生成KeyPair:
zhangSan.generateKeyPair();
liSi.generateKeyPair();
// 双方交换各自的PublicKey:
// zhangSan根据liSi的PublicKey生成自己的本地密钥:
zhangSan.generateSecretKey(liSi.publicKey.getEncoded());
// liSi根据zhangSan的PublicKey生成自己的本地密钥:
liSi.generateSecretKey(zhangSan.publicKey.getEncoded());
// 检查双方的本地密钥是否相同:
System.out.println("==========检查双方的本地密钥===========");
System.out.println("==========zhangSan:密钥===========");
zhangSan.printKeys();
System.out.println("==========liSi:密钥===========");
liSi.printKeys();
// 双方的SecretKey相同,后续通信将使用SecretKey作为密钥进行AES加解密...
//
//==========检查双方的本地密钥===========
//==========zhangSan:密钥===========
//Name: ZhangSan
//Private key: 3081d202010030819706092a864886f70d010301308189024100fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e170240678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4020201800433023100f0c6828e3547e61ce01174362fbf13045c20d70bf22069d664a9e6d844761737dabab6ab2fe1c047c049c4c196c97ad3
//Public key: 3081df30819706092a864886f70d010301308189024100fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e170240678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4020201800343000240755894bc5dc580252514d1a2aa1d59e40f310f4ee45a469aa4195fad07d8e44a61b1de52fb1fcdd86130dfc1af2ce7548ad2a1d1a30dc517d7e295d9a5e0d2e5
//Secret key: d6b903a0d4d497f95e26136b3413c181bd607ed3e316ddaf6932649b19aa0ac28968b81ec45be98346022af16c345c25b859115d26042b3138b100cc135c8024
//==========liSi:密钥===========
//Name: LiSi
//Private key: 3081d202010030819706092a864886f70d010301308189024100fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e170240678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4020201800433023100c59b19a7150617d2212f694a4018a1b8c201a14b791f342b34fb38c6f06e703a356023bd4e4814eb97adaf59e203a5df
//Public key: 3081df30819706092a864886f70d010301308189024100fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e170240678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4020201800343000240519092640b3d5a8564f7d0edf86a1a01fdc6c0a12e764ed8a8b9b85c87146f1577b4e95fd901a397e282f061fb6e0a33861b0f18f81bc6132636b866790805c2
//Secret key: d6b903a0d4d497f95e26136b3413c181bd607ed3e316ddaf6932649b19aa0ac28968b81ec45be98346022af16c345c25b859115d26042b3138b100cc135c8024
}
static 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 (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
//利用传入的公钥 生成秘钥
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);//自己的PrivaKey
keyAgreement.doPhase(receivedPublicKey,true);//对方的PublicKey
//生成SecretKey
this.secretKey = keyAgreement.generateSecret();
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
}
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));
}
}
}
7.非对称加密算法(RSA算法)
package main.com.wyz.test;
import javax.crypto.Cipher;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
public class RSATest {
public static void main(String[] args) throws Exception{
byte[] plain = "Hello,encrypt use RSA".getBytes(StandardCharsets.UTF_8);
//创建公钥/私钥对
Person zhangsan = new Person("zhangsan");
//用zhangsan的公钥加密:
byte[] pk = zhangsan.getPublicKey();
System.out.println(String.format("public key: %x", new BigInteger(1, pk)));
byte[] encrypt = zhangsan.encrypt(plain);
System.out.println(String.format("encrypted: %x", new BigInteger(1, encrypt)));
//用zhangsan的私密解密
byte[] sk = zhangsan.getPrivateKey();
System.out.println(String.format("private key: %x", new BigInteger(1, sk)));
byte[] decrypt = zhangsan.decrypt(encrypt);
System.out.println(new String(decrypt, StandardCharsets.UTF_8));
// public key: 30819f300d06092a864886f70d010101050003818d0030818902818100a01ddd40901cbb072db865576aeb2bd58f834222ced94acb126dd7c2d94aad698d4a799d2151e1148d72eda5372bc53abf8c75c0decaca586359ebc3b8527ec770c6ac3dfee34a2df4c963b7261c6ba0237acef1202ebdcda08a83b5d2f1f553657907f6362a88789fecbb3f400c03d98ce8b23c275d8d6696f3971f8becb7ef0203010001
// encrypted: 4d324a47047b8e1644846f60d4cfff3170a47a67b7a4a19d596a2f36d79b568da4001ff604d92968e4a115115b41bbdd1d1645095ab54b1587cb89ed5c5a06bc70c143c1ccb7a02bfcc2526b22ba368d54ebdb99fb512f8b148b424bc76bd598339ae626a3ef0d372b0378c66c9578f5e549f857bc565effb7f44a168a2b326c
// private key: 30820277020100300d06092a864886f70d0101010500048202613082025d02010002818100a01ddd40901cbb072db865576aeb2bd58f834222ced94acb126dd7c2d94aad698d4a799d2151e1148d72eda5372bc53abf8c75c0decaca586359ebc3b8527ec770c6ac3dfee34a2df4c963b7261c6ba0237acef1202ebdcda08a83b5d2f1f553657907f6362a88789fecbb3f400c03d98ce8b23c275d8d6696f3971f8becb7ef0203010001028181008772bc0831e11c16268726b39caef495e4a19500fd1ab43ab58c56496ea7cdaacceb839578ea5b0d97daf14e222dd4daadcf948d63eb08e15caa64d75cc5ec98538ba8e1fb0464adac2397f5c5cb4eda54a3aee2cfb8dac2f71e05ed60cee357de25fa5e221e462ee15113ef9128b3a025220c6dc095ad30f9695c83634ba101024100d76acd488fd6921d87c72dca9e6ffd84c1daa00518b002b26f489558412c6e8527fe2fb0ed0bed4057cd5b15451c20cd7121333f3d41378e627f5f923147cdc7024100be480364ae7c0f61fcc6ca74ed08c2bfd369a4700ff004579e73394d8188eca842120a90a94196812b16567b85a60e98bd20713f333cda815d0a89f1fb57649902400e4ee0bdbe18117276af4b22572db718174c2f2ec77a0163dab266810b2b29581cd4ec54031ab4b27e627c774834db14ea3bbb4cab03e6edc52b12ad022af3c702404f2b9f5dd0cb858afba5aaaf23c0b567230b9d8392de06b07e18eb0ab88ec408ee149b98bd13b10f656211f1ab160094c47c2f2260ab3d2efe0b5881fa55ce61024100a1a16f2c413af4061e55558a8d490a54f6fa4301209b5659855a8805b802a84a9ac90bc2ac261e4f39a1943d86e4d89c9242571dfd9d90f1a87811bb4f9c702e
// Hello,encrypt use RSA
}
static 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 PublicKey recoverPublicKey( byte[] pkData) throws GeneralSecurityException{
KeyFactory kf = KeyFactory.getInstance("RSA");
//恢复公钥
X509EncodedKeySpec pkSpec= new X509EncodedKeySpec(pkData);
PublicKey publicKey = kf.generatePublic(pkSpec);
return publicKey;
}
//恢复私钥
public PrivateKey recoverPrivateKey( byte[] skData) throws GeneralSecurityException{
KeyFactory kf = KeyFactory.getInstance("RSA");
//恢复公钥
PKCS8EncodedKeySpec skSpec = new PKCS8EncodedKeySpec(skData);
PrivateKey privateKey = kf.generatePrivate(skSpec);
return privateKey;
}
}
7.数字签名(RSA/DSA/ECDSA)
package main.com.wyz.test;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.*;
public class DSATest {
public static void main(String[] args) throws GeneralSecurityException{
//生成RSA公钥/私钥
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
kpGen.initialize(1024);
KeyPair kp = kpGen.generateKeyPair();
PrivateKey sk = kp.getPrivate();
PublicKey pk = kp.getPublic();
//待签名的消息
byte[] message = "Hello, I am Bob!".getBytes(StandardCharsets.UTF_8);
//用私钥签名
Signature s = Signature.getInstance("SHA1withRSA");
s.initSign(sk);
s.update(message);
byte[] sign = s.sign();
System.out.println(String.format("signature: %x", new BigInteger(1, sign)));
//用公钥验证
Signature v = Signature.getInstance("SHA1withRSA");
v.initVerify(pk);
v.update(message);
boolean valid = v.verify(sign);
System.out.println("valid? " + valid);
// signature: 7ffa96db287f9b11983c7b19e46159d37ed63c4455fbd9599b19271a49f3a4707c508da63c836842c25fdbf72e3f615c734d4c64ed9b3b8212988e302c89a4b68f7e42664e64b84e85c2c225bc09ca3833e22dc16020401bffa7bdb3754fa07c486127b12d02ef30f9061be1d5c173d544b6d94d132b8bba6b0b0b34109353f5
// valid? true
}
}
9.数字证书 (CA)
package main.com.wyz.test;
import javax.crypto.Cipher;
import java.io.InputStream;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.X509Certificate;
//注意:数字证书存储的是公钥,以及相关的证书链和算法信息。私钥必须严格保密,如果数字证书对应的私钥泄漏,就会造成严重的安全威胁。
public class CATest {
public static void main(String[] args) throws Exception {
String password ="123456";//keyStore文件证书密码
String alias ="mycert";//keyStore证书文件的别名
//需要发送的信息
byte[] message = "Hello,use X.509 cert!".getBytes(StandardCharsets.UTF_8);
//读取keyStore文件
KeyStore ks = loadKeyStore("/my.keystore", password);
//读取私钥
PrivateKey privateKey =(PrivateKey) ks.getKey("mycert", password.toCharArray());
//读取证书
X509Certificate certificate = (X509Certificate)ks.getCertificate(alias);
//加密消息
byte[] encrypt = encrypt(certificate, message);
System.out.println(String.format("encrypted: %x", new BigInteger(1, encrypt)));
//解密信息
byte[] decrypt = decrypt(privateKey, encrypt);
System.out.println("decrypted: " + new String(decrypt, StandardCharsets.UTF_8));
//签名
byte[] sign = sign(privateKey, certificate, message);
System.out.println(String.format("signature: %x", new BigInteger(1, sign)));
//验证签名
boolean verify = verify(certificate, message, sign);
System.out.println("verify: " + verify);
}
//读取(加载)KeyStore文件
static KeyStore loadKeyStore(String keyStoreFile, String password){
try (InputStream input = CATest.class.getResourceAsStream(keyStoreFile)) {
if(input == null){
throw new RuntimeException("file not found in classpath:"+keyStoreFile);
}
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(input,password.toCharArray());
return ks;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// 用公钥加密信息
static byte[] encrypt(X509Certificate certificate,byte[] message) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance(certificate.getPublicKey().getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE,certificate.getPublicKey());
return cipher.doFinal(message);
}
//用私钥解密信息
static byte[] decrypt(PrivateKey privateKey,byte[] data) throws GeneralSecurityException{
Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE,privateKey);
return cipher.doFinal(data);
}
//用私钥和公钥进行信息签名
static byte[] sign(PrivateKey privateKey,X509Certificate certificate,byte[] message) throws GeneralSecurityException {
Signature signature = Signature.getInstance(certificate.getSigAlgName());
signature.initSign(privateKey);
signature.update(message);
return signature.sign();
}
//用公钥进行签名验证
static boolean verify(X509Certificate certificate,byte[] message,byte[] sig) throws GeneralSecurityException{
Signature signature = Signature.getInstance(certificate.getSigAlgName());
signature.initVerify(certificate);
signature.update(message);
boolean verify = signature.verify(sig);
return verify;
}
}
参考:https://www.liaoxuefeng.com/wiki/1252599548343744/1255943717668160