1、摘要算法

单向散列函数输出的散列值也称为消息摘要(message digest)或者指纹(fingerprint).
主要用途是检测是否被篡改,在消息验证码(HMAC)和数字签名中使用的比较多。

摘要算法有几个特点:

  1. 输出长度固定
  2. 单向、不可逆
  3. 计算出散列值耗时短
  4. 防碰撞

输出长度固定

散列值的长度和消息的长度无关。无论消息是1比特,还是100MB,甚至100GB,单向散列函数都会计算出固定长度的散列值。

单向、不可逆

只能进行正向的信息摘要,而无法从摘要中恢复出任何的原始信息,甚至根本找不到任何与原始信息相关的信息。

计算出散列值耗时短

计算散列值所花费的时间必须要短。尽管消息越长,计算散列值的时间也会越长,但如果不能在限时的时间内完成计算就没有意义了。

以一个60M的文件为测试样本,经过1000次的测试平均值,三种算法的表现为(来自网友的测试):

MD5算法运行1000次的平均时间为:226ms      
SHA1算法运行1000次的平均时间为:308ms      
SHA256算法运行1000次的平均时间为:473ms

防碰撞

两个不同的消息产生同一个散列值的情况称为碰撞(collision),如果要将单向散列函数用于完整性的检查,则需要确保在事实上不可能被人为地发现碰撞。密码技术中所使用的单向散列函数,都需要具备抗碰撞性。

下面介绍几个摘要算法的用途:

MD5

MD5在强抗碰撞性已经被攻破,也就是说,现在已经能够产生具备相同散列值的两条不同的消息,因此它已经不安全了,不推荐使用。

SHA1

SHA1的强抗碰撞性已于2005年被攻破,不过目前个别签名算法中还仍然在使用。

SHA256

目前安全,用处最多的就是在签名算法中,用于检测消息是否被篡改过。

SHA256_HAMC

提到HMAC 就需要知道消息认证码(message authentication code)是一种确认完整性并进行认证的技术,取三个单词的的首字母简称MAC。
消息认证码的输入包括任意长度的消息和一个发送者与接收者之间共享的密钥,它可以输入固定长度数据,具体长度根据不同的散列算法函数也是不同的,可以参考上面的表格。

消息认证码也可以简单的理解是一种与密钥相关联的单向散列函数

HMAC 是一种使用单向散列函数来构造消息认证码的方法。其中HMAC的H 就是Hash 的意思。HMAC中所使用的单向散列函数并不仅限于一种,任何高强度的单向散列函数都可以被用于HMAC,使用SHA1、MD5、SH256 所构造的HMAC,分别称为SHA1_HMAC、MD5_HMAC、SHA256_HMAC.

通过发送方和接收方之间共享密钥的方式,来判断出是否发生了篡改行为。

摘要算法可以防止消息被篡改,怎么做到防止重放攻击呢?

重放攻击:是指攻击者拦截到数据之后原封不动的重新发送给接收方,虽然很多数据都是加密过,攻击者无法获得数据的原文,但是他们知道这些数据的作用,就可以在不知道数据内容的情况下通过再次发送这些数据达到愚弄接收端的目的。例如:网上转账的消息,被多次重放。

有几种方法可以防御重放攻击

1. 序号

约定每次都对发送的消息赋予一个递增的编号(序号),并且在计算MAC值时将序号也包含在消息中,这样一来,由于攻击者无法计算序号递增之后的MAC值,因此就可以防御重放攻击。这种方法虽然有效,但是对每个通信对象都需要记录最后一个消息的序号。从架构设计方面,不利于扩展,侵入太大。

2.时间戳

基于时间戳生成的OTP,就是很好的例子。
约定在发送消息时包含当前的时间,如果收到以前的消息,即便MAC值正确也将其当作错误的消息来处理,这样就能够防御重放攻击,这种方法虽然有效,但是发送者和接受者的时钟必须一致,而且考虑到通信的延迟,必须在时间的判断上留下缓冲,于是多多少少还是会存在可以进行重放攻击的空间。

