术语解释
- 对称算法(Symmetric key algorithm):采用相同的密钥执行加密或解密。
- 非对称算法(Asymmertric key algorithm,公开密钥算法):用作加密的密钥不同于用作解密的密钥,而且解密密钥不能根据加密密钥计算出来。加密密钥能够公开,但解密密钥必须保持私密性。任何获得加密密钥的实体都可以加密信息,但只有持有对应的解密密钥的实体才能解密信息。
- 哈希函数(Hash function):一种将不同长度的数据映射成固定长度数据的函数。
- 消息认证码(Message authentication code,简称MAC):密码学上的一种数据校验和,通过使用对称密钥来检测数据是否发生意外或有意的修改。
- 分组密码(Block cipher):对称算法的一种,他将明文分成多个等长的组,并用相同的算法对每组进行加密。
- 流密码(Stream cipher,序列密码):对称算法的一种,他说用算法和密钥一起产生一个随机码流,将其与数据流XOR产生加密后的数据流。
- 工作模式(Block cipher mode of operation):是指使用分组密码算法对数据进加密转换的方法。常见的工作模式有ECB、CBC、CFB 、OFB和CTR五种基本加密模式以及CCM、GCM等认证加密模式。
- 初始向量(Initialization Vector,简称IV):是许多工作模式中用于随机化加密的一块数据,因此可以由相同的明文、相同的密钥产生不同密文。
- 填充(Padding):在对消息进行密码运算前的数据规整性处理,是的待保护数据在长度上满足密码算法运算要求,在安全性上也能抵抗相关的密码分析。
- 盐值(Salt):通常由随机数来冲淡的一段数据,计算口令单项哈希时用于对口令进行加扰,防止彩虹表攻~击,研制无需保密。
- 安全强度(Security strength):用来衡量密码算法或者密码系统的安全性,它是对破~解密码算法或者系统所需要的工作量的一个数值度量。
- 口令(Password):指用于身份认证、鉴权或者派生加密密钥的字符串,可以由字母、数字和符号组成。
- 密钥(Key):一个结合密码算法一起使用的参数,只有持有它的实体才能进行相关的密码运算(加密、解密、签名、验证等)。
- 种子(Seed):真随机数产生器的输出。
- 彩虹表攻~击(Rainbow Table):马丁·赫尔曼早期提出的简单算法的应用,用于加密散列函数逆运算的预先计算好的表, 为破~解密码的散列值(或称哈希值、微缩图、摘要、指纹、哈希密文)而准备。最好防御彩虹表攻~击的方式是“加盐”,即在密码的特定位置插入特定的字符串。
密码算法的选择
1、禁止使用私有的、非标准的密码算法(安全影响:高)
私有、非标准的算法包括但不限于:
- 未经过专业机构评估、自行设计的密码算法
- 自行对标准密码算法进行改造
- 自行定义的通过变形/字符移位/替换等方式执行的数据转换算法
- 用编码的方式实现数据加密目的的伪加密实现
- 用差错控制编码(如奇偶校验、CRC)实现完整性校验
注:在不用于如机密性、完整性等用途且产品未在界面、资料声称算法用户安全目的,出于正常业务需要,可以使用base64等算法。
2、禁止使用不安全的密码算法,推荐使用强密码算法
用途 | 常见不安全密码算法 | 可遗留使用密码算法 | 推荐使用的强密码算法 | |
对称加密 | 分组加密 | Blowfish,DES,DESX,RC2,Skipjack,2TDEA,TEA,3DES | AES-GCM(>=128 bits) | |
流加密 | SEAL,CYLINK_MEK,RC4 | AES-CTR(>=128 bits),AES-OFB(>=128 bits),chacha20-poly1305 | ||
哈希算法 | SHA0,MD2,MD4,MD5,SHA1(数字签名、Hash-only场景),RIPEMD,RIPEMD-128 | SHA-1(HMAC/秘钥派生、随机数产生场景/MGF),SHA224,SHA512/224,SHA3-224 | SHA256或以上,SHA3-256或以上 | |
非对称加密 | RSA(<2048 bits),ECIES(<224 bits) | RSA(<3072 bits),ECIES(<256 bits) | RSA(>3072 bits),ECIES(>=256 bits) | |
数字签名 | RSA(<2048 bits),DSA(同X9.42标准DH),ECDSA(<224 bits) | RSA(<3072 bits),DSA(同X9.42标准DH),ECDSA(<256 bits) | RSA(>=3072 bits),DSA(同X9.42标准DH),ECDSA(>=256 bits),EdDSA(>=256 bits) | |
秘钥协商 | DH | L < 2048 bits, N < 224 bits | L < 3072 bits, N < 256 bits | L >= 3072 bits, N >= 256 bits |
ECDH | ECDH ( < 224 bits) | ECDH ( < 256 bits) | ECDH ( >= 256 bits) |
- SHA-1用于数字签名以及hash-only时,为不安全算法,由于SHA1可碰撞攻~击(影响数字签名及hash-only)已经成为现实,业界部分标准、规范对SHA1使用持谨慎态度,因此SHA1用于消息认证码(MAC)、密钥派生函数(KDF)、随机数生成(RNG)、掩码生成函数(例如RSA-PSS填充时MGF)场景时作为遗留算法使用。
- DH密钥交换算法在域参数构成上目前有PKCS#3、X9.42两种标准,PKCS#3标准的DH安全强度和群规模参数L有关,而X9.42标准的DH安全强度除和群规模参数L有关,还和子群规模参数N有关。因此,产品如采用PKCS#3标准的DH域参数,则表格中的N的大小可以不关注
安全影响:
场景 | 影响 |
使用不安全密码算法 | 高 |
使用可遗留使用的密码算法 | 中,个别算法影响低或无,具体场景具体分析 |
3、优先选择国际标准密码算法
如果使用非客户所属国的国家标准算法,可能出现密码算法不被客户认可的情况。对于与公开的中国国密算法(SM2/SM3/SM4/SM9),在发往国外的产品中可以指出,但须默认关闭,除非可和明确要求或者明确声明不做要求。发往国外的产品中应禁止包括未公开的中国国密算法(SSF33/SM1/SM7)。对于已被采纳为国际标准的中国国密算法(如祖冲之算法、SM2/SM3/SM9),不受此规则约束。同时发往多个国家的产品中,默认密码算法应该采用国际标准算法。
国密算法列表:
国密算法名称 | 所属分类 | 是否纳入国际标准 | 是否公开 |
ZUC | 流加密算法 | 是 | 已公开 |
SSF33 | 分组加密算法 | 否 | 暂未公开 |
SM1 | 分组加密算法 | 否 | 暂未公开 |
SM2 | 椭圆曲线公钥密码算法 | 是 | 已公开 |
SM3 | 哈希算法 | 是 | 已公开 |
SM4 | 分组加密算法 | 否 | 已公开 |
SM7 | 分组加密算法 | 否 | 暂未公开 |
SM9 | 基于身份标识的非对称密码算法 | 是 | 已公开 |
安全影响:
场景 | 影响 |
使用未公开算法 | 高 |
默认开启已公开但未纳入国际标准的国密算法 | 高 |
默认开启不属于本领域的已纳入国际标准的算法 | 高 |
4、优先选择通过权威证人机构认证的加密算法库或硬件安全模块
通过权威机构认证的加密算法库或硬件安全模块,其加密功能和密钥管理功能已经经过认证机构认证标准和确认,由于事先错误引入的风险可控。已获得FIPS或CC等权威认证,或经权威认证机构(包括德国BSI、法国ANSSI等)完成认证都满足此要求。
算法库方面,OpenSSL和VPP都有经过FIPS认证的版本,IBM JAVA JCE和BouncyCastle Java API也有经过FIPS的版本,安全硬件方面,TPM、HSM等安全模块经过FIPS认证,具体版本信息需要到FIPS官网查询。
安全影响:
场景 | 影响 |
产品为使用加密算法库而自行按照自己理解实现某密码算法 | 高 |
使用未经认证的加密算法库或硬件安全模块 | 中 |
5、在设计阶段就应考虑密码算法使用的敏捷性
在设计时应舍得算法模块独立,代码接口具有较好的拓展性,易于替换升级,而且保证系统支持的算法是可替代的。不应将算法标识硬编码在应用代码中,可以使用工厂模式去设计一个加密类,这样可以根据实际加密的内容和加密需求来灵活选择加密算法。
常用的算法库(OpenSSL、IPSI、JDK等)中都提供了类似的接口函数,在使用时尽量使用此类接口。不要讲算法标识等参数写死,应从配置文件中读取。为防止攻~击者对密码参数配置文件进行恶意篡改,还应对该配置文件进行访问控制,只允许可信用户进行访问和修改,或者使用HMAC来校验其完整性。例如:
CipherFactory cipher = CipherFactory :: defaultFactory();
String cipherName = ConfugurationManager.AppSetting["MyPreferredCipher"];
Cipher MyCipher = cipher.Create(cipherName);
其中MyPreferredCipher是配置文件的配置项,配置文件内容如下:
<encryption>
MyPreferredCipher = "aes-256-gcm"
MyPreferredHash = "SHA256"
SaltFlag = "TRUE"
</encryption>
开发人员在设计密文结构时应让密文中包含足够的密码运算参数的信息(如算法标识、秘钥ID、IV、盐值等),确保算法更新狗,密码算法接口可以根据密文中的密码参数信息正确的解密历史数据,实现应用系统版本的向下兼容。
安全影响:
场景 | 影响 |
未考虑密码算法敏捷性 | 中,影响产品持续安全性,不影响当前安全性 |
密码算法常见应用
1、敏感数据对称加解密
对数据段类型的敏感数据进行加密时,通常采用对称加密算法。简单的方案流程图如下:
AES-GCM加密流程
AES-GCM解密流程
设计要点如下:
- 对称加密算法使用AES256
- 对称加密算法的工作模式使用GCM模式
- 加密中所需的IV值,由安全随机数发生器产生。对于AES分组算法GCM模式,IV的长度建议12字节
- 额外认证数据(AAD)是可选参数,GCM模式仅保护AAD完整性而不对其提供机密性保护,如果有AAD数据,则加密和解密时必须提供相同的AAD数据,产品在对敏感数据加密的同时有其他需要保护完整性单无需保护机密性的数据时,可以将其作为AAD参数
- Tag是GCM模式中的消息认证码,用于验证被加密数据及AAD的完整性,GCM的Tag建议为16字节,至少12字节
- 对文件加密时,为防止文件过大,无法一次性读入内存,可将文件分段读取至内存,逐段加密后保存到一个密文文件
2、敏感数据非对称加解密
客户端与服务器之间无法使用安全协议或共享密钥建立安全通道时,此时使用非对称加密可以很方便地实现敏感数据的加密传输。服务器端产生公私钥对,将公钥传给客户端。公私钥对可在程序中产生也可使用外部工具产生。公钥不需要加密,但加密方需确知该公钥属于接收方--服务器端,一般通过校验数字证书、校验哈希值或其它可靠的方式来保证这一点。私钥在服务器端需要加密保存。客户端给服务器发送敏感数据时用服务器公钥进行加密,服务器端用私钥进行解密。
设计要点:
- 为保证128位的安全强度,使用RSA算法时密钥长度要为3072及以上
- 使用RSA算法时采用OAEP填充方式。OpenSSL中使用OAEP填充方式时输入明文长度必须至少比RSA密钥长度少42字节(OpenSSL中OAEP填充方式默认哈希算法是SHA1),对于3072位的密钥,明文长度最大为2072/8-42=342字节
- 使用RSA算法时的公共指数e通常取值为(2^16)+1,即0x10001
- 非对称加密效率通常较低,不适合加密大量数据,大量数据的加密传输可以采用数字信封方式进行。对于长度超过一次加密允许的最大明文长度的情况,在数据量较小时可以对明文进行分割,再对分割后的个明文数据段分别进行非对称加密
3、敏感数据的数字签名
在实际业务中,为了保证敏感数据的完整性和不可抵赖性,需要对数据进行数字签名。通信双方各自产生自己的公私钥对并将公钥公布出去,必须保证双方都可以互相验证对方公钥的真实性。数字签名一般由持有私钥的实体在私钥的参与下针对被签名数据产生,由持有公钥的实体在公钥的参与下验证签名的有效性(验证通过表明签名值确为持有私钥的实体产生,且未经篡改过),对于RSA算法,签名方用自己的私钥加密敏感数据哈希值,加密结果作为签名结果发送给验证方。验证法用相同的哈希算法计算敏感数据的哈希值,并将计算记过和公钥解密的签名结果比较,相同则验证通过,否则不通过。
设计要点:
- 为保证128位安全强度,使用RSA算法时,密钥长度应为3072及以上
- 使用RSA算法时推荐使用PSS填充方式
4、敏感数据的加密传输
在非信任的网络中,需要进行敏感数据的批量传输,尽量使用已经成熟的安全标准(SSL/TLS、SSH、IPSec等安全协议)。
设计要点:
- 在所以服务器上,对于PKCS#3标准的DH,须使用3072位的密钥
- 保护私钥,对私钥的可访问范围做最小化。建议的策略包括:
- 将私钥存储在备份系统时,需要用口令加密保护以防止被泄密
- 一旦发生泄密,吊销所有旧的证书并且为新的证书生成新的密钥对
- 每年更新证书,而且永远使用新的密钥
- 服务器从可信CA申请证书
- 默认情况下使用最新的TLS协议版本,使用一些老的版本保持与用户的互通性
- 只使用安全的加密套件。推荐使用128比特或更高安全强度的加密套件,其他的必须限制使用,如:
- 匿名DH(ADH)套件不提供认证功能
- NULL套件不提供加密功能
- 出口密钥交换套件使用了容易被破~解的认证机制
- 使用弱加密算法的套件使用的加密算法(如DES、3DES、RC4)很容易被破~解
5、口令的安全存储
口令是个用户登录的重要凭证,即使是系统管理员也不应该知道用户的明文口令。在基于用户口令认证的系统中,在不需要还原口令的场景下,应将口令进行单项哈希保存。口令单向哈希场景下推荐使用PBKDF2算法,通过输入口令(明文)生成哈希值。
PBKDF2算法是一个密钥派生算法,既可用于派生密钥,也可用于口令保存,计算公式:
DK = PBKDF2(HashAlg,Password,Salt,Count,dkLen)
- HashAlg:哈希算法(推荐使用SHA256)
- Password:用户输入的口令,字符串
- Salt:盐值,随机数,无需加密
- Count:迭代次数,正整数,无需加密
- dkLen:派生密钥的字节长度,正整数
- DK:派生的密钥,长度为dkLen个字节的字符串。在这里就是最终存储的口令哈希值。
采用PBKDF2算法可以有效增加彩虹表攻~击难度。通过增加迭代次数,能显著增加暴力破~解的耗时,但对完成一次认证的性能影响不大。
设计要点:
- Hash函数的选择:选择SHA256或更安全的哈希算法
- 迭代次数的选择:无性能要求场景推荐不少于10000000,对于通用操作系统产品至少10000次,对于有性能约束的产品(如认证服务器、嵌入式系统)至少1000次
- salt的选取:推荐16字节或者以上;salt应为安全的随机数
- PBKDF2的输出长度应该不小于256比特
6、非标准安全协议下密钥协商
在不能使用安全协议的情况下,有时需要在通信双方间写上一个会话密钥,建立安全通道,这种情况可使用DH算法进行密钥协商。
DH算法是一种匿名交换协议,不对交换双方进行身份认证,容易受到中间人攻~击威胁,因此使用DH算法进行密钥协商时,须验证对方身份的真实性。
A和B想通过DH算法产生一个共享密钥原材料,先协定并预置一组全局公开的参数。公开参数使用RFC 3526、RFC7919标准群组域参数或使用工具产生自定义域参数。无论何种方式获取域参数,其群组规模长度推荐大于等于3072比特。
DH算法具体过程如下图:
DH算法数据流图
经过图示过程后A和B得到同样的值K,这个值可以作为共享密钥原材料。协商过程中需对双方交换的临时公钥值进行某些特殊值过滤,如0,1,P-1(P为公开参数)。一旦A和B得出了共享密钥原材料,就可以通过密钥派生算法生成对称密钥,给双方通讯内容加密。
设计要点:
- 公开参数的产生需要较长时间,可以直接选用推荐参数并保存到文件,需要时从文件中读取
- 为保证安全强度,DH算法的密钥长度要为3072比特及以上
- 必须使用安全随机数且长度应大于224比特
- 两个随机数和最后计算的K在挣个过程中是需要保密的,生成密钥后要立即删除