数据加解密方案选择(RSA+AES)

为什么要对数据加密

理由很简单,为了安全。
因为之前一直在赶项目,没有对传输的数据做处理,导致我这边通过抓包软件直接能看到我请求发的是什么数据,服务端给我返回的数据是什么。

而且可以通过抓包软件修改响应数据返回给客户端,这样一来,客户端实际上接收到的数据并不是服务端给我的源数据,而是被第三者修改过的数据,如此一来,数据传输的安全就很有必要了。

那如何保证数据传输的安全呢?
总体要做到一下两点

1. 保证传输的数据是经过加密或者编码过的,即使有人通过抓包软件抓取到数据,也看不懂或者很难解开的。
2. 要能够确定接收到的数据没有经过篡改,也就是确认发送者的身份

虽然说没有绝对的安全,但是做到以上两点,我们能够极大程度的提高数据的安全性以及对身份的确定性


加密算法的选择

市面上的加密算法众多,但是就目前来讲加密大致分为以下两种:

1. 对称加密
2. 非对称加密

关于对称加密和非对称加密的原理等文章有很多,这里我就不展开介绍了,可以看看下面的文章,都写的很好!
感谢以下文章作者的分享!

常用加密算法概述
浅谈常见的七种加密算法及实现
MD5算法和SHA-1算法
对称加密及AES加密算法
从支付宝SDK的支付流程理解什么是公钥和私钥,什么是加密和数字签名
非对称加密及RSA加密算法

这里我们就不再去纠结算法的原理是什么了,说实话,我也看不懂(很难受)
数据加解密方案选择(RSA+AES)

我们的目的就是选择一个合适的方案并且能够合理的用在项目中就行了。

所以,我们先来简单的根据上面的文章来总结一下加解密的相关知识

秘钥

下面的解释来自百度百科:
秘钥,即**,在密码学中,**(key,又常称金钥)是指某个用来完成加密、解密、完整性验证等密码学应用的秘密信息。在对称密码学(或称**密码学)中,加密和解密用的是同一个钥匙,因此钥匙需要保密。而在公钥密码学(或称非对称密码学)中,加密和解密用的钥匙不同:通常一个是公开的,称为公钥;另一个保密,称为私钥。


对称加密

加密和解密都是使用一个秘钥

优点: 对数据没有长度限制,加解密速度快
缺点: 秘钥的传输及保管是个问题,任何一方的秘钥泄漏都将导致数据的不安全

在众多的对称加密算法中,目前来讲AES是最好的,最安全的,因为它是最新出的。
一般来讲,新出的都会比以前的好。

数据加解密方案选择(RSA+AES)
不过需要注意的是,AES在不同的Android版本上需要注意兼容性的问题,这个后面再讲


非对称加密

非对称加密首先要生成一对秘钥,分为公钥和私钥
公钥和私钥能够相互解密
一般来讲,长度长的作为私钥,要放在服务端保管好,千万不能泄露。长度短的作为公钥,分发给客户端,公钥是公开的。
支付宝给我们提供了生成RSA秘钥的工具,一键生成RSA秘钥
需要的可以下载。
嫌麻烦的也可以使用在线生成RSA秘钥

注意事项:
生成的秘钥大概如下,根据你自己的需求生成
秘钥位数: 一般来讲秘钥的长度选择为1024位或2048位。2048位的安全性更高,支付宝也建议使用2048位来生成秘钥。不过这里有个坑,网上的大部分RSA工具类在使用2048位秘钥进行解密的时候都会报错,这个坑我们后面再来解决。
秘钥格式: 我们选择目前比较流行的PKCS#8即可,如果出现问题,就选择pkcs#1格式

数据加解密方案选择(RSA+AES)

说了这么多,我们来看看非对称秘钥的优缺点:

  • 优点:无需关心秘钥的传输问题,只要在服务端把私钥保管好即可
  • 缺点:加密速度慢,对加密的数据长度有限制

加密方案选择

好了,了解可加密的相关知识,下面我们来分几个安全等级来排列一下下面的加密方案(安全等级依次提升)

方案一,使用Base64编码

这里我们引入一下编码,我们在使用加密的时候一般都要对加密后的数据进行一下编码,防止传输的过程中出现乱码的情况。
最常用的就是Base64编码了,Base64不算是加密,只是把字符经过编码变成不可读一串文字。
如果你的项目对安全根本没有什么要求,你就可以使用编码的方式,简单省事。但是这个方式只是比“裸奔”好那么一点,可以防止大部分小白用户吧。

方案二,双方约定好密码,使用AES加密

