百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

java中的加密体系架构第一篇java中支持的常见的加密算法

toyiye 2024-06-06 22:12 13 浏览 0 评论

大家好,我是贠学文,点击右上方“关注”,每天为您分享java程序员需要掌握的知识点干货。

凌晨四点的背景

大家在做java开发的时候,用户的注册与登录,是一个最常见的功能了,但是就是这个最常见的功能,却隐含了一个很重要的安全性问题,就是用户的密码,如何安全的传输与存储?想解决这个问题,就要首先了解一下常见的加密算法,那我们今天就来讲下java中支持的一些常见的加密算法。注意,我们这里这讲不同的加密算法之间的一些安全性和效率上的差异,以及如何选择使用,不会去讲具体的算法,因为算法比较复杂,我们也不是专门做算法的,了解这些算法的意义也不大,有兴趣的可以自己去了解。

在讲加密算法之前,我们首先要清楚一个事情:这个世界上,并没有什么算法是绝对的安全,任何的加密算法都有被破解的可能。就拿https来说,大家都觉得https应该很安全了吧,但是https也不是绝对的安全,https的安全性,是建立在证书是可信任的前提下。如果黑客伪造了一个非法证书,并且诱导用户安装,客户端浏览器也验证通过,那么它还安全么?

所以我们利用加密算法做加密时,不要奢望可以达到绝对的安全,这个我们永远做不到,我们只能不断的提升安全级别,增大黑客攻击破解的难度和成本。但是这个安全级别,永远都达不到100%

一、什么是密钥、公钥、私钥

在谈到加密算法时,我们经常会听到三个名词:密钥、公钥、私钥。那这三者到底是什么呢?

举个例子,我通过系统,向银行发起一笔转账的请求,为了保证信息不被泄漏,我们通常会对一些关键字段加密,比如银行卡号字段、金额字段等等,或者对整段报文做加密。那我们希望,加密后的内容,只有银行可以解密,其它任何人都不能解密。为什么呢?我们可以想下,如果连银行都不能解密,它就无法知道我要转账的具体信息,自然也就无法转账。如果所有人都可以解密呢,那我们加密就没有意义了,任何的黑客拦截,都能获取到我们的信息,造成信息泄露。

那如何才能做到只有银行可以解密,其他人都不能解密呢?这个问题银行已经帮我们想到了,它会给我们一把钥匙,要求我们利用这把钥匙做加密,加密后的数据,只有利用同样的钥匙才可以解密。而同样的钥匙,只有银行自己有,其他人都没有,这样就达到了这个目的。

那这个钥匙,就是我们常常提到的密钥,在编码的过程中,它就是一段字符串(密钥)而已,银行把这个字符串(密钥)给到我们,我们利用这个字符串(密钥)加密,然后银行再利用这个字符串解密。

那这样其实还有个问题,如果银行在把密钥给我我们的过程中,被别人拦截了,那别人也就拥有了这个密钥。那我们在利用这个密钥加密后,别人也就可以破解了。为了解决这个问题,又引出了公钥和私钥的概念。

私钥,顾名思义,私人的钥匙,只有服务端自己可以拥有。公钥,任何人都可以拥有。公钥和私钥是成对出现的。利用公钥加密的数据,只能由对应的私钥可以做解密。理论上来说,公钥和私钥都可以做加密和解密。但是从实际情况下讲,都是公钥做加密,私钥做解密。因为公钥是对所有人都开发的,如果让私钥加密,公钥解密,那就任何人都可以做解密了,这样就失去加密的意义了。

那如何利用公钥和私钥来解决我们上面提到的问题呢?银行先生成一对公钥和私钥,然后把公钥发给我们,在发给我们的过程中,不需要担心拦截的问题,因为公钥本来就是公开的,任何人都可以拥有。然后我们拿到公钥后,利用公钥做加密,把加密后的数据发送给银行,银行就可以利用私钥解密,在这个过程中,也不需要担心拦截的问题,因为别人手里最多能拿到公钥,公钥是无法解密的。这样就解决了我们上面提到的问题。

