一、Hutool-crypto概述
加密分为三种:
1、对称加密(symmetric),例如:AES、EDS等
2、非对称加密(asymmetric),例如:RSA、DSA等
3、摘要加密(digest),例如:MD5、SHA-1、SHA-256、HMAC等
二、对称加密
对称加密(也叫私钥加密)指加密和解密使用相同密钥的加密算法。有时又叫传统密码算法,就是加密密钥能够从解密密钥中推算出来,同时解密密钥时也可以从加密密钥中推算出来。而在大多数的对称算法中,加密密钥和解密密钥是相同的,所以也称这种加密算法为秘密密钥算法或单密钥算法。它要求发送方和接收方在安全通信之前,商定一个密钥。对称算法的安全性依赖于密钥,泄露密钥就意味着任何人都可以对他们发送或接收的消息解密,所以密钥的保密性对通信安全性至关重要。
代码示例:
import cn.hutool.core.util.CharsetUtil; import cn.hutool.crypto.SecureUtil; import cn.hutool.crypto.symmetric.AES; import cn.hutool.crypto.symmetric.SymmetricAlgorithm; import cn.hutool.crypto.symmetric.SymmetricCrypto; public class HutoolSecure { public static void main(String[] args) { //生成UUID String s = SecureUtil.simpleUUID(); System.out.println(s); //5f210cbe09154af08564ffab22e66b6f //第一种:以AES算法 String content = "test中文"; //随机生成密钥 byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.AES.getValue()).getEncoded(); //构建 SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.AES,key); //加密 byte[] encrypt = aes.encrypt(content); //解密 byte[] decrypt = aes.decrypt(encrypt); //加密16进制表示 String encryptHex = aes.encryptHex(content); System.out.println("AES加密16进制表示:" + encryptHex); //46953def8ec02e21f7c9bb4405243a70 //解密为字符串 String decryptStr = aes.decryptStr(encryptHex, CharsetUtil.CHARSET_UTF_8); System.out.println("AES解密为字符串:" + decryptStr); //test中文 //第二种 DESede加密 String content2 = "test中文"; byte[] key2 = SecureUtil.generateKey(SymmetricAlgorithm.DESede.getValue()).getEncoded(); SymmetricCrypto des = new SymmetricCrypto(SymmetricAlgorithm.DESede,key2); //加密 byte[] encrypt2 = des.encrypt(content2); //解密 byte[] decrypt2 = des.decrypt(encrypt2); //加密为16进制字符串(Hex表示) String encryptHex2 = des.encryptHex(content2); System.out.println("DESede加密16进制表示:" + encryptHex2); //fcedfe2478d3e65b1a525d60676a6d88 String decryptStr2 = des.decryptStr(encryptHex2); System.out.println("DESede解密为字符串:" + decryptStr2); //test中文 //第三种AES封装 String content3 = "test中文"; //随机生成密钥 byte[] key3 = SecureUtil.generateKey(SymmetricAlgorithm.AES.getValue()).getEncoded(); //构建 AES aes3 = SecureUtil.aes(key3); //加密 byte[] encrypt3 = aes3.encrypt(content3); //解密 byte[] decrypt3 = aes3.decrypt(encrypt3); //加密为16进制表示 String encryptHex3 = aes3.encryptHex(content3); System.out.println("AES封装加密16进制表示:" + encryptHex3); //7300c26ae4081f9d9bd2395b9390f9ec //解密为字符串 String decryptStr3 = aes3.decryptStr(encryptHex3, CharsetUtil.CHARSET_UTF_8); System.out.println("AES封装解密为字符串:" + decryptStr3); //test中文 //由于IOS等移动端对AES加密有要求,必须为PKCS7Padding模式 AES aes4 = new AES("CBC","PKCS7Padding", //密钥,可以自定义 "0123456789ABHAEQ".getBytes(), //iv加盐,按照实际需求添加 "DYgjCEIMVrj2W9xN".getBytes()); //加密为16进制表示 String encryptHex4 = aes4.encryptHex(content3); System.out.println("加密后:" + encryptHex4); //90beca190dbe25c29925a8493ef6a538 String decryptStr4 = aes4.decryptStr(encryptHex4); System.out.println("解密后:" + decryptStr4); //test中文 //SM4国密算法 String content5 = "test国密算法"; SymmetricCrypto sm4 = new SymmetricCrypto("SM4"); String encryptHex5 = sm4.encryptHex(content5); System.out.println("SM4加密后:" + encryptHex5); //7d00175c6f2570fc132603f3922df7ca38c35f1c2fff3782140db4b915bf486b String decryptStr5 = sm4.decryptStr(encryptHex5, CharsetUtil.CHARSET_UTF_8); System.out.println("SM4解密后:" + decryptStr5); //test国密算法 } }
三、非对称加密
非对称加密最常用的就是RSA和DSA,在Hutool中使用AsymmetricCrypto对象来负责加密解密。
非对称加密有公钥和私钥两个概念,私钥自己拥有,不能给别人,公钥公开。根据应用的不同,我们可以选择使用不同的密钥加密;
1、签名:使用私钥加密,公钥解密。用于让所有公钥所有者验证私钥所有者的身份并且用来防止私钥所有者发布的内容被篡改,但是不用来保证内容不被他人获得。
2、加密:用公钥加密,私钥解密。用于向公钥所有者发布信息,这个信息可能被他人篡改,但是无法被他人获得。
使用:在非对称加密中,我们可以通过AsymmetricCrypto(AsymmetricAlgorithm algorithm)构造方法,通过传入不同的算法枚举,获得其加密解密器。
当然,为了方便,我们针对最常用的RSA算法构建了单独的对象:RSA。
代码示例:
import cn.hutool.core.codec.Base64; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.HexUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.asymmetric.KeyType; import cn.hutool.crypto.asymmetric.RSA; import sun.misc.BASE64Decoder; import java.io.IOException; public class HutoolAsymmetricCrypto { public static void main(String[] args) throws IOException { //非对称加密 RSA rsa = new RSA(); //获得私钥 rsa.getPrivateKey(); rsa.getPrivateKeyBase64(); //获得公钥 rsa.getPublicKey(); rsa.getPublicKeyBase64(); //公钥加密,私钥加密 byte[] encrypt = rsa.encrypt(StrUtil.bytes("RAS测试", CharsetUtil.CHARSET_UTF_8), KeyType.PublicKey); byte[] decrypt = rsa.decrypt(encrypt, KeyType.PrivateKey); String encode = Base64.encode(decrypt); System.out.println(encode); //UkFT5rWL6K+V //单元测试 // Assert.assertEquals("我是一段测试aaaa", StrUtil.str(decrypt, CharsetUtil.UTF_8)); //私钥加密,公钥解密 byte[] encrypt2 = rsa.encrypt(StrUtil.bytes("RAS测试", CharsetUtil.CHARSET_UTF_8), KeyType.PrivateKey); byte[] decrypt2 = rsa.decrypt(encrypt2,KeyType.PublicKey); String encode2 = Base64.encode(decrypt2); System.out.println(encode2); //UkFT5rWL6K+V //Base64解码 BASE64Decoder decoder = new BASE64Decoder(); String str = new String(decoder.decodeBuffer(encode2), "UTF-8"); System.out.println("解码后:" + str); //RAS测试 //已知私钥及密文如何加解密 String PRIVATE_KEY = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAIL7pbQ+5KKGYRhw7jE31hmA" + "f8Q60ybd+xZuRmuO5kOFBRqXGxKTQ9TfQI+aMW+0lw/kibKzaD/EKV91107xE384qOy6IcuBfaR5lv39OcoqNZ" + "5l+Dah5ABGnVkBP9fKOFhPgghBknTRo0/rZFGI6Q1UHXb+4atP++LNFlDymJcPAgMBAAECgYBammGb1alndta" + "xBmTtLLdveoBmp14p04D8mhkiC33iFKBcLUvvxGg2Vpuc+cbagyu/NZG+R/WDrlgEDUp6861M5BeFN0L9O4hz" + "GAEn8xyTE96f8sh4VlRmBOvVdwZqRO+ilkOM96+KL88A9RKdp8V2tna7TM6oI3LHDyf/JBoXaQJBAMcVN7fKlYP" + "Skzfh/yZzW2fmC0ZNg/qaW8Oa/wfDxlWjgnS0p/EKWZ8BxjR/d199L3i/KMaGdfpaWbYZLvYENqUCQQCobjsuCW" + "nlZhcWajjzpsSuy8/bICVEpUax1fUZ58Mq69CQXfaZemD9Ar4omzuEAAs2/uee3kt3AvCBaeq05NyjAkBme8SwB0iK" + "kLcaeGuJlq7CQIkjSrobIqUEf+CzVZPe+AorG+isS+Cw2w/2bHu+G0p5xSYvdH59P0+ZT0N+f9LFAkA6v3Ae56OrI" + "wfMhrJksfeKbIaMjNLS9b8JynIaXg9iCiyOHmgkMl5gAbPoH/ULXqSKwzBw5mJ2GW1gBlyaSfV3AkA/RJC+adIjsRGg" + "JOkiRjSmPpGv3FOhl9fsBPjupZBEIuoMWOC8GXK/73DHxwmfNmN7C9+sIi4RBcjEeQ5F5FHZ"; RSA rs2 = new RSA(PRIVATE_KEY, null); String a = "2707F9FD4288CEF302C972058712F24A5F3EC62C5A14AD2FC59DAB93503AA0FA17113A020EE4EA35EB53F"+ "75F36564BA1DABAA20F3B90FD39315C30E68FE8A1803B36C29029B23EB612C06ACF3A34BE815074F5EB5AA3A"+ "C0C8832EC42DA725B4E1C38EF4EA1B85904F8B10B2D62EA782B813229F9090E6F7394E42E6F44494BB8"; byte[] aByte = HexUtil.decodeHex(a); byte[] decrypt3 = rs2.decrypt(aByte,KeyType.PrivateKey); String encode1 = Base64.encode(decrypt3); String txt = new String(decoder.decodeBuffer(encode1)); System.out.println("解密后的文本信息:" + txt); //虎头闯杭州,多抬头看天,切勿只管种地 } }
四、摘要加密算法
摘要算法是一种能产生特殊输出格式的算法,这种算法的特点是:无论用户输入什么长度的原始数据,经过计算后输出的密文都是固定产的长度的。这种算法的原理是根据一定的运算规则对原数据进行某种形式的提取,这种提取就是摘要,被摘要的数据内容与原数据有密切的联系,只要原数据稍有改变,输出的“摘要”便完全不同,因此,基于这种原理的算法便能对数据完整性提供较为健全的保障。
但是由于输出的密文是提取数据经过处理的定长值,所以它已经不能还原数据,即消息摘要算法是不可逆的,理论上无法通过反向运算取得原数据内容,因此它通常只能采用来做数据完整性验证。
代码示例:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15to18</artifactId>
<version>1.66</version>
</dependency>
import cn.hutool.crypto.digest.DigestAlgorithm; import cn.hutool.crypto.digest.DigestUtil; import cn.hutool.crypto.digest.Digester; public class HutoolDegister { public static void main(String[] args) { //获取摘要 //MD5 String testStr = "5393554e94bf0eb6436f240a4fd71282"; //方式一 Digester md5 = new Digester(DigestAlgorithm.MD5); String str = md5.digestHex(testStr); System.out.println(str); //c3b68dca7f530043db5590f8c5e53a1a //方式二 String string = DigestUtil.md5Hex(testStr); System.out.println(string); //c3b68dca7f530043db5590f8c5e53a1a //SM3 Digester digester = DigestUtil.digester("sm3"); String digestHex = digester.digestHex(testStr); System.out.println(digestHex); //73bea8ca42b88469ebd8221896636db83fb0297c5cdaf98787344c07abf480dd } }
五、消息认证算法-HMac
HMAC,全称为"Hash Message Authentication Code", 中文名“散列消息鉴别码”,主要是利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出。一般的,消息鉴别码用于验证传输于两个共同享有一个密钥的单位之间的消息。HMAC可以与任何迭代散列函数捆绑使用。MD5和SHA-1就是这种散列函数。HMAC还可以使用一个用于计算和确认消息鉴别值得密钥。