概述
Hutool-crypto概述
加密分为三种:
- 对称加密(symmetric),例如:AES、DES等
- 非对称加密(asymmetric),例如:RSA、DSA等
- 摘要加密(digest),例如:MD5、SHA-1、SHA-256、HMAC等
hutool-crypto针对这三种加密类型分别封装,并提供常用的大部分加密算法。
对于非对称加密,实现了:
- RSA
- DSA
对于对称加密,实现了:
- AES
- ARCFOUR
- Blowfish
- DES
- DESede
- RC2
- PBEWithMD5AndDES
- PBEWithSHA1AndDESede
- PBEWithSHA1AndRC2_40
对于摘要算法实现了:
- MD2
- MD5
- SHA-1
- SHA-256
- SHA-384
- SHA-512
- HmacMD5
- HmacSHA1
- HmacSHA256
- HmacSHA384
- HmacSHA512
其中,针对常用到的算法,模块还提供SecureUtil
工具类用于快速实现加密。
加密解密工具-SecureUtil
介绍
SecureUtil
主要针对常用加密算法构建快捷方式,还有提供一些密钥生成的快捷工具方法。
方法介绍
对称加密
SecureUtil.aes
-
摘要算法
SecureUtil.md5
SecureUtil.sha1
SecureUtil.hmac
SecureUtil.hmacMd5
-
非对称加密
SecureUtil.rsa
-
UUID
SecureUtil.simpleUUID
方法提供无“-”的UUID密钥生成
SecureUtil.generateKey
针对对称加密生成密钥SecureUtil.generateKeyPair
生成密钥对(用于非对称加密)SecureUtil.generateSignature
生成签名(用于非对称加密)
其它方法为针对特定加密方法的一些密钥生成和签名相关方法,详细请参阅API文档。
对称加密-SymmetricCrypto
介绍
对称加密(也叫私钥加密)指加密和解密使用相同密钥的加密算法。有时又叫传统密码算法,就是加密密钥能够从解密密钥中推算出来,同时解密密钥也可以从加密密钥中推算出来。而在大多数的对称算法中,加密密钥和解密密钥是相同的,所以也称这种加密算法为秘密密钥算法或单密钥算法。它要求发送方和接收方在安全通信之前,商定一个密钥。对称算法的安全性依赖于密钥,泄漏密钥就意味着任何人都可以对他们发送或接收的消息解密,所以密钥的保密性对通信的安全性至关重要。
对于对称加密,封装了JDK的,具体介绍见:https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#KeyGenerator
- AES (默认
AES/ECB/PKCS5Padding
) - ARCFOUR
- Blowfish
- DES (默认
DES/ECB/PKCS5Padding
) - DESede
- RC2
- PBEWithMD5AndDES
- PBEWithSHA1AndDESede
- PBEWithSHA1AndRC2_40
使用
通用使用
以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);
//解密为字符串
String decryptStr = aes.decryptStr(encryptHex, CharsetUtil.CHARSET_UTF_8);
DESede实现
String content = "test中文";
byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.DESede.getValue()).getEncoded();
SymmetricCrypto des = new SymmetricCrypto(SymmetricAlgorithm.DESede, key);
//加密
byte[] encrypt = des.encrypt(content);
//解密
byte[] decrypt = des.decrypt(encrypt);
//加密为16进制字符串(Hex表示)
String encryptHex = des.encryptHex(content);
//解密为字符串
String decryptStr = des.decryptStr(encryptHex);
AES封装
AES全称高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法。
对于Java中AES的默认模式是:AES/ECB/PKCS5Padding
,如果使用CryptoJS,请调整为:padding: CryptoJS.pad.Pkcs7
快速构建
String content = "test中文";
// 随机生成密钥
byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.AES.getValue()).getEncoded();
// 构建
AES aes = SecureUtil.aes(key);
// 加密
byte[] encrypt = aes.encrypt(content);
// 解密
byte[] decrypt = aes.decrypt(encrypt);
// 加密为16进制表示
String encryptHex = aes.encryptHex(content);
// 解密为字符串
String decryptStr = aes.decryptStr(encryptHex, CharsetUtil.CHARSET_UTF_8);
自定义模式和偏移
AES aes = new AES(Mode.CTS, Padding.PKCS5Padding, "0CoJUm6Qyw8W8jud".getBytes(),
"0102030405060708".getBytes());
DES封装
DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,Java中默认实现为:
DES/CBC/PKCS5Padding
DES使用方法与AES一致,构建方法为:快速构建
byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.DES.getValue()).getEncoded();
DES des = SecureUtil.des(key);
自定义模式和偏移
DES des = new DES(Mode.CTS, Padding.PKCS5Padding, "0CoJUm6Qyw8W8jud".getBytes(),
"01020304".getBytes());
SM4
在4.2.1之后,Hutool借助Bouncy Castle库可以支持国密算法,以SM4为例:
我们首先需要引入Bouncy Castle库:<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.60</version>
</dependency>
然后可以调用SM4算法,调用方法与其它算法一致:
String content = "test中文";
SymmetricCrypto sm4 = new SymmetricCrypto("SM4");
String encryptHex = sm4.encryptHex(content);
String decryptStr = sm4.decryptStr(encryptHex, CharsetUtil.CHARSET_UTF_8);//test中文
同样我们可以指定加密模式和偏移:
String content = "test中文";
SymmetricCrypto sm4 = new SymmetricCrypto("SM4/ECB/PKCS5Padding");
String encryptHex = sm4.encryptHex(content);
String decryptStr = sm4.decryptStr(encryptHex, CharsetUtil.CHARSET_UTF_8);//test中文
非对称加密-AsymmetricCrypto
介绍
对于非对称加密,最常用的就是RSA和DSA,在Hutool中使用AsymmetricCrypto
对象来负责加密解密。
非对称加密有公钥和私钥两个概念,私钥自己拥有,不能给别人,公钥公开。根据应用的不同,我们可以选择使用不同的密钥加密:
- 签名:使用私钥加密,公钥解密。用于让所有公钥所有者验证私钥所有者的身份并且用来防止私钥所有者发布的内容被篡改,但是不用来保证内容不被他人获得。
- 加密:用公钥加密,私钥解密。用于向公钥所有者发布信息,这个信息可能被他人篡改,但是无法被他人获得。
Hutool封装了JDK的,详细见https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#KeyPairGenerator
- RSA
- DSA
- EC
使用
在非对称加密中,我们可以通过AsymmetricCrypto(AsymmetricAlgorithm algorithm)
构造方法,通过传入不同的算法枚举,获得其加密解密器。
当然,为了方便,我们针对最常用的RSA和DSA算法构建了单独的对象:RSA
和DSA
。基本使用
我们以RSA为例,介绍使用RSA加密和解密 在构建RSA对象时,可以传入公钥或私钥,当使用无参构造方法时,Hutool将自动生成随机的公钥私钥密钥对:RSA rsa = new RSA();
//获得私钥
rsa.getPrivateKey()
rsa.getPrivateKeyBase64()
//获得公钥
rsa.getPublicKey()
rsa.getPublicKeyBase64()
//公钥加密,私钥解密
byte[] encrypt = rsa.encrypt(StrUtil.bytes("我是一段测试aaaa", CharsetUtil.CHARSET_UTF_8), KeyType.PublicKey);
byte[] decrypt = rsa.decrypt(encrypt, KeyType.PrivateKey);
//Junit单元测试
//Assert.assertEquals("我是一段测试aaaa", StrUtil.str(decrypt, CharsetUtil.CHARSET_UTF_8));
//私钥加密,公钥解密
byte[] encrypt2 = rsa.encrypt(StrUtil.bytes("我是一段测试aaaa", CharsetUtil.CHARSET_UTF_8), KeyType.PrivateKey);
byte[] decrypt2 = rsa.decrypt(encrypt2, KeyType.PublicKey);
//Junit单元测试
//Assert.assertEquals("我是一段测试aaaa", StrUtil.str(decrypt2, CharsetUtil.CHARSET_UTF_8));
对于加密和解密可以完全分开,对于RSA对象,如果只使用公钥或私钥,另一个参数可以为
null
自助生成密钥对
有时候我们想自助生成密钥对可以:
KeyPair pair = SecureUtil.generateKeyPair("RSA");
pair.getPrivate();
pair.getPublic();
自助生成的密钥对是byte[]形式,我们可以使用Base64.encode
方法转为Base64,便于存储为文本。
当然,如果使用RSA
对象,也可以使用encryptStr
和decryptStr
加密解密为字符串。
案例
案例一:
已知私钥和密文,如何解密密文?
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 rsa = new RSA(PRIVATE_KEY, null);
String a = "2707F9FD4288CEF302C972058712F24A5F3EC62C5A14AD2FC59DAB93503AA0FA17113A020EE4EA35EB53F"
+ "75F36564BA1DABAA20F3B90FD39315C30E68FE8A1803B36C29029B23EB612C06ACF3A34BE815074F5EB5AA3A"
+ "C0C8832EC42DA725B4E1C38EF4EA1B85904F8B10B2D62EA782B813229F9090E6F7394E42E6F44494BB8";
byte[] aByte = HexUtil.decodeHex(a);
byte[] decrypt = rsa.decrypt(aByte, KeyType.PrivateKey);
//Junit单元测试
//Assert.assertEquals("虎头闯杭州,多抬头看天,切勿只管种地", StrUtil.str(decrypt, CharsetUtil.CHARSET_UTF_8));
摘要加密-Digester和HMac
介绍
摘要算法介绍
摘要算法是一种能产生特殊输出格式的算法,这种算法的特点是:无论用户输入什么长度的原始数据,经过计算后输出的密文都是固定长度的,这种算法的原理是根据一定的运算规则对原数据进行某种形式的提取,这种提取就是摘要,被摘要的数据内容与原数据有密切联系,只要原数据稍有改变,输出的“摘要”便完全不同,因此,基于这种原理的算法便能对数据完整性提供较为健全的保障。
但是,由于输出的密文是提取原数据经过处理的定长值,所以它已经不能还原为原数据,即消息摘要算法是不可逆的,理论上无法通过反向运算取得原数据内容,因此它通常只能被用来做数据完整性验证。
HMAC介绍
HMAC,全称为“Hash Message Authentication Code”,中文名“散列消息鉴别码”,主要是利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出。一般的,消息鉴别码用于验证传输于两个共 同享有一个密钥的单位之间的消息。HMAC 可以与任何迭代散列函数捆绑使用。MD5 和 SHA-1 就是这种散列函数。HMAC 还可以使用一个用于计算和确认消息鉴别值的密钥。
Hutool支持的摘要算法类型
详细见:https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#MessageDigest
摘要算法
- MD2
- MD5
- SHA-1
- SHA-256
- SHA-384
-
Hmac算法
HmacMD5
- HmacSHA1
- HmacSHA256
- HmacSHA384
-
摘要算法抽象
摘要对象被抽象为两个对象:
Digester
- HMac
使用
Digester
以MD5为例:
当然,做为最为常用的方法,MD5等方法被封装为工具方法在Digester md5 = new Digester(DigestAlgorithm.MD5);
String digestHex = md5.digestHex(testStr);//5393554e94bf0eb6436f240a4fd71282
DigestUtil
中,以上代码可以进一步简化为:String md5Hex1 = DigestUtil.md5Hex(testStr);
//Junit单元测试
//Assert.assertEquals("5393554e94bf0eb6436f240a4fd71282", md5Hex1);
HMac
以HmacMD5为例:String testStr = "test中文";
byte[] key = "password".getBytes();
HMac mac = new HMac(HmacAlgorithm.HmacMD5, key);
String macHex1 = mac.digestHex(testStr);//b977f4b13f93f549e06140971bded384
SM3
在4.2.1之后,Hutool借助Bouncy Castle库可以支持国密算法,以SM3为例:
我们首先需要引入Bouncy Castle库:
然后可以调用SM3算法,调用方法与其它摘要算法一致:<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.60</version>
</dependency>
Digester digester = DigestUtil.digester("sm3");
//136ce3c86e4ed909b76082055a61586af20b4dab674732ebd4b599eef080c9be
String digestHex = digester.digestHex("aaaaa");
签名和验证-Sign
介绍
Hutool针对java.security.Signature
做了简化包装,包装类为:Sign
,用于生成签名和签名验证。
对于签名算法,Hutool封装了JDK的,具体介绍见:https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#Signature
// The RSA signature algorithm
NONEwithRSA
// The MD2/MD5 with RSA Encryption signature algorithm
MD2withRSA
MD5withRSA
// The signature algorithm with SHA-* and the RSA
SHA1withRSA
SHA256withRSA
SHA384withRSA
SHA512withRSA
// The Digital Signature Algorithm
NONEwithDSA
// The DSA with SHA-1 signature algorithm
SHA1withDSA
// The ECDSA signature algorithms
NONEwithECDSA
SHA1withECDSA
SHA256withECDSA
SHA384withECDSA
SHA512withECDSA
使用
byte[] data = "我是一段测试字符串".getBytes();
Sign sign = SecureUtil.sign(SignAlgorithm.MD5withRSA);
//签名
byte[] signed = sign.sign(data);
//验证签名
boolean verify = sign.verify(data, signed);
国密算法工具-SmUtil
介绍
Hutool针对Bouncy Castle
做了简化包装,用于实现国密算法中的SM2、SM3、SM4。
国密算法工具封装包括:
- 非对称加密和签名:SM2
- 摘要签名算法:SM3
- 对称加密:SM4
使用
引入Bouncy Castle
依赖
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
说明
bcprov-jdk15on
的版本请前往Maven中央库搜索,查找对应JDK的版本。
非对称加密SM2
使用随机生成的密钥对加密或解密
String text = "我是一段测试aaaa";
SM2 sm2 = SmUtil.sm2();
// 公钥加密,私钥解密
String encryptStr = sm2.encryptBcd(text, KeyType.PublicKey);
String decryptStr = StrUtil.utf8Str(sm2.decryptFromBcd(encryptStr, KeyType.PrivateKey));
使用自定义密钥对加密或解密
String text = "我是一段测试aaaa";
KeyPair pair = SecureUtil.generateKeyPair("SM2");
byte[] privateKey = pair.getPrivate().getEncoded();
byte[] publicKey = pair.getPublic().getEncoded();
SM2 sm2 = SmUtil.sm2(privateKey, publicKey);
// 公钥加密,私钥解密
String encryptStr = sm2.encryptBcd(text, KeyType.PublicKey);
String decryptStr = StrUtil.utf8Str(sm2.decryptFromBcd(encryptStr, KeyType.PrivateKey));
摘要加密算法SM3
//结果为:136ce3c86e4ed909b76082055a61586af20b4dab674732ebd4b599eef080c9be
String digestHex = SmUtil.sm3("aaaaa");
对称加密SM4
```java String content = “test中文”; SymmetricCrypto sm4 = SmUtil.sm4();
String encryptHex = sm4.encryptHex(content); String decryptStr = sm4.decryptStr(encryptHex, CharsetUtil.CHARSET_UTF_8); ```