使用Hutool处理RSA等非对称加密
使用Hutool处理RSA等非对称加密
路小磊 发表于3个月前
使用Hutool处理RSA等非对称加密
  • 发表于 3个月前
  • 阅读 1581
  • 收藏 94
  • 点赞 3
  • 评论 22
摘要: Hutool工具是一个国产开源Java工具集,旨在简化Java开发中繁琐的过程,Hutool-crypto模块便是针对JDK加密解密做了大大简化。此文主要介绍利用Hutool-crypto简化非对称加密解密。对于非对称加密,最常用的就是RSA和DSA,在Hutool中使用`AsymmetricCrypto`对象来负责加密解密。

介绍

Hutool工具是一个国产开源Java工具集,旨在简化Java开发中繁琐的过程,Hutool-crypto模块便是针对JDK加密解密做了大大简化。

此文主要介绍利用Hutool-crypto简化非对称加密解密。

对于非对称加密,最常用的就是RSA和DSA,在Hutool中使用AsymmetricCrypto对象来负责加密解密。

非对称加密有公钥和私钥两个概念,私钥自己拥有,不能给别人,公钥公开。根据应用的不同,我们可以选择使用不同的密钥加密:

  1. 签名:使用私钥加密,公钥解密。用于让所有公钥所有者验证私钥所有者的身份并且用来防止私钥所有者发布的内容被篡改,但是不用来保证内容不被他人获得。

  2. 加密:用公钥加密,私钥解密。用于向公钥所有者发布信息,这个信息可能被他人篡改,但是无法被他人获得。

使用

引入Hutool

<dependency>
    <groupId>com.xiaoleilu</groupId>
    <artifactId>hutool-all</artifactId>
    <version>3.1.0</version>
</dependency>

在非对称加密中,我们可以通过AsymmetricCrypto(AsymmetricAlgorithm algorithm)构造方法,通过传入不同的算法枚举,获得其加密解密器。

当然,为了方便,我们针对最常用的RSA和DSA算法构建了单独的对象:RSADSA

基本使用

我们以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);
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);
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对象,也可以使用encryptStrdecryptStr加密解密为字符串

案例

案例一:

已知私钥和密文,如何解密密文?

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);
Assert.assertEquals("虎头闯杭州,多抬头看天,切勿只管种地", StrUtil.str(decrypt, CharsetUtil.CHARSET_UTF_8));
共有 人打赏支持
路小磊
粉丝 209
博文 49
码字总数 36545
作品 5
评论 (22)
小帅帅丶
支持直接16进制的公私钥 转PrivateKey PublicKey吗?
huyong5802

引用来自“小帅帅丶”的评论

支持直接16进制的公私钥 转PrivateKey PublicKey吗?
16进制你可以转10进制之后再转byte数组这样应该就可以拿到公私钥对象了
huyong5802
支持下楼主,还有一个加解密相关的公共包,也可以推荐下:http://springcryptoutils.com/
路小磊

引用来自“小帅帅丶”的评论

支持直接16进制的公私钥 转PrivateKey PublicKey吗?
使用HexUtil转为byte即可。
路小磊

引用来自“huyong5802”的评论

支持下楼主,还有一个加解密相关的公共包,也可以推荐下:http://springcryptoutils.com/
看了一眼。基于Spring的,Hutool-crypto只依赖JDK哦~~更加灵活。
小帅帅丶

引用来自“小帅帅丶”的评论

支持直接16进制的公私钥 转PrivateKey PublicKey吗?

引用来自“路小磊”的评论

使用HexUtil转为byte即可。
好吧。我发下我的实现把。不是那么直接转的。String big1 = hexString;
      String big2 = "10001";
      RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(new BigInteger(big1,16), new BigInteger(big2,16));
      KeyFactory factory = KeyFactory.getInstance("RSA");
      RSAPublicKey rsaPublicKey = (RSAPublicKey) factory.generatePublic(rsaPublicKeySpec);
小帅帅丶

引用来自“小帅帅丶”的评论

支持直接16进制的公私钥 转PrivateKey PublicKey吗?

引用来自“huyong5802”的评论

16进制你可以转10进制之后再转byte数组这样应该就可以拿到公私钥对象了
nonono。看我的实现:String big1 = hexString;
      String big2 = "10001";
      RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(new BigInteger(big1,16), new BigInteger(big2,16));
      KeyFactory factory = KeyFactory.getInstance("RSA");
      RSAPublicKey rsaPublicKey = (RSAPublicKey) factory.generatePublic(rsaPublicKeySpec);