但是还有一个问题,在这种模式下,如果黑客拦截了银行的公钥A,然后自己又生成了一对公钥B和私钥B,然后把拦截到的公钥A自己留下,再把自己生成的公钥B发给我们,我们无法知道我们接收到的公钥是银行的还是黑客的。那我们利用公钥B做加密,发送请求,黑客就可以利用私钥B去解密我们的数据了,然后对我们的数据做篡改,对篡改后的数据利用银行的公钥A加密,在发给银行。银行也不知道他接收到的数据,是我们自己发送的,还是黑客发送的,这样仍在会造成安全性问题。

要解决这个问题,就涉及到证书了,我们在这里先不说,我们后面讲到HTTPS的文章,会提到这个问题,这里,我们只需要了解 密钥、公钥、私钥的意义即可。

二、加密算法的分类

加密算法,可以分为不可逆算法和可逆算法,可逆算法又分为对称加密算法和非对称加密算法,具体如下图所示:

加密算法分类

二、不可逆加密算法

不可逆加密算法,即只能把明文加密成密文,不能将密文解密成明文。

2.1 不可逆加密算法的特点

1、对于不同长度的明文,都会加密成一个固定长度的密文。

2、对明文数据进行任何改动,哪怕只变得1个字节,所得到的密文都有很大区别。

2.2 不可逆算法的应用场景

1、密码等无需解密的字段的存储。因为像密码这样的字段,为了安全,不可能以明文的方式存储到数据库,都是用加密后的密文存储到数据库。用户登录验证密码时,只需要对传过来的密码做一次同样的加密计算,然后直接比较加密后的密文即可。

2、报文签名。报文签名的作用是为了检查报文是否有在传输的途中被篡改,这种场景也无需解密,在验签时,将签名数据的明文,用同样的算法做一次加密运算,然后直接拿密码数据与签名数据做对比即可。

2.3 MD5加密,SHA家族系列加密对比

不可逆加密算法,主要包括:MD5加密,SHA家族系列加密(包括SHA1、SHA2,其中SHA2又包括SHA-224、SHA-256、SHA-384、SHA-512)、HMAC算法。

这里我们先不讲HMAC,先讲MD5和SHA。

从效率上来讲:MD5 > SHA1 > SHA-224 > SHA-256 > SHA-384 > SHA-512

从安全性上来讲正好相反:MD5 < SHA1 < SHA-224 < SHA-256 < SHA-384 < SHA-512

效率上,我们可以写个例子测试下,如下代码中的例子,测试下加密一千万次,每种算法花费的时间:

不可逆算法测试代码

我们再看下运行结果,如下图所示:

不可逆算法测试结果

可以看到,MD5的效率是最高的,SHA1到SHA-512的效率依次降低。

我们再来讲下安全性,提到安全性,我们首先要知道暴力破解密码的方式,一般有两种:

1、穷举法。穷举法就是不停的尝试各种字符的排列组合,看哪个组合的加密后的值能和要破解的值对上。但是这种方式耗费时间,假如一个密码只能由8位的数字和大小写组成,那它的排列方式就有62的8次方种,恐怕破解几年都破解不完。所以一般不会采用这种方式。

2、字典法。这种方法是把所有的密文和与其对应的明文,以映射表的形式存储起来。破解时,直接根据密文去表中对应的明文。这种方法一般是比较常用的。

那么对于第二种字典法破解,我们如果想增大它的破解难度,就是让这个映射表变大,表越大,它查找的就越慢,破解的难度也就越大。那这个映射表怎么才能变大呢?当然是密文的长度越长,它的表就越大了。

下面的表格是每种算法加密后生成的bit数和转换成16进制的长度:

加密算法

bit

十六进制长度

MD5

128

32

SHA-1

160

40

SHA-224

224

56

SHA-256

256

64

SHA-384

384

96

SHA-512

512

128

由此可见,MD5生成的密文长度是最短的,所以它的安全性是最低的,SHA-1到SHA-512生成的密码长度依次变长,所以安全性依次升高。

目前来讲,由于MD5算法和SHA-1算法的安全性太低,所以现在基本不会用了。从安全性和效率上来综合考虑,目前用的最多的是SHA-256算法。

