【转载】前后端分离项目接口数据加密的秘钥交换逻辑(RSA、AES)

转自:https://www.renfei.net/posts/1003346

在前后端分离的项目中,往往需要传输一些敏感的信息,例如密码、金额等,签名验签算法只能保证数据不被篡改,但是却无法对数据进行保密,如果用户输入的密码明文传输,就会被网络中的节点截获,虽然大部分网络运营商并不会去截取网络传输的内容,但是不能排除用户连接的WiFi网络是不是钓鱼网络,所以在传输敏感信息的时候需要加密,本文就讨论如何安全的让客户端和服务器交换秘钥。

加密算法的选择,RSA还是AES

涉及到加解密就涉及到加解密算法的选择,比较常见的是非对称加密RSA和对称加密AES,它们各有什么特点和选择呢?我们逐个说明

RSA非对称加密

RSA算法会生成两个秘钥,一个公钥,一个私钥,使用公钥加密的数据必须使用私钥解密,这样的好处是只有服务器有私钥,其他人无法解密。但是他有个非常致命的弱点,那就是加密内容的长度不能大于秘钥长度,以RSA 1024为例,PKCS#1建议的padding占用了11个字节,这样,128字节(1024bits)-减去11字节是117字节,也就是说我们使用RSA 1024最多只能加密117字节的内容,如果超过这个内容就会报错,可往往我们要传输的内容非常庞大,我们也不能无限制的增加秘钥长度。而且在移动设备上性能有限,并不适合大量加解密运算。所以我们还需AES。

AES对称加密

因为上述的RSA受到秘钥长度的加密限制,我们还需要AES加密,AES的优点是无论明文有多大它都可以加解密。但是缺点是它不区分私钥和公钥,密钥只有一个,任何知道秘钥的人都可以加解密信息。

RSA和AES结合使用取长补短

RSA和AES都有各自的优缺点,如果我们把他们结合使用就可以取长补短,我们可以使用RSA来保护AES的秘钥,这样可以保证只有双方知道AES的秘钥,并且AES可以加密任何长度的信息,这样就解决了它们各自的缺点。

秘钥交换逻辑

一、客户端向服务器端申请RSA公钥;服务器生成一个RSA秘钥对,将公钥发送给客户端。我们起名为「Server公钥」

二、客户端收到服务器给出的「Server公钥」,客户端生成自己的RSA秘钥对,我们起名为「Client公钥」,客户端使用「Server公钥」去加密自己的「Client公钥」,发送给服务器

三、服务器收到客户端的请求,使用「Server私钥」解密得到「Client公钥」

四、服务器生成一个「AES秘钥」,使用「Client公钥」加密「AES秘钥」发送给客户端

五、客户端使用「Client私钥」解密得到「AES秘钥」

后续双方的交互使用「AES秘钥」进行加解密,秘钥交换流程完成。

秘钥交换逻辑

实例代码:

  1. @Test
  2. public void reaTest() {
  3.     //服务器端的
  4.     Map<Integer, String> serverKeyMap = RSAUtils.genKeyPair(2048);
  5.     //客户端的
  6.     Map<Integer, String> clientKeyMap = RSAUtils.genKeyPair(1024);
  7.     String clientPubKey = clientKeyMap.get(0);
  8.     try {
  9.         //客户端使用服务器公钥加密自己的公钥
  10.         String encrypt = RSAUtils.encrypt(clientPubKey, serverKeyMap.get(0));
  11.         //服务器端使用自己的私钥解密拿到客户端公钥
  12.         Assert.assertEquals(clientPubKey, RSAUtils.decrypt(encrypt, serverKeyMap.get(1)));
  13.         String AESkey = "aeskey123456";
  14.         //使用客户端的公钥加密AES的秘钥
  15.         String encryptAES = RSAUtils.encrypt(AESkey, clientPubKey);
  16.         //客户端用自己的私钥解密拿到AES的秘钥
  17.         Assert.assertEquals(AESkey, RSAUtils.decrypt(encryptAES, clientKeyMap.get(1)));
  18.     } catch (Exception ex) {
  19.         ex.printStackTrace();
  20.         Assert.assertNull(ex);
  21.     }
  22. }
点赞

发表回复

电子邮件地址不会被公开。必填项已用 * 标注