3.nonce

在通信之前,接收者先向发送者发送一个一次性的随机数,这个随机数一般称为nonce。发送者在消息中包含这个nonce 并计算MAC值,由于每次通信时nonce的值都会发生变化,因此无法进行重放攻击。这种方法虽然有效,但是通信的数据量会有所增加。

在通信保护这块推荐使用移动安全信道。


2、AES对称加密

对称加密算法之所以对称,是因为这类算法对明文的加密和解密需要使用同一个密钥。A(AES,Rijndael)是一种分组密码加密和解密算法,是全球使用最广泛的加密算法。 AES使用128、192或256位的密钥来处理128位的块
AES 支持三种长度的密钥:

128bit (16B),  192bit(24B) ,  256bit(32B)

使用效果:

AES256 安全性最高,AES128性能最优。本质是它们的加密处理轮数不同。

AES128

10轮

AES192

12轮

AES256

14轮

ECB 模式

ECB 模式是最简单的块密码加密模式,加密前根据加密块大小(AES 128位)分成若干块,之后将每块使用相同的密钥单独加密,在该模式下,每个明文块的加密都是独立的,互不影响的。解密同理。

不要使用AES电子密码本(ECB)模式 

AES ECB模式或AES/ECB/PKCS5Padding (在Java中)在语义上并不安全 

缺点

  • 相同的明文块经过加密会变成相同的密文块,因此安全性较差。

CBC 模式

CBC模式引入一个新的概念:初始向量IV。

IV的作用和MD5的"加盐"有些类似,目的是防止同样的明文块始终加密成相同的密文块。

CBC模式原理:

在每个明文块加密前会让那个明文块和IV向量先做异或操作。IV作为初始化变量,参与第一个明文块的异或,

后续的每个明文块和它前一个明文块所加密出的密文块相异或,这样相同的明文块加密出来的密文块显然不一样。

优势

  • 安全性更高

缺点

  • 无法并行计算,性能上不如ECB
  • 引入初始向量IV,增加复杂度

GCM模式

在AES加密和解密中,我们需要以下输入:不要重复使用具有相同密钥的IV(初始值或初始向量)。

 IV(初始值或初始向量),它是随机字节,通常为12个字节或16个字节。 在Java中,我们可以使用SecureRandom生成随机IV。

在Java中,我们使用AES/GCM/NoPadding表示AES-GCM算法。 对于加密的输出,我们将16字节的IV前缀到加密的文本(密文)之前,因为解密需要相同的IV。

  • AES密钥(256位)
  • IV – 96位(12字节)


常用的填充方式

AES 算法在对明文加密的时候,并不是把整个明文加密成一整段密文,而是把明文拆分成几组独立的明文块,每一个明文块的长度128bit(16B),最后不足128bit(16B),会根据不同的Padding 填充模式进行填充,然后进行加密。

总结:加密过程是先处理pading,后加密。解密过程是先进行分块解密,最后在处理Padding。

例如:一段明文的长度198bit,按照128bit 拆分,第二个之后70bit,不足128bit,就需要对明文块进⾏填充(Padding)。

常见的填充模式有:

  • NoPadding
  • PKCS5Padding
  • PKCS7Padding
  • ISO10126Padding
  • ISO7816-4Padding
  • ZeroBytePadding
  • X923Padding
  • TBCPadding(Trailing-Bit-Compliment)
  • PKCS1Padding


NoPadding

不做任何填充,要求明文必须是16字节的整数倍。

PKC5Padding(推荐)

明文块少于128bit(16B),在明文块的末尾补足相应数量的字符,且每个字节的值等于缺少的字符数。

原始:FF FF FF FF FF FF FF FF 填充:FF FF FF FF FF FF FF FF 08 08 08 08 08 08 08 08 原文为整数倍也需要填充