2.4 加密算法加盐

当然了,暴力破解的难度,不仅和选择的算法有关,也和明文的复杂程度有关,复杂度越低,就越容易破解。为了解决这个问题,通常会对明文做加盐处理,加盐,即通过生成一个随机的字符串,与明文拼接到一起,使明文变得更加复杂,这样就增大了暴力破解的难度。

如下图所示,我们加密的明文很简单,就是123456,然后我们用MD5加密,得出加密后的密文。

简单明文的加密

那我们再把得到的密文,随便拿到一个破解MD5的网站,都能破解出来,如下图:

简单明文加密后的暴力破解

那我们在给这个明文加上盐呢,代码和运行结果如下图所示:

加盐后的明文做加密

这时再把得到的密文去网站上解密,发现已经无法破解成功了,如下如所示:

加盐后明文加密后的暴力破解

我们可以看到,加盐后的明文做加密,已经很难破解了,这样又提高了安全性。但是我们要注意的是,要把每次随机生成的盐记录下来,便于后面做校验时用。

2.5 HMAC算法

这里为什么要把HMAC算法拿出来单独说呢?因为HMAC算法是在基于其它不可逆加密算法(MD5、SHA、或者其他,后面简称为S)的基础上,又利用密钥,做的加密。所以它的效率和安全性,是和S密切相关的,效率上来讲,因为它的运算更加复杂,所以它要比S的效率稍慢,但是安全性上来讲,因为它涉及到了密钥,所以它要比S的安全性更高。

HMAC加密算法有很多种,每种加密算法的命名,就是HMAC+它选择的不可加密算法,例如:HmacMD5、HmacSHA1、HmacSHA256等等。

如下图所示,用的HmacSHA256做加密的代码及计算结果:


HmacSHA256做加密的代码及计算结果

看到这里,大家有没有觉得,HMAC的加密方式,与我们上面说的加盐的方式是有些类似的,可以把密钥理解为我们提到的盐,只不过它的计算逻辑要比加盐复杂的多,安全性也更高,但是思想都是一致,都是把明文变得越来越复杂,提升它的破解难度。

是要依托于其它不可逆加密算法(MD5、SHA、或者其他)才能实现的。如果它依托于MD5算法,那它的算法名称就是HmacMD5,依托于SHA-1,它的算法名称就是HmacSHA1...以此类推。

HMAC更适合做报文的签名。因为如果单纯的用MD5或者SHA签名的话,如果报文被黑客篡改了,黑客知道你这个加密算法,那么黑客就可以利用它修改后的报文做一个签名,这种情况下验签也会成功的。但是用HMAC的话就不会有这个问题,黑客拦截并篡改报文后,它即使知道用的HMAC算法做的签名,但是它不知道密钥,所以也无法做签名,这样就提升了安全性。

三、可逆加密算法

可逆加密算法,即可以通过密文解密出明文,它又分为对称加密和非对称加密。

3.1 对称加密和非对称加密的区别

1、对称加密算法,加密和解密时,用的是同一把密钥,而非对称加密算法,加密和解密用的是不同的密钥。

2、对称加密的效率较高,但是安全性较差。非对称加密的效率较差,但是安全性更高。

3.2 对称加密

为什么说对称加密的安全性较差呢?因为对称加密在加密和解密用的是同一把密钥,所以会涉及到密钥的传输,一旦密钥在传输的过程中被拦截,那就任何的加密信息都可以破解了。

常用的加密算法有DES、3DES、AES三种,其中3DES是在基于DES的基础上做的升级,它的安全性要比DES更高,但是效率较差。而AES算法,它的效率是最快的,安全性也是最高的,所以它目前是被广泛应用的。所以我们这里只来讲AES,不再讲DES和3DES。

3.2.1 AES加密

我们先来看下如何使用AED加解密,如下如代码所示:

AES加解密

我们再来看下它的执行结果,如下图所示:

AES加解密结果

我们可以看到,这个结果其实是有些怪异的,我们用同样的密钥,同样的明文,做了三次加密,每次加密的结果竟然都是不同的,但是每次解密出来的结果还是相同的,这个是怎么做到的呢?