这种方案要求服务端和客户端约定好加密的密码,两端分别保留,在处理数据时就用本地约定好的密码对数据进行加解密。
这中方案能应付一些对安全要求不是很高的项目。由于密码是分别放在两端的,一些别有用心之心如果通过一些手段(例如Android端通过反编译或者逆向)获取到了密码,那么,数据安全也就是空谈了,可以直接通过 在线AES加密解密 网站或者写个程序**传输的数据了。
在线AES加密解密 这个网站我们可以收藏一下,后面调试项目的时候很可能会用上。

方案三,使用AES加密,密码随机生成

这种方案可以在服务端和客户端中写一个随机函数,生成一个随机的密码,两端均通过这个随机密码进行加密,然后传输数据的时候把这个随机密码传输给对方(例如放到请求头中),对方用接收到的随机密码进行解密。

实际上这个方案有点掩耳盗铃的意思,你都把解密的密码放到请求头中去了,人家一抓包很容易就获取到密码,甚至比方案二还要容易。

方案四,RSA结合AES进行加密,实现对服务端的单向认证

我们知道了RSA虽然能过做到身份验证,但是其加密速度较慢,并且不适合对大数据进行加密。
那么,单纯的使用RSA加密肯定是不可取的。
而AES的加密速度快且对加密数据没有大小限制,但是,秘钥的传输及管理是个问题,上面我们已经举过例子了。
那么,我们把两者结合起来取长补短不就好了吗?

我们可以这样:
以服务端给客户端传输数据为例

  1. 服务端生成一对RSA秘钥,私钥放在服务端,公钥下发给客户端
  2. 服务端使用随机函数生成AES加密要用的key
  3. 服务端使用随机的key对要传输的数据用AES进行加密
  4. 使用服务端的私钥对生成的随机Key进行加密。这里我为什么更倾向于使用RSA加密而不是签名呢?因为我个人觉得签名的话还要把签名的数据和加密后的数据一起传给客户端,会增加传输数据的大小,其实,只要是客户端能够成功的解密,实际上就已经能够确认服务端的身份了。如果别修改过后重新加密再传输给你,你是肯定解密失败的。前提是服务端私钥没有泄漏
  5. 服务端将使用AES加密的数据以及使用RSA加密的随机key一起发给客户端
  6. 客户端拿到数据后,先使用公钥对加密的随机key进行解密,解密成功即可确定是服务端发来的数据,没有经过他人修改,然后使用解密成功的随机key对使用AES加密的数据进行解密,获取最终的数据

这种方案实际上已经很安全了,实现了对服务端身份的单向认证以及对传输数据的加密,基本上可以应付绝大部分的项目了

方案五,RSA结合AES,实现双向验证

方案四实际上已经足够安全,实现了客户端对服务端的身份验证,但是如果你的服务端也要对客户端的身份进行验证,那么,你可以使用这个方案。

该方案实际上就是在方案四的基础上多了一对RSA秘钥,要求服务端和客户端都生成一对秘钥,服务端保管好自己生成的私钥,把公钥给客户端,客户端也保管好自己生成的私钥,把公钥给服务端。

大概流程如下;
本次以客户端给服务端传输数据为例

  1. 两端均生成一对RSA秘钥,各自保管好私钥,把公钥发给对方
  2. 客户端使用随机函数生成AES加密要用的key
  3. 客户端使用随机的key对要传输的数据用AES进行加密
  4. 客户端使用私钥对生成的随机Key进行加密。
  5. 客户端将使用AES加密的数据以及使用客户端私钥加密的随机key一起发给服务端
  6. 服务端拿到数据后,先使用客户端提供的公钥对加密的随机key进行解密,解密成功即可确认客户端的身份,没有经过他人修改,然后使用解密成功的随机key对使用AES加密的数据进行AES解密,获取最终的数据

服务端给客户端返回数据也是类似。
总结来讲就是:

  1. 两端各自用自己的RSA私钥对AES随机key进行加密
  2. 两端各自使用对方提供的RSA公钥对加密的随机Key数据进行解密
  3. 剩下的都一样,就是使用解密的得到的AES密码进行解密了

基本上加密的方案就这么多,足够你使用了,选一个适合你项目的即可,本篇博客主要就是介绍加密方案的选择,下一篇博客,我们来代码进行实战,以及解决实战中遇到的坑

Android完美使用RSA2结合AES对数据进行加密(兼容RSA2 SHA256WithRSA,可使用2048长度的秘钥,AES Android各版本通用)


如果你觉得本文对你有帮助,麻烦动动手指顶一下,算是对本文的一个认可,如果文中有什么错误的地方,还望指正,转载请注明转自喻志强的博客 ,谢谢!