ISO10126Padding

明文块少于128bit(16B),在明文块的末尾补足相应数量的字符,最后一个字符值等于缺少的字符数,其他字符填充随机数

填充至符合块大小的整数倍,填充值最后一个字节为填充的数量数,其他字节随机处理。

原始:FF FF FF FF FF FF FF FF FF 填充:FF FF FF FF FF FF FF FF FF 3F 7A B4 09 14 36 07

ISO10126PADDING

填充至符合块大小的整数倍,填充值最后一个字节为填充的数量数,其他字节随机处理。

原始:FF FF FF FF FF FF FF FF FF 填充:FF FF FF FF FF FF FF FF FF 3F 7A B4 09 14 36 07

ISO7816-4PADDING

填充至符合块大小的整数倍,填充值第一个字节为 0x80,其他字节填 0。

原始:FF FF FF FF FF FF FF FF FF 填充:FF FF FF FF FF FF FF FF FF 80 00 00 00 00 00 00

ZEROBYTEPADDING

填充至符合块大小的整数倍,填充值为 0。

原始:FF FF FF FF FF FF FF FF FF 填充:FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00

X923PADDING

填充至符合块大小的整数倍,填充值最后一个字节为填充的数量数,其他字节填 0。

原始:FF FF FF FF FF FF FF FF FF 填充:FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 07

TBCPADDING(Trailing-Bit-Compliment)

填充至符合块大小的整数倍,原文最后一位为“1”时填充 0x00,最后一位为“0”时填充“0xFF”。

原始:FF FF FF FF FF FF FF FF FF 填充:FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 原始:FF FF FF FF FF FF FF FF F0 填充:FF FF FF FF FF FF FF FF F0 FF FF FF FF FF FF FF

PKCS1PADDING

该填充模式是 RSA 加密中使用的,详见 RFC 2313。RSA 加密时,需要将原文填充至密钥大小,填充的格式为:00 + BT + PS + 00 + D

  • 00 为固定字节
  • BT 为处理模式。公钥操作时为 02,私钥操作为 00 或 01
  • PS 为填充字节,填充数量为 k - 3 - D,k 表示密钥长度,D 表示原文长度。PS 的最小长度为 8 个字节。填充的值根据 BT 值不同而不同:
  • BT = 00 时,填充全 00
  • BT = 01 时,填充全 FF
  • BT = 02 时,随机填充,但不能为 00


要求

1)需要还原的加密数据,比如 IMEI、生日等个人数据,推荐使用 AES 加密算法,模式采用 GCM 模式;

2)对于不需要还原的加密数据,比如用户的密码,推荐使用 PBKDF2 加密不可逆数据。

3)签名场景,推荐使用 RSA 算法,密钥长度至少 3072 位。(2048 仅可遗留使用,新版本中只能用于验签,不能用于签名) 4)消息认证场景,推荐使用 HMAC-SHA256 算法。

5)Java里Cipher.getInstance("AES"),其中"AES"默认是ECB模式,禁止使用(密文检索场景也禁止使用,无备案通道。);

6)Java里Cipher.getInstance("AES/ECB/NoPadding"),禁止包含"ECB"字样。

7)检查AES加密算法中是否采用CMS-Padding和ISO-Padding模式,不是则提单,是则测试结束(PKCS5Padding/PKCS7Padding属于CMS系,同样符合要求)。

8)搜索代码中AES加密的代码,检查IV是否完全随机和可变(不同分组模式对IV有不同要求

9)检 视 关 键 字“.getInstance("AES")”,找出 AES 算法使用的点。检查 IV 的生成,是否每次 AES 加密 算法的调用都生成一个新的 IV(无关键字查询,需代码检视)。


3、RSA非对称加密

RSA是非对称公钥密码算法的一种。

从使用RSA 算法的角度入手需要注意以下几点:

  1. 公钥通信的流程
  2. key 的长度和加密原文的最大长度
  3. 会遇到哪些攻击手段。
  4. 解决方法。

公钥通信的流程
假设Alice 要给Bob发送一条消息,Alice 是发送者,Bob是接收者,而这一次窃-听者Eve 依然能够窃-听到他们之间的通信内容。

在公钥密码通信中,通信过程是由接收者Bob来启动。
(1)Bob 生成一个包含公钥和私钥的密钥对。
私钥由Bob自行妥善保管。
(2)Bob 将自己的公钥发送给Alice。
Bob的公钥被窃-听者Eve截获也没关系。
将公钥发送给Alice,表示Bob 请Alice 用这个公钥对消息进行加密并发送给他。
(3)Alice用Bob的公钥对消息进行加密。
加密后的消息需要用Bob 私钥才能够解密。
虽然Alice 拥有Bob的公钥,但是Bob的公钥是无法对密文进行解密的。
(4)Alice 将密文发送给Bob。
密文被窃-听者Eve 截获也关系。Eve 可能拥有Bob的公钥,但是用Bob的公钥是无法进行解密的。
(5)Bob 用自己的私钥对密文进行解密。
通信完成。

key 的长度和加密原文的最大长度
RSA 加密原文的长度是由Padding 填充模式决定的。

RSA_PKCS1_PADDING 填充模式(默认最常用的模式)SDK算法默认使用这个模式。
要求输入必须比RSA key长度短至少11个字节。
RSA 算法常用key的长度以 1024bit 和 2048bit 为例子,对应的加密原文的最大长度
1024bit的key加密 原文的最大长度:(1024/8 - 11)= 117B
2048bit的key加密 原文的最大长度:(2048/8 - 11) = 245B

RSA_PKCS1_OAEP_PADDING
加密原文的长度 key的长度减41
RSA_NO_PADDING
加密原文的长度和key的长度一样长,如果输入的明文过长,需要做切割的。

会遇到的那些攻击手段

1.通过暴力破解或者质因子分解攻击的方法,了解这两种攻击方式需要去了解RSA的原理,这里就不展开讲了,直接说答案目前是非常困难的,目前还没有出现,而且我们也不知道是否真的存在这样的方法。

2.中间人攻击
这种方法虽然不能破译RSA,但却是一种针对机密性的有效攻击。

常见加密算法_散列函数

针对中间人攻击如何防御呢?

目前仅靠公钥密码本身,是无法防御中间人攻击的。
我们可以使用公钥的证书,接收者都需要验证证书的有效性、颁发机构以及证书链等等,具体证书的介绍看下篇。




4、国密码算法介绍

常用的国密算法SM2、SM3、SM4

SM2
SM2 非对称算法 基于ECC 椭圆曲线密码机制,但在签名、密钥交换方面不同于ECDSA、ECDH等国际标准,而是采用了更为安全的机制。另外,SM2 推荐了一条256位的曲线作为标准曲线,相对于RSA算法,256位的SM2密码强度已经比2048位的RSA密码强度要高。主要用于数字签名算法,密钥交换协议以及公钥加密算法等。

SM3
SM3是 摘要算法中的一种,是我国自主设计,适用于商用密码应用中的数字签名和验证消息认证码的生成与验证以及随机数的生成,可满足多种密码应用的安全需求。为了保证算法的安全性,其产生值的长度不应太短,MD5输出长度128bit,输出长度太短,安全性较低,目前已经在强抗碰撞性下被攻破。SHA1 算法的输出长度为160bit,SM3算法的输出长度为256bit,因此SM3算法的安全性要高于MD5算法和SHA1 算法。

SM4
SM4 分组密码算法是我国自主设计的分组对称密码算法,用于实现数据的加密和解密,以保证数据和信息的机密性。要保证一个对称密码算法的安全性的基本条件是其具备足够的密钥长度,SM4算法与 AES 算法具有相同的密钥长度分组长度128bit,安全性上高于3DES算法。