我们看到,在加密的代码里,有这样一行代码:Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 这个方法的参数中,利用/将参数值分割成了三部分。这三部分分别为算法名称、工作模式、填充方式。下面我们分别来讲一下这三部分的含义

算法名称。这个比较简单,因为我们现在想要AES算法,所以这里就填AES,如果你想使用其它算法,你也可以写DES,3DES等等。

工作模式。AES加密方式,属于分组加密方式,它先将明文按照一定的长度做分组,得到明文组,然后通过对明文组做加密。那么工作模式的含义,就是如何对明文组做加密。

工作模式有六种:ECB、CBC、PCBC、CFB、OFB、CTR。但是最常用的只有前两种ECB和CBC,我们在这里也只介绍前两种,其他的如果有兴趣可以自己了解。

ECB模式:这种方式是将每个明文组做单独的加密运算,然后将每个组的计算结果拼接起来,得到最终的结果。由于组与组之间是互相独立的,没有联系,所以它做加密计算时,可以并行计算,效率较高。但是同时安全性也较差。

CBC模式:每个明文块先与前一个密文块进行异或后,再进行加密。但是第一个明文块与谁做加密呢,这时我们需要引入一个向量IV,让第一个明文块与向量IV做异或。这种方式下,每个明文的加密,都要依赖于前一个明文组加密的结果,所以它无法做并行计算,效率也会稍差一些。但是安全性会更高一些。

我们的例子中,就是因为使用了CBC模式,引入了向量IV,但是每次的向量IV都是不同的,所以每次加密时,虽然使用了相同的明文和密钥,计算出来的结果还是不同的。

填充方式。在对明文分组时,如果最后一组的长度不足要求的长度,这个时候需要对明文做填充,填充方式有下面几种:

No Padding:不填充,要求明文的长度,必须是加密算法分组长度的整数倍。

ANSI X9.23:在填充字节序列中,最后一个字节填充为需要填充的字节长度,其余字节填充0。例如需要填充4个字节,则填充00 00 00 04

ISO 10126:在填充字节序列中,最后一个字节填充为需要填充的字节长度,其余字节填充随机数。例如需要填充4个字节,则填充98 A3 B2 04,其中98 A3 B2是随机的。

PKCS#5和PKCS#7:在填充字节序列中,每个字节填充为需要填充的字节长度。例如需要填充4个字节,则填充04 04 04 04。这种是用的比较多的。

SO/IEC 7816-4:在填充字节序列中,第一个字节填充固定值80,其余字节填充0。若只需填充一个字节,则直接填充80。例如需要填充4个字节,则填充80 00 00 00

Zero Padding:在填充字节序列中,每个字节填充为0。例如需要填充4个字节,则填充00 00 00 00

最后说下,AES加密可支持128位、192位和256位的密钥长度,密钥长度越长,安全性越高,但是运算起来也会更加复杂,效率也会随之下降。

3.3 非对称加密

非对称加密算法,加密和解密用的不是同一个密钥。服务方首先会生成一对公钥和私钥,然后私钥自己留下,把公钥发给使用者。因为它不会涉及到私钥的网络传输,所以它比对称加密的安全性更高,但是效率要比对称加密差一些。

非对称加密主要包括RSA加密和ECC加密,我们先来说下RSA加密。

3.3.1 RSA加密

我们先来看下如何使用RSA加解密,如下如代码所示:

RSA加解密

我们再来看下运行结果:


RSA加解密结果

我们可以看到,是可以正常的加解密的。

我们再把待加密的明文变长一些,如下图所示:

明文过长的RSA加解密

我们再来看下运行结果:

明文过长的RSA加解密结果

我们看到,此时报了个异常,异常信息为:待加密数据不能超过117位。这是为什么呢?

RSA 算法一次能加密的明文长度与密钥长度是相同的,如上面中的例子所示,我们生成了一个1024位的密钥,那么RSA可加密的明文长度最大是 1024 位。如果小于这个长度,就需要对明文做补齐。

