1 背景
随着大环境对隐私、数据安全的要求越来越高,我们日常开发工作中遇到数据安全处理的需求也越来越多,多数情况下都会有专门的安全团队提供完整的解决方案,我们按照对应的文档处理就能很好地解决问题。但是有这样的安全团队支持,并不代表我们不需要对安全知识有一定的了解。作为一名优秀的程序员,还是要适当对别人封装好的技术方案有一定的专研精神,一方面是可以拓宽自己的技术边界,另一方面也可以帮助我们在和安全团队对接方案时有更多的共同认知,提高沟通和接入效率。本文首先会对常见的加解密算法及其特性做一个简单介绍,然后结合工作中的高频需求来分析如何综合运用这些算法来实现安全要求。
2 常见加解密算法简介
在处理数据安全问题时,接触到最多的技术应该是加解密了,下图直观地体现了加解密算法的工作流。
根据加解密过程中用到的密钥是否相同,可以把加解密算法分为两类:
对称加密: 加解密用的是同一把密钥,在业界中最常见的算法是AES(Advanced Encryption Standard)
非对称加密: 加解密用的是两把不同的密钥,一把叫公钥(Public Key),一把叫私钥(Private Key),在业界中最常见的算法是RSA(三位发明人的姓氏首字母)
在业界中使用加解密算法遵循的一个原则是:算法公开,密钥私有。 我们在设计的时候,基本都是采用业界公开被论证为足够安全的算法,然后自己保管好密钥,而不是尝试自己设计一套加解密算法(在一些政企业务中可能会被要求使用国产安全算法)。因此保护数据安全的问题,其实就转化成了保护密钥安全的问题了。
我们在设计信息安全机制的时候,一定要基于业务所需要的安全等级来。比如银行系统,那一定是怎么增加机制的复杂度都不为过;但是像类似新闻、天气等一些只读的公开信息接口,甚至都可以不使用安全技术来保护。所以一切脱离业务要求的安全等级谈安全机制设计都是耍流氓。但是实际上在具体落地的时候我们能经常看到安全机制设计得远远超过了安全等级要求,比如我只是一个简单的开放新闻只读接口,却用了一套很复杂的加密算法。这也要求我们对安全技术有个基本的了解,这样才能对安全团队为我们提供的方案有个清晰的认识,我们站在业务的角度还能有仔细推敲、取舍的能力,选择一套确实符合我们需要的方案,而不至于不小心“杀鸡用了牛刀”,所以下面对加解密算法的一些参数作简单解释。
密钥长度
AES算法最常见的密钥长度是128位、192位、256位。RSA常见的密钥长度(模数位数)1024位和2048位,由于RSA是一对密钥,这里的长度是指模数位数,并不就是说公钥或者私钥的长度就是2048位这么长(实际上私钥会比公钥长很多),这一点需要注意。但是至于什么是模数位数则可以不用了解那么细,这里涉及到密码学的知识,我们只要了解密钥长度越长,理论上安全性越高,算法性能越差,我们在确定密钥长度的时候就需要根据我们的业务要求选择合适的密钥长度。
填充模式
在Java中,加解密相关功能被封装成以下代码所示的API进行操作
Key k = toKey(key);
Cipher cipher;
cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, k);
cipher.doFinal(data);
其中“algorithm”参数传入的是类似“AES/ECB/NoPadding”、“AES/CBC/PKCS7Padding”这样格式的字符串。类似的取值还可能有
RSA/NONE/NoPadding
RSA/NONE/PKCS1Padding
RSA/NONE/OAEPWithMD5AndMGF1Padding
RSA/NONE/OAEPWithSHA256AndMGF1Padding
其中第一个参数表示的是具体的加解密算法,第二个参数是加密的模式,第三个参数是填充模式,这里我们先讲填充模式。简单理解就是一些加密算法首先会对原文进行分块,每一次处理固定长度的内容(block size),比如16个字节,那么如果原文长度不是16字节的整数倍的话会对不足的那些部分进行填充。
加密模式
从上面举例来看,加密模式在AES算法中可以有不同的选择,比如有ECB、CBC、CTR、OCF、CFB、XTS。实际应用中CBC是最常见的(ECB安全性不太够),这种模式是分块进行加密,所以会跟着一种填充模式,对于AES而言,“AES/CBC/PKCS7Padding“是比较常用的加密方式。
初始向量iv
这个也是AES里面特有的参数,在CBC这种分块的算法中,为了增加复杂度,还使用了前一个分块加密后的密文作为一