RSA非对称加密(附工具类Util)

您所在的位置:网站首页 对称密码算法是什么 RSA非对称加密(附工具类Util)

RSA非对称加密(附工具类Util)

2023-06-14 00:35| 来源: 网络整理| 查看: 265

文章目录 非对称加密是什么非对称加密通信流程RSA非对称加密算法非对称加密工具类Util及案例演示

        之前写过一篇关于DES对称加密的帖子,感兴趣的小伙伴可以去看看:DES对称加密算法

今天主要聊聊什么是非对称加密,以及它是如何实现的。

一、非对称加密是什么?

非对称加密(asymmetric cryptography),也称为公开密钥加密(Public-key cryptography),是密码学的一种算法,它需要两个密钥,一个是公开密钥,另一个是私有密钥。顾名思义,公钥可以任意对外发布;而私钥必须由用户自行严格秘密保管,绝不透过任何途径向任何人提供,也不会透露给要通信的另一方,即使他被信任。

非对称加密的重要性质:

1.加密的双向性

加密具有双向性,即公钥和私钥中的任一个均可用作加密,此时另一个则用作解密。

使用其中一个密钥把明文加密后所得的密文,只能用相对应的另一个密钥才能解密得到原本的明文,甚至连最初用来加密的密钥也不能用作解密,这是非对称加密最重要的性质或者说特点。

2.公钥无法推导出私钥 

必须确保使用公钥无法推导出私钥,至少妄想使用公钥推导私钥必须在计算上是不可行的,否则安全性将不复存在。

虽然两个密钥在数学上相关,但如果知道了公钥,并不能凭此计算出私钥;因此公钥可以公开,任意向外发布;而私钥不公开,绝不通过任何途径向任何人提供。

在对称密码中,由于加密和解密的密钥是相同的,因此必须向接收者配送密钥。用于解密的密钥必须被配送给接收者,这一问题称为密钥配送问题。如果使用非对称加密,则无需向接收者配送用于解密的密钥,这样就解决了密钥配送的问题。

非对称加密中,密钥分为加密密钥和解密密钥两种。发送者用加密密钥对消息进行加密,接收者用解密密钥对密文进行解密。需理解公钥密码,清楚地分加密密钥和解密密钥是非常重要的。加密密钥是发送者加密时使用的,而解密密钥则是接收者解密时使用的。

3.加密密钥和解密密钥的区别

发送者只需要加密密钥接收者只需要解密密钥解密密钥不可以被窃听者获取加密密钥被窃听者获取也没关系

也就是说,解密密钥从一开始就是由接收者自己保管的,因此只要将加密密钥发给发送者就可以解决密钥配送问题了,而根本不需要配送解密密钥。

非对称加密中,加密密钥一般是公开的。真是由于加密密钥可以任意公开,因此该密钥被称为公钥(pulickey)。相对地解密密钥是绝对不能公开的,这个密钥只能由你自己来使用,因此称为私钥(privatekey)。私钥不可以被别人知道,也不可以将它发送给别人。

公钥和私钥是"一一对应的",一对公钥和私钥统称为密钥对(keypair)。由公钥进行加密的密文,必须使用与该公钥配对的私钥才能解密。密钥对中的两个密钥之间具有非常密切的的关系(数学上的关系)。因此公钥和私钥不能分别单独生成。

PS:公钥密码的使用者需要生成一个包括公钥和私钥的密钥对,其中公钥会被发送给别人,而私钥则仅供自己使用。

二、非对称加密通信流程

举例:假设士兵A要给军官B发一条信息,A是发送者,B是接收者,黑客C想窃听A和B之间的通讯内容。

1.军官B生成一个包含公钥和私钥的密钥对(私钥由B自行妥善保管)

2.军官B将自己的公钥发送给士兵A,表示B请A用这个公钥对消息进行加密并发送给他。但此时公钥被黑客C截获(没关系,无伤大雅)。

3.士兵A用军官B的公钥对消息进行加密(加密后的消息只有B的私钥才能够解密。虽然A拥有B的公钥,但用B的公钥是无法对密文进行解密的)

4.士兵A将密文发送给军官B(密文也被黑客C截获,不过也没关系,C虽然拥有B的公钥,但是B的公钥是无法进行解密的)

5.军官B用自己的私钥对密文进行解密,获得最终的明文,详细可参考下图: 

A和B之间传输的信息有两个,一个是B的公钥,一个是B公钥加密的密文,由于B的私钥没有出现在通信内容中,因此C无法对密文进行解密。

三、RSA非对称加密算法

RSA是一种非对称加密算法,它的名字由三位开发者。即RonRivest、AdiShamir和LeonardAdleman 的姓氏的首字母组成的(Rivest-Shamir-Leonard)。

1.RSA加密

RSA的加密工程可以用下来公式来表达,如下:

也就是说,RSA的密文是对代表明文的数字的E次方求modN的结果。换句话说,就是将明文自己做E次乘法,然后将其结果除以N求余数,这个余数就是密文。 

RSA的加密是求明文的E次方modN,因此只要知道E和N这两个数,任何人都可以完成加密的运算。所以说E和N是RSA加密的密钥。也就是说E和N的组合就是公钥。

有一个很容易引起误解的地方需要大家注意一一E和N这两个数并不是密钥对(公钥和私钥的密钥对)。E和N两个数才组成了一个公钥,因此我们一般会写成 “公钥是(E,N)” 或者 “公钥是{E, N}" 这样的形式,将E和N用括号括起来。

2.RSA解密

RSA的解密和加密一样简单,可以用下面的公式来表达:

也就是说,对表示密文的数字的D次方求modN就可以得到明文。换句话说,将密文自己做D次乘法,在对其结果除以N求余数,就可以得到明文。

这里所使用的数字N和加密时使用的数字N是相同的。数D和数N组合起来就是RSA的解密密钥,因此D和N的组合就是私钥。只有知道D和N两个数的人才能够完成解密的运算。

大家应该已经注意到,在RSA中,加密和解密的形式是相同的。加密是求 "E次方的mod N”,而解密则是求 "D次方的modN”,这真是太美妙了。

当然,D也并不是随便什么数都可以的,作为解密密钥的D,和数字E有着相当紧密的联系。否则,用E加密的结果可以用D来解密这样的机制是无法实现的。

PS:顺便说一句,D是解密〈Decryption)的首字母,N是数字(Number)的首字母。

四、RSA工具类Util RsaTestUtils.java package com.st.microservice.billcenter.infrastructure.util; import org.apache.commons.codec.binary.Base64; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import java.nio.charset.StandardCharsets; import java.security.*; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.HashMap; import java.util.Map; /** * @description: RSA加密工具类 * @author: admin */ public class RsaTestUtils { public static void main(String[] args) { //生成公钥和私钥 Map keyMap = genKeyPair(); //加密字符串 String content = "我是原文啊!132456789"; System.out.println("加密前内容:" + content); System.out.println("随机生成的公钥为:" + keyMap.get(0)); System.out.println("随机生成的私钥为:" + keyMap.get(1)); String messageEn = encrypt(content, keyMap.get(0)); System.out.println("加密后的内容为:" + messageEn); String messageDe = decrypt(messageEn, keyMap.get(1)); System.out.println("还原后的内容为:" + messageDe); } /** * 随机生成密钥对 */ public static Map genKeyPair() { // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象 KeyPairGenerator keyPairGen = null; try { keyPairGen = KeyPairGenerator.getInstance("RSA"); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } // 初始化密钥对生成器,密钥大小为96-1024位 assert keyPairGen != null; keyPairGen.initialize(1024, new SecureRandom()); // 生成一个密钥对,保存在keyPair中 KeyPair keyPair = keyPairGen.generateKeyPair(); // 得到私钥 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 得到公钥 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded())); // 得到私钥字符串 String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded()))); // 将公钥和私钥保存到Map Map keyMap = new HashMap(); // 0表示公钥 keyMap.put(0, publicKeyString); // 1表示私钥 keyMap.put(1, privateKeyString); return keyMap; } /** * RSA公钥加密 * * @param str 加密字符串 * @param publicKey 公钥 * @return 密文 */ public static String encrypt(String str, String publicKey) { // base64编码的公钥 byte[] decoded = Base64.decodeBase64(publicKey); RSAPublicKey pubKey; String outStr = null; try { pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded)); Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, pubKey); outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes(StandardCharsets.UTF_8))); } catch (InvalidKeySpecException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException | NoSuchPaddingException | NoSuchAlgorithmException e) { e.printStackTrace(); } // RSA加密 return outStr; } /** * RSA私钥解密 * * @param str 加密字符串 * @param privateKey 私钥 * @return 明文 */ public static String decrypt(String str, String privateKey) { //64位解码加密后的字符串 byte[] inputByte = Base64.decodeBase64(str.getBytes(StandardCharsets.UTF_8)); //base64编码的私钥 byte[] decoded = Base64.decodeBase64(privateKey); RSAPrivateKey priKey; //RSA解密 Cipher cipher; String outStr = null; try { priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded)); cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, priKey); outStr = new String(cipher.doFinal(inputByte)); } catch (InvalidKeySpecException | NoSuchAlgorithmException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException e) { e.printStackTrace(); } return outStr; } }

实例结果:

简单的应用场景: 先生成一对公私钥匙对,前端拿公钥加密,后端拿私钥解密。

如果这篇文章对您有所帮助,或者有所启发的话,求一键三连:点赞、评论、收藏➕关注,您的支持是我坚持写作最大的动力。 


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3