但是在做补齐的时候,补齐的数据就要占用实际的明文长度。对于 1024 位(128个字节)密钥对而言,如果使用默认的补齐方式(RSA_PKCS1_PADDING),此种方式会占用11个字节,所以明文长度最多为 128 - 11 = 117 字节,所以上面的例子中,才会报待加密数据不能超过117位的异常。

所以我们在做加密之前,首先要判断明文数据+补齐数据的长度,是否会超过密钥的长度,如果超过了,就需要做分段加解密。我们先来看下分段加解密的代码,如下图所示:

RSA分段加密


RSA分段解密

我们再来看下运行结果:

RSA分段加密执行结果

我们看到,用分段加解密计算出来的结果,就是正确的了。

我们在来看下RSA的各种补齐方式,对明文长度的要求,如下表所示:

补齐方式

明文最大长度(字节)

RSA_PKCS1_PADDING

密钥长度-11

RSA_X931_PADDING

密钥长度-2

RSA_NO_PADDING

密钥长度 - 0

3.3.2 DH密钥交换算法

好多人都把DH算法归结到非对称加密算法当中,但是我的个人理解,DH其实并不是一种加密算法,它只是密钥交换的算法。

我们知道,非对称加密的安全性高,但是效率慢。对称加密的效率高,但是安全性又低。那DH算法,就是通过交换密钥的方式,来达到安全性高而且效率又高的目的。

它的操作流程是这样的,假设A和B之间互相通信。

1、A生生成一对非对称密钥,我们记为公钥A、私钥A

2、A将生成的公钥A发送给B

3、B接收到公钥A后,利用公钥A又生成了一对非对称密钥,我们即为公钥B、私钥B

4、B将公钥B发送给A

5、A接收到公钥B后,利用私钥A和公钥B,生成一个对称密钥

6、B也利用私钥B和公钥A生成一个对称密钥

在最后的两步中,A生成的对称密钥和B生成的对称密钥是相同的,那后面就可以用这个对称密钥对传输的数据做加解密了。而且在这个过程中,只有公钥会在网络中传输,私钥和对称密钥都没有在网络中传输,没有被拦截的可能,所以这样即保证了安全性,又提高了效率。

3.3.2 ECC加密

ECC加密算法与RSA加密算法相比,它的安全性和效率都要比RSA高很多。只不过ECC作为新一代的主流的非对称加密算法,兼容性方面还没有普及。所以目前用的最广泛的就是RSA算法。

而且JDK也是不支持ECC算法的,如果想要在java是使用ECC算法,还需要下载第三方包。这里我们就先不讲了。

四、我是如何做密码的传输与存储的

上面我们讲完了常见的加密算法,我们在回到开篇提到的问题,在用户的注册与登录的过程中,用户的密码是如何传输与存储的。

我是这样做的,首先在传输的过程中,用的的RSA非对称加密,来保证传输过程中的安全性。在后端会开放一个接口,用来获取RSA的公钥,前端通过这个接口,获取公钥,对密码加密,后端在接收时,再利用对应的私钥对其解密。

然后在存储时,我们首先生成一个2~5的随机数n,这个n代码加密的次数,然后在随机生成n个16位的字符串,s1~sn。让明文密码首先与s1做一次异或运算,对得到的结果对SHA-256加密,然后对加密的结果,在与s2做异或,对异或的结果在做SHA-256加密,这样重复n次,得到的结果就是最终加密的结果,然后把加密的结果存储到数据库中。

至此,我们就讲完了java中支持的一些比较常见的加密算法以及使用,下一篇文章,我们会继续讲 java中的加密体系架构之JCA和JCE。

往期精彩:

分布式锁第一篇:分布式锁的背景

分布式锁第二篇:redisson分布式锁的使用以及可重入性

分布式锁第三篇:redisson分布式锁的可重试性以及看门狗源码解析

分布式锁第四篇:redisson分布式锁的联锁、红锁、公平锁、读写锁

作者介绍:

贠学文,具有多年经验的java开发工程师,业余时间利用头条分享技术知识点与自己对技术的感悟,帮助对自己未来感到迷茫的程序员,在技术上得到提升。结识一些志同道合的朋友,相互促进,共同进步。

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码