路小磊

引用来自“小帅帅丶”的评论

支持直接16进制的公私钥 转PrivateKey PublicKey吗?

引用来自“路小磊”的评论

使用HexUtil转为byte即可。

引用来自“小帅帅丶”的评论

好吧。我发下我的实现把。不是那么直接转的。String big1 = hexString;
      String big2 = "10001";
      RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(new BigInteger(big1,16), new BigInteger(big2,16));
      KeyFactory factory = KeyFactory.getInstance("RSA");
      RSAPublicKey rsaPublicKey = (RSAPublicKey) factory.generatePublic(rsaPublicKeySpec);
还是我理解不深。并未考虑N、e、d这三个特征值得情况。感谢你的实现。Hutool3.1.1中将支持此类型。
小帅帅丶

引用来自“路小磊”的评论

引用来自“小帅帅丶”的评论

支持直接16进制的公私钥 转PrivateKey PublicKey吗?

引用来自“路小磊”的评论

使用HexUtil转为byte即可。

引用来自“小帅帅丶”的评论

好吧。我发下我的实现把。不是那么直接转的。String big1 = hexString;
      String big2 = "10001";
      RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(new BigInteger(big1,16), new BigInteger(big2,16));
      KeyFactory factory = KeyFactory.getInstance("RSA");
      RSAPublicKey rsaPublicKey = (RSAPublicKey) factory.generatePublic(rsaPublicKeySpec);
还是我理解不深。并未考虑N、e、d这三个特征值得情况。感谢你的实现。Hutool3.1.1中将支持此类型。

回复@路小磊 :我这个主要是因为iot里面返回的16进制不包含前面部分的内容。才会可能需要这样实现。接下来作者来国密的把。RSA也可以加上签名,验签方法
路小磊

引用来自“小帅帅丶”的评论

引用来自“路小磊”的评论

引用来自“小帅帅丶”的评论

支持直接16进制的公私钥 转PrivateKey PublicKey吗?

引用来自“路小磊”的评论

使用HexUtil转为byte即可。

引用来自“小帅帅丶”的评论

好吧。我发下我的实现把。不是那么直接转的。String big1 = hexString;
      String big2 = "10001";
      RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(new BigInteger(big1,16), new BigInteger(big2,16));
      KeyFactory factory = KeyFactory.getInstance("RSA");
      RSAPublicKey rsaPublicKey = (RSAPublicKey) factory.generatePublic(rsaPublicKeySpec);
还是我理解不深。并未考虑N、e、d这三个特征值得情况。感谢你的实现。Hutool3.1.1中将支持此类型。

回复@路小磊 :我这个主要是因为iot里面返回的16进制不包含前面部分的内容。才会可能需要这样实现。接下来作者来国密的把。RSA也可以加上签名,验签方法
感谢提供思路。现阶段Hutool只是对hash算法、对称加密、非对称加密针对JDK做简单包装,简化开发。很多概念并不熟悉。后续Hutool会强化这个模块。欢迎提供思路~~
mzllon
2048支持么?
LeoXu
您好,请教个问题,采用RSA算法,对于待加密内容的长度有限制不?
loyal
对于加解密, 还是没有更简单~
路小磊

引用来自“mzllon”的评论

2048支持么?
什么是2048?
路小磊

引用来自“leoxu”的评论

您好,请教个问题,采用RSA算法,对于待加密内容的长度有限制不?
因为加密解密都是在内存中进行,应该不能太大。你可以试下。
路小磊

引用来自“loyal”的评论

对于加解密, 还是没有更简单~
你想一个方法搞定?我也是这么想的。但是非对称加密涉及概念较多,都是必须项。我认为这样是最好理解的。如果有更好的思路欢迎提供~~
边城

引用来自“leoxu”的评论

您好,请教个问题,采用RSA算法,对于待加密内容的长度有限制不?
RSA 对内容长度没限制,但是非对称算法超级慢,所以一般是会用对称加密算法来加密内容,用非对称算法来加密对称算法的密钥
oschina小吕

引用来自“路小磊”的评论

引用来自“mzllon”的评论

2048支持么?
什么是2048?

他问2048长度的密钥
highMan
谢谢分享
RainMax
原来java没有内置rsa加密的类么。dot net是有内置的。
×
路小磊
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: