高校|密码算法靠数学提高安全性( 四 )


ECB 模式的优势很明显 , 首先加密逻辑非常简单 , 其次由于上下文无关 , 所以有利于并行计算 , 最后仍然得益于上下文无关 , 误差不会被传递;它的劣势也是很清晰的 , 一方面是无法隐藏明文的模式 , 另一方面攻击者可以直接对明文进行主动攻击 。
为了增强 ECB 模式的安全性 , CBC 模式被引入进来 。 CBC 全称是密码分组链接(CBC , Cipher-block chaining)模式 。 在 CBC 模式下 , 每个明文块需要先与前一个密文块进行异或(xor) , 然后再进行加密 , 因此每个密文块都依赖于它前面的所有明文块 。 那么初始化向量又是在何处被引入的呢?为了保证每条消息的唯一性 , 在第一个明文块会直接与初始化向量进行异或 。 用数学语言来表述如下:
cipher_text_0 = IV
cipher_text_i = E_k{plain_text_i XOR cipher_text_{i-1
如果 CBC 模式下的初始化向量发生重复使用、全 0 设置等情况 , 就会使同样的明文产生同样的密文结果;即使初始化向量未发生重用 , 对于攻击者来说密文仍然是可预测的 , 这依然会使加密算法在面对选择明文攻击时的安全性大大降低 。
如下代码使用 CBC 模式进行加密 , 但在编码过程中将初始化向量设置为全 0 , 这就导致密文更加容易预测 , 并且可能会面临字典攻击等安全威胁:
public class Cipher {
public static void main() {
byte[
plain_text = \"Hello World!\".getBytes();
byte[
iv = {
0x000x000x000x000x000x000x000x00
;
KeyGenerator kg = KeyGenerator.getInstace(\"DES\");
kg.init(56);
SecretKey key = kg.generateKey();
Cipher cipher = Cipher.getInstace(\"DES/CBC/PKCS5Padding\");
IvParameterSpec ips = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE key ips);
// ...


不安全的 Padding
许多加密算法都支持 padding 机制 , 一方面 padding 是为了补全明文 , 使其满足加密算法的格式要求;另一方面在 padding 机制产生作用后 , 明文将更难以预测 , 攻击者的攻击复杂度也会相应提高 。 以下是一种典型的错误示例:
public Cipher getRSACipher() {
Cipher rsa = null;
try {
rsa = javax.crypto.Cipher.getInstance(\"RSA/NONE/NoPadding\");

catch (Exception e) {
// ...

return rsa;

案例实战通过一系列典型的安全风险场景 , 相信你对密码安全风险已经有了更加深刻的理解 。 接下来我们从两个更为复杂的实战案例出发 , 看看它在实际应用中又能给我们什么启发 。
数字签名伪造
我们知道数字签名是互联网信任体系的根基 , 那么数字签名是否一定是可信的呢?为了寻找答案 , 我们要站在攻击者的视角来审视整个体系 。
设想一种场景 , 在这种场景中攻击者试图执行一次签名诈骗攻击 。 首先攻击者准备了一份正常的合同 m , 以及一份伪造的合同 m_fake , 在不改变合同原本意义的情况下 , 通过插入逗号、空行、空格、同义词替换等行为 , 攻击者可以生成一系列以 m 和 m_fake 为原型的合同变体 。 攻击者了解在合同签署过程中使用的签名函数是 f() , 并通过运算在所有合同变体中找到了 f(m) = f(m_fake) , 于是攻击者可以将 m 带给合作方签名 。 在签名完成后 , 攻击者可以将签名取下并附到 m_fake 上 , 以此来证明合作方签署了 m_fake 合同 。
再设想一种场景 , 我们都知道在下载软件安装包时 , 最好的情况是去官网下载 , 一方面是来源更可信 , 另一方面是官网同时也会披露对应安装包的 MD5 值供用户验证 。 那么如果攻击者通过碰撞的方式 , 制造出了一个恶意应用程序 , 同时该恶意程序的 MD5 值与官方安装包一致 , 就可能会导致用户错误地安装恶意程序 , 从而被攻击者控制 。

推荐阅读