简单解释下AES和RSA
AES:对称加密,双方用一样的秘钥加密解密,耗时根据加密长度线性增长.
RSA:非对称加密,有公钥和私钥,用公钥加密,用私钥解密,一般用在单向请求的业务中.发送方只保存公钥,用来加密原文.接收方只保存私钥,用来解密密文.耗时根据加密长度指数性增长.
直接上代码;
AES 工具类
public class AESUtil {
private static final String AES = "AES";
private static final String UTF8="utf-8";
/**
* 生成秘钥
* @param size 长度
* @param secure 加密参数
* @return 秘钥
*/
public static String getAESKey(int size,String secure) throws NoSuchAlgorithmException {
KeyGenerator kgen = KeyGenerator.getInstance(AES);
/**可以根据参数生成固定的秘钥*/
if (null == secure || secure.equals("")){
kgen.init(size, new SecureRandom());
}else{
kgen.init(size, new SecureRandom(secure.getBytes()));
}
/**生成秘钥并转base64编码*/
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
String encodeKey = Base64.getEncoder().encodeToString(enCodeFormat);
System.out.println("AES秘钥::"+encodeKey);
return encodeKey;
}
/**
* AES 加密
* @param content 原文
* @param aesKey 秘钥
* @return 密文
* @throws Exception
*/
public static String encrypt(String content, String aesKey) throws Exception {
/**base64解码秘钥 并转换为AES专用密钥*/
SecretKeySpec key = new SecretKeySpec(Base64.getDecoder().decode(aesKey), AES);
Cipher cipher = Cipher.getInstance(AES);
byte[] byteContent = content.getBytes(UTF8);
/**初始化为加密模式的密码器 */
cipher.init(Cipher.ENCRYPT_MODE, key);
/**加密并转出base64返回密文*/
byte[] result = cipher.doFinal(byteContent);
return Base64.getEncoder().encodeToString(result);
}
/**
* AES 解码
* @param content 密文
* @param aesKey 秘钥
* @return 原文
*/
public static String decrypt(String content, String aesKey) throws Exception {
/**将秘钥,密文 base64字节*/
byte[] decodeKey = Base64.getDecoder().decode(aesKey);
byte[] decodeContent = Base64.getDecoder().decode(content);
/**转换为AES专用密钥*/
SecretKeySpec key = new SecretKeySpec(decodeKey, AES);
/**创建 初始化 容器*/
Cipher cipher = Cipher.getInstance(AES);
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] result = cipher.doFinal(decodeContent);
/**返回明文*/
return new String(result,UTF8);
}
public static void main(String[] args) {
try {
getAESKey(128,null);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
注:可以根据传入的一样的参数从而生成一样的秘钥
AES 测试
public class AESTest {
public static final String AES_KEY = "+6x5a6mr033+USKVCpWxog==";
public static void main(String[] args) {
String content = "小桥流水人家";
try {
String encrypt = AESUtil.encrypt(content, AES_KEY);
System.out.println("密文::"+encrypt);
String decrypt = AESUtil.decrypt(encrypt, AES_KEY);
System.out.println("原文::"+decrypt);
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出内容:
密文::b2xklTIno1Q0eAOXgvG8noriNuQR4wUrf7QkZdaIdI4=
原文::小桥流水人家
RSA工具类
public class RSAUtil {
private static final String RSA = "RSA";
private static final String UTF8="utf-8";
/**
* 生成秘钥对
* @param size 密钥长度 于原文长度对应 以及越长速度越慢
* @param secure 用于生成秘钥的参数
* @throws NoSuchAlgorithmException
*/
public static void genKeyPair(int size,String secure) throws NoSuchAlgorithmException {
/**基于RSA算法生成公钥和私钥对对象*/
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(RSA);
/**可以根据参数生成固定的秘钥*/
if (null == secure || secure.equals("")){
keyPairGen.initialize(size, new SecureRandom());
}else {
keyPairGen.initialize(size, new SecureRandom(secure.getBytes()));
}
/**生成一个密钥对*/
KeyPair keyPair = keyPairGen.generateKeyPair();
/**得到私钥 并用base64加密*/
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
String privateKeyString = Base64.getEncoder().encodeToString(privateKey.getEncoded());
System.out.println("秘钥::"+privateKeyString);
System.out.println("私钥长度::"+privateKeyString.length());
/**得到公钥 并用base64加密*/
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
String publicKeyString = Base64.getEncoder().encodeToString(publicKey.getEncoded());
System.out.println("公钥::"+publicKeyString);
System.out.println("公钥长度::"+publicKeyString.length());
}
/**
* 公钥加密
* @param str 加密内容
* @param publicKey 公钥
* @return
* @throws Exception
*/
public static String encrypt(String str, String publicKey) throws Exception {
/**base64解码公钥*/
byte[] decoded = Base64.getDecoder().decode(publicKey);
RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance(RSA).generatePublic(new X509EncodedKeySpec(decoded));
/**RSA加密*/
Cipher cipher = Cipher.getInstance(RSA);
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] content = cipher.doFinal(str.getBytes(UTF8));
/**base64将字节转字符*/
String outStr = Base64.getEncoder().encodeToString(content);
return outStr;
}
/**
* 私钥解密
* @param str 密文
* @param privateKey 私钥
* @return
* @throws Exception
*/
public static String decrypt(String str, String privateKey) throws Exception {
/**base64把密文转称字节*/
byte[] inputByte = Base64.getDecoder().decode(str);
/**base64解码私钥*/
byte[] decoded = Base64.getDecoder().decode(privateKey);
RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
/**RSA解密*/
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, priKey);
String outStr = new String(cipher.doFinal(inputByte));
return outStr;
}
public static void main(String[] args) {
try {
genKeyPair(2048,null);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
注:跟AES一样可以传入一样的参数获得一样的秘钥对
AES 测试
public class RSATest {
/**公钥 用于加密*/
public static final String PRIVATE_KEY= "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCEHt3BzouSNGIY/mxMBOF5oH/LYAo6dunHitMD4zv8wYN6AI3/tZp69uAW3bcrPWN3bGGEQj3uTRLP5SwqTn5b3KIYAWU1oShscHmtTcohQV0w4AH9eGAaZcY6gXYVckW7Y0EGYKPDWf5JRrB6AFcUV1vIx4pTWaecuDNzwzqkUNUjj05KiEHZsPuS4YUXP7z+Oi4i0RKnh0Mp4bbZC4BcJ1x/420t8YFzJnIt+E6jN3glxBaaSKluYjLxmz4gdxxeHXoaLBuWccshV6FCuuMJigoO4DSKQiPRIn88XrV9aebLCjfm3qCBlaaTO5CQvqtQsrxgUqmVLQ6M/D0lGEDPAgMBAAECggEAGxpJ22wHbaKZTQ9EIAQQTOcD0DCPaJbkNi7gQrfmol8AHZLnjkEuw3LJXWd2H8SkFueAyaTdF3lwFn2opbUcbrO//LSskmfQ5w3bqBWBFXlXKKOLRPfgnwmptG7CTnv2mg4uVKSWc4iOhXGe2igftOiGx5VHZvnJTHjs9R5jdTlkGADB26z4P1KRs0nhqCBjVXL9if6T6eLV+fJfS/SUynxSVbbsQ3XGaZnfzKU6PgUxnrndD5yfl0JPb31v0p1lpZ47lYFRbsOPKXbbheJtIrTaNcoJjor6udHSa4QFv8dOJO1j/oZvQcD+HXW69f6F1gin7/kV0MJRFZ1UQloXAQKBgQDF1IBJOwhLeHSrdTwHylnnrr1MBhsdBERJqbldt0h9RNjVeqgBmxnC5W0olxdDcaT7mC6j0E5SWSz0DfXJBSQKTFU2sy3VyWI6PsP8AymUQ976Z/6FAiJ7s/AbDECnsXkP/TrxxV7iHYLeG8CNP9bF7V1UvTaZ6pAT8LiAsW9IIQKBgQCq+CKPOIAdwMXGv/fPEP2vHY28UG0u1LflEp8lch8CMd49jk9qKD7DhDKFGsg79JKRzi8VOhCYqmJwIrJXx/lDhWhE2sBK05ekItLsEfttmTl6PIvu5G3H3F4bbBdTuPR1YYIFscpuLsBLu7rVZGBlkV4gaIRghYRXddR+1o6q7wKBgAPW9AZ31tlgJSOOyvN7wfL1OUdYdv5BLvIfETH4dLe5tluuXcRqNj3KJiw7goAUnJclhQI48Mw4Xt79xl94chKhGKZPI/yaRAXNYhBqH0x5ZMKHcjEysWilPWvI+RhIIYll6Nb4dbb9y6Rz9XDIZGrDCKS0Z3LlUpaQfYRB7V8BAoGALJizMxay3I/3RwO2GU4+ThpwaUm1YTzdhyRXXQYqroDhjr77Wh6LWKa4It48kt8WCHB2+Zt+zsPLD6MNUDZ6f7Fh5GwHMr2E1ay7xhZetlT8mDUI71SoijSiW5bTcuRQ5/l6WA/rVNhfEqIydw1K09OacOuydBb/0WyL9FX1OwMCgYBfNLg3YZX4pQpcOPv22f6mDROMDi3YJvFGcM79ryPKTX6FgP4Tj7Hrf9xwm5Qd4j6AIL29Ttt+3xlo+dLm+T8b/e59Yw94h1ZliL9OCgWNzgcV90OctTECpIulJijQk835TkrJjsMe7uPUiUs50xXIWLC3KmCuU2EDgWq0YWICzw==";
/**私钥 用于解密*/
public static final String PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhB7dwc6LkjRiGP5sTATheaB/y2AKOnbpx4rTA+M7/MGDegCN/7WaevbgFt23Kz1jd2xhhEI97k0Sz+UsKk5+W9yiGAFlNaEobHB5rU3KIUFdMOAB/XhgGmXGOoF2FXJFu2NBBmCjw1n+SUawegBXFFdbyMeKU1mnnLgzc8M6pFDVI49OSohB2bD7kuGFFz+8/jouItESp4dDKeG22QuAXCdcf+NtLfGBcyZyLfhOozd4JcQWmkipbmIy8Zs+IHccXh16GiwblnHLIVehQrrjCYoKDuA0ikIj0SJ/PF61fWnmywo35t6ggZWmkzuQkL6rULK8YFKplS0OjPw9JRhAzwIDAQAB";
public static void main(String[] args) {
String content = "古道西风瘦马";
try {
/**公钥加密*/
String encrypt = RSAUtil.encrypt(content, PUBLIC_KEY);
/**私钥解密*/
String decrypt = RSAUtil.decrypt(encrypt, PRIVATE_KEY);
System.out.println("解密后的原文::"+decrypt);
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果:
解密后的原文::古道西风瘦马
AES + RSA 组合更加安全,RSA的公钥私钥保持不变,AES的秘钥每次随机生成,发送方用AES加密原文,再用公钥加密AES的秘钥,带上加密后的秘钥和密文去请求.而接受方则先用私钥解密得到AES的秘钥再对密文进行解密
public class Demo {
/**公钥 用于加密*/
public static final String PRIVATE_KEY= "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCEHt3BzouSNGIY/mxMBOF5oH/LYAo6dunHitMD4zv8wYN6AI3/tZp69uAW3bcrPWN3bGGEQj3uTRLP5SwqTn5b3KIYAWU1oShscHmtTcohQV0w4AH9eGAaZcY6gXYVckW7Y0EGYKPDWf5JRrB6AFcUV1vIx4pTWaecuDNzwzqkUNUjj05KiEHZsPuS4YUXP7z+Oi4i0RKnh0Mp4bbZC4BcJ1x/420t8YFzJnIt+E6jN3glxBaaSKluYjLxmz4gdxxeHXoaLBuWccshV6FCuuMJigoO4DSKQiPRIn88XrV9aebLCjfm3qCBlaaTO5CQvqtQsrxgUqmVLQ6M/D0lGEDPAgMBAAECggEAGxpJ22wHbaKZTQ9EIAQQTOcD0DCPaJbkNi7gQrfmol8AHZLnjkEuw3LJXWd2H8SkFueAyaTdF3lwFn2opbUcbrO//LSskmfQ5w3bqBWBFXlXKKOLRPfgnwmptG7CTnv2mg4uVKSWc4iOhXGe2igftOiGx5VHZvnJTHjs9R5jdTlkGADB26z4P1KRs0nhqCBjVXL9if6T6eLV+fJfS/SUynxSVbbsQ3XGaZnfzKU6PgUxnrndD5yfl0JPb31v0p1lpZ47lYFRbsOPKXbbheJtIrTaNcoJjor6udHSa4QFv8dOJO1j/oZvQcD+HXW69f6F1gin7/kV0MJRFZ1UQloXAQKBgQDF1IBJOwhLeHSrdTwHylnnrr1MBhsdBERJqbldt0h9RNjVeqgBmxnC5W0olxdDcaT7mC6j0E5SWSz0DfXJBSQKTFU2sy3VyWI6PsP8AymUQ976Z/6FAiJ7s/AbDECnsXkP/TrxxV7iHYLeG8CNP9bF7V1UvTaZ6pAT8LiAsW9IIQKBgQCq+CKPOIAdwMXGv/fPEP2vHY28UG0u1LflEp8lch8CMd49jk9qKD7DhDKFGsg79JKRzi8VOhCYqmJwIrJXx/lDhWhE2sBK05ekItLsEfttmTl6PIvu5G3H3F4bbBdTuPR1YYIFscpuLsBLu7rVZGBlkV4gaIRghYRXddR+1o6q7wKBgAPW9AZ31tlgJSOOyvN7wfL1OUdYdv5BLvIfETH4dLe5tluuXcRqNj3KJiw7goAUnJclhQI48Mw4Xt79xl94chKhGKZPI/yaRAXNYhBqH0x5ZMKHcjEysWilPWvI+RhIIYll6Nb4dbb9y6Rz9XDIZGrDCKS0Z3LlUpaQfYRB7V8BAoGALJizMxay3I/3RwO2GU4+ThpwaUm1YTzdhyRXXQYqroDhjr77Wh6LWKa4It48kt8WCHB2+Zt+zsPLD6MNUDZ6f7Fh5GwHMr2E1ay7xhZetlT8mDUI71SoijSiW5bTcuRQ5/l6WA/rVNhfEqIydw1K09OacOuydBb/0WyL9FX1OwMCgYBfNLg3YZX4pQpcOPv22f6mDROMDi3YJvFGcM79ryPKTX6FgP4Tj7Hrf9xwm5Qd4j6AIL29Ttt+3xlo+dLm+T8b/e59Yw94h1ZliL9OCgWNzgcV90OctTECpIulJijQk835TkrJjsMe7uPUiUs50xXIWLC3KmCuU2EDgWq0YWICzw==";
/**私钥 用于解密*/
public static final String PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhB7dwc6LkjRiGP5sTATheaB/y2AKOnbpx4rTA+M7/MGDegCN/7WaevbgFt23Kz1jd2xhhEI97k0Sz+UsKk5+W9yiGAFlNaEobHB5rU3KIUFdMOAB/XhgGmXGOoF2FXJFu2NBBmCjw1n+SUawegBXFFdbyMeKU1mnnLgzc8M6pFDVI49OSohB2bD7kuGFFz+8/jouItESp4dDKeG22QuAXCdcf+NtLfGBcyZyLfhOozd4JcQWmkipbmIy8Zs+IHccXh16GiwblnHLIVehQrrjCYoKDuA0ikIj0SJ/PF61fWnmywo35t6ggZWmkzuQkL6rULK8YFKplS0OjPw9JRhAzwIDAQAB";
public static void main(String[] args) {
String content = "枯藤老树昏鸦,小桥流水人家,古道西风瘦马。夕阳西下,断肠人在天涯。";
try {
//发送方
/**1.AES 加密原文*/
String aesKey = AESUtil.getAESKey(128, null);
String contentEncrypt = AESUtil.encrypt(content, aesKey);
System.out.println("AES密文::"+contentEncrypt);
/**2.RSA 公钥加密AES的秘钥*/
String aesKeyEncrypt = RSAUtil.encrypt(aesKey, PUBLIC_KEY);
System.out.println("加密后的AES秘钥::"+aesKeyEncrypt);
//发送密文contentEncrypt 和加密后的秘钥aesKeyEncrypt
//接收方
/**3.RSA 私钥解密获取AES 秘钥*/
String aesKeyDecrypt = RSAUtil.decrypt(aesKeyEncrypt, PRIVATE_KEY);
System.out.println("解密后的AES秘钥::"+aesKeyDecrypt);
/**4.AES 解密获取原文*/
String contentDecrypt = AESUtil.decrypt(contentEncrypt, aesKeyDecrypt);
System.out.println("原文::"+contentDecrypt);
}catch (Exception e){
e.printStackTrace();
}
}
}
输出内容:
AES秘钥::meueToop83cx+dRMx0+K+g==
AES密文::13bH6M6/TTVOIE9DUFu0F58j/BUAR9dnJL4DF8WWZJYW7U64KrvvivXB2hlbaDxi+pwpXR97I5icI9fThwylRNrIvuEsih/ugfGwBmFTj2py/DXbPoZ2bnQPNx6Yj9WPP47c0dCaWly4OqgVZkvSQA==
加密后的AES秘钥::UkhDS6Br2IN1PJpUcABnq4u3OibaHtFZSRnoXX4rRhjNy46zaYA+LeMPFM9aZHBQnYWrb8PYWwNuOpKVgBWRSGbzWuJ6rhVXSvWlmxVbcMDLsxebFJ0wfoPaxY0wWHORQGi3OPHNeyiUS9yKiZ+JKM8FmkGq81FSFJRv6HzLkh16TlMG0lTcSUQidKQmzxM5TZXHr+nW3FP+dicg4FAxI51lFijt/JfqnoagX2smorG12Ow3SqXGrOp8uY4gH6jikfhyVpP7eGHwqZWxKOTnBrGoVlqL7kF15JQvrMMhgzZC4gyS8MDFiELWgAatxqSMoiMafxMIs9AAuGye5wu1Og==
解密后的AES秘钥::meueToop83cx+dRMx0+K+g==
原文::枯藤老树昏鸦,小桥流水人家,古道西风瘦马。夕阳西下,断肠人在天涯。
参考自:https://blog.csdn.net/qq_42889895/article/details/106249724
https://blog.csdn.net/DamonREN/article/details/87601165