C++ / a working model

160 / 163   ·   C11   ·   约 8 分钟

密码学

先记住这句话

操作系统无法保护已经离开其硬件管辖范围的数据。密码学借助密钥把明文变成密文,使未授权者即便拿到比特也无法还原含义或进行可控篡改。本章用原创讲解介绍对称加密模型、密钥保密的决定性作用,以及哈希如何提供完整性检测。

本篇内容
  1. 当内核的手够不到时
  2. 明文、密文与确定性变换
  3. 算法可以公开,密钥必须保密
  4. 完整性:让篡改变成乱码
  5. 运行示例
  6. 动手练习

官方章节 PDF

当内核的手够不到时

访问控制列表只对内核正在管理的对象有效。U盘被拿走、网线被窃听、另一台机器的内存被转储之后,本地策略立刻失效。因此必须事先把数据变换成一种即使比特全部泄露也毫无价值的形式,这正是密码学要解决的问题。

明文、密文与确定性变换

可读数据称为明文P。加密算法E与密钥K共同产生密文C。解密算法D用同一把密钥把C变回P。两次变换都必须是确定性的,并且在缺少K时从C恢复P应当计算上不可行。我们通常把P看作要发送的消息,把C看作暴露在外的受保护副本。

算法可以公开,密钥必须保密

设计没有弱点的密码极其困难,因此实际系统几乎总是采用经过长期公开分析的标准算法。于是全部安全保障都落在密钥上:一旦K泄露,任何人都能够解密。维护密钥的机密性在真实系统中远比写出加密公式更难,也是实践中最常见的失败点。

完整性:让篡改变成乱码

强密码具有扩散性,密文哪怕改动一个比特,解密结果也会变成无法预测的乱码,攻击者因此无法把明文改成自己想要的内容。若再附上明文的哈希,接收方解密后重新计算并比对,任何改动都会立刻暴露。

常见误区

  • 把加密算法本身当成秘密来依赖,而不是保护密钥。
  • 在缺少随机数或消息计数器的情况下用同一密钥加密大量独立消息。
  • 误以为加密同时证明了数据来源的真实性。

运行一个例子

最低标准 C11 · 完整程序 · 下载 .c

#include <stdio.h>
#include <string.h>
#include <ctype.h>

void caesar_shift(char *s, int shift)
{
    int delta = ((shift % 26) + 26) % 26;
    for (int i = 0; s[i] != '\0'; i++) {
        unsigned char c = (unsigned char)s[i];
        if (isupper(c)) {
            s[i] = 'A' + (c - 'A' + delta) % 26;
        } else if (islower(c)) {
            s[i] = 'a' + (c - 'a' + delta) % 26;
        }
    }
}

int simple_hash(const char *s)
{
    int h = 0;
    for (int i = 0; s[i] != '\0'; i++) {
        h = (h + (unsigned char)s[i]) % 256;
    }
    return h;
}

int main(void)
{
    char buf[64] = "Transfer funds now";
    int h = simple_hash(buf);
    printf("plaintext: %s\n", buf);
    printf("hash: %d\n", h);
    caesar_shift(buf, 3);
    printf("ciphertext: %s\n", buf);
    caesar_shift(buf, -3);
    printf("decrypted: %s hash_match=%s\n", buf, simple_hash(buf) == h ? "yes" : "no");
    caesar_shift(buf, 3);
    buf[4] = 'X';
    caesar_shift(buf, -3);
    printf("tampered decrypt: %s hash_match=%s\n", buf, simple_hash(buf) == h ? "yes" : "no");
    return 0;
}

在本地编译

gcc -std=c11 -Wall -Wextra -Wpedantic -Werror ostep-56-cryptography.c -o example && ./example

预期结果

plaintext: Transfer funds now
hash: 249
ciphertext: Wudqvihu ixqgv qrz
decrypted: Transfer funds now hash_match=yes
tampered decrypt: TranUfer funds now hash_match=no

CHECK YOUR UNDERSTANDING

合上答案,试着解释。

攻击者能够任意改写密文,为什么仍然很难让解密结果变成他指定的明文?怎样才能更可靠地发现这种改写?

查看参考答案

好的密码把密文的微小差异扩散成面目全非的明文,攻击者无法预知该改哪些比特才能得到目标明文。把明文哈希与数据一起保护,解密后重新计算哈希并比较,任何改动都会导致不匹配。

继续查证

标准草案与官方章节会更新;版本标记只说明示例最低要求。

回到目录