存储加密模式的设计哲学

举报
码乐 发表于 2026/01/06 08:12:51 2026/01/06
【摘要】 1 简介存储加密模式的选择触及了存储加密的核心技术选型问题。XTS和GCM代表了两种不同的设计哲学。本文试图深入分析。 存储加密选XTS:因为它为随机访问、扇区独立性、零开销优化 数据传输选GCM:因为它提供完整性和认证,适合流式数据 2 XTS模式:为存储加密而设计XTS(XEX-based tweaked-codebook mode with ciphertext stealing...

1 简介

存储加密模式的选择触及了存储加密的核心技术选型问题。XTS和GCM代表了两种不同的设计哲学。本文试图深入分析。

  存储加密选XTS:因为它为随机访问、扇区独立性、零开销优化

  数据传输选GCM:因为它提供完整性和认证,适合流式数据

2 XTS模式:为存储加密而设计

XTS(XEX-based tweaked-codebook mode with ciphertext stealing)原理
核心设计目标:磁盘/存储设备加密
XTS简化工作流程

    void xts_encrypt_sector(sector_data, sector_number) {
        // 关键:每个扇区独立加密,扇区内可随机访问
        tweak = generate_tweak(sector_number);  // 基于扇区号

        for (int i = 0; i < blocks_in_sector; i++) {
            // 每个块的加密都基于tweak
            encrypted_block[i] = encrypt(
                plain_block[i] ⊕ f(tweak, i),  // 与位置相关
                key
            ) ⊕ f(tweak, i);
        }
    }
  • XTS的存储专用特性

1. 随机访问能力(决定性优势)

模拟磁盘读取场景

    class DiskStorage:
        def read_sector(self, sector_num, offset, length):
            # 传统加密模式的问题
            if using_cbc_or_gcm:
                # 要解密offset=4096的数据,必须从sector=0开始解密
                # 因为链式依赖!
                data = b""
                for i in range(0, sector_num + 1):
                    encrypted = self.raw_read_sector(i)
                    data += decrypt(encrypted)  # 必须顺序解密

                return data[offset:offset+length]  # 性能灾难!

            # XTS解决方案
            elif using_xts:
                # 直接解密目标扇区,无需前序扇区
                encrypted = self.raw_read_sector(sector_num)
                return xts_decrypt_sector(encrypted, sector_num)[offset:offset+length]
                # O(1)时间复杂度!

实际性能对比:

场景:读取1TB SSD中位于中间位置的文件(500GB处)

  • GCM/CTR/CBC:必须从0解密到500GB才能访问
    时间:~20分钟(假设解密速度500MB/s)
    内存:需要缓存或重新解密

  • XTS:直接解密目标扇区
    时间:~10毫秒
    内存:只需一个扇区缓存(通常4KB)

2. 定位数据(Tweak机制)

XTS的tweak生成

    uint8_t* xts_generate_tweak(uint64_t sector_number, int block_index) {
        // tweak = 扇区号 + 块在扇区内的位置
        uint8_t tweak[16] = {0};

        // 扇区号(通常64位)
        memcpy(tweak, &sector_number, 8);

        // 块索引(通常64位中的剩余部分)
        uint64_t position = block_index;
        memcpy(tweak + 8, &position, 8);

        // 关键:相同的明文块,在不同的(sector, position)会加密成不同密文
        return tweak;
    }

示例:数据库记录的物理存储

– 假设用户表存储在扇区1000-1100
– 每个扇区512字节,存储多个用户记录

用户A记录:{id: 1001, name: “Alice”, balance: 5000}
用户B记录:{id: 1002, name: “Bob”, balance: 5000} – 相同余额!

– XTS加密后:
– 用户A的"5000"在扇区1002,块位置3
– 用户B的"5000"在扇区1005,块位置1
– 即使数值相同,tweak不同 → 密文完全不同!
– 解决了ECB的模式泄露问题

3. 无需完整性保护的设计哲学

存储加密的特殊需求:

磁盘/存储的故障模型:

  1. 位翻转(罕见)
  2. 扇区损坏(坏块)
  3. 数据老化(SSD读干扰)

但不像网络传输:

  1. 没有主动的中间人攻击者
  2. 篡改需要物理访问或内核漏洞
  3. 完整性由文件系统/RAID/ECC保障

因此XTS假设:完整性由上层保证
XTS在国密中的应用:SM4-XTS

国密SM4-XTS实现要点

    int sm4_xts_encrypt_sector(
        const uint8_t *plaintext,   // 扇区明文
        uint8_t *ciphertext,        // 扇区密文  
        size_t sector_size,         // 扇区大小(512B/4KB)
        uint64_t sector_number,     // 扇区号
        const uint8_t key1[16],     // 数据加密密钥
        const uint8_t key2[16]      // tweak加密密钥
    ) {
        // 1. 生成tweak
        uint8_t tweak[16];
        sm4_xts_generate_tweak(sector_number, tweak);

        // 2. 用key2加密tweak
        uint8_t encrypted_tweak[16];
        sm4_encrypt(key2, tweak, encrypted_tweak);

        // 3. 分块加密扇区数据
        for (int i = 0; i < sector_size / 16; i++) {
            // 每个块独立加密,基于encrypted_tweak和块位置
            uint8_t block_tweak[16];
            sm4_xts_update_tweak(encrypted_tweak, i, block_tweak);

            // XEX模式:P ⊕ T → 加密 → ⊕ T
            xor_block(plaintext + i*16, block_tweak, temp);
            sm4_encrypt(key1, temp, temp2);
            xor_block(temp2, block_tweak, ciphertext + i*16);
        }

        return 0;
    }

3 为什么存储不推荐GCM

GCM在存储场景的五大问题

  • 问题1:链式依赖破坏随机访问

GCM使用递增计数器
要解密计数器N,需要知道计数器0…N-1?
实际上CTR模式可以独立计算,但是:

** GCM的CTR模式导致依赖关系

  class GCMStorage:
      def read_random_position(self, offset, length):


          # 问题:认证标签是全局的!
          tag = calculate_gmac(entire_ciphertext)  # 需要全部数据

          # 要验证部分数据的完整性:
          # 1. 要么预先计算整个文件的tag(不现实)
          # 2. 要么分块单独认证(丧失GCM优势)

          # 对比XTS:每个扇区独立,无链式依赖
  • 问题2:认证标签的存储开销

计算存储成本:

假设:1TB数据库,4KB页大小

XTS方案:
总数据:1TB
开销:0(无额外认证数据)
实际存储:1TB

GCM方案(每页单独认证):
数据:1TB
每页16字节tag:1TB / 4KB × 16B = 4GB
总存储:1TB + 4GB = 1.004TB
开销:0.4%

GCM方案(整个文件一个tag):
数据:1TB
tag:16字节
总存储:1TB + 16B ≈ 1TB
但:无法随机访问验证!
更严重的是数据库场景:

– 考虑B+树索引的更新

			UPDATE users SET balance = 5000 WHERE id = 1001;

– XTS:只需重写对应扇区
– 开销:4KB写入

– GCM(每页单独tag):
– 1. 读取旧页(4KB + 16B tag)
– 2. 验证tag
– 3. 修改数据
– 4. 生成新tag
– 5. 写入新页(4KB + 16B)
– 开销:8KB+32B读写,计算两次GCM

– GCM(全局tag):
– 修改一个记录 → 需要重新计算整个1TB文件的tag!
– 完全不可行

  • 问题3:Nonce管理灾难

GCM的Nonce必须唯一,但在存储中…

    class GCMDiskEncryption:
        def write_sector(self, sector_num, data):
            # 每次写入都需要新Nonce
            nonce = generate_nonce()

            # 问题1:存储Nonce在哪?
            # 选项A:与数据一起存储 → 每扇区额外12字节
            # 选项B:从扇区号派生 → 但重写扇区需要新Nonce!

            # 问题2:扇区重写(写放大)
            for i in range(1000):
                # SSD的同一逻辑扇区可能写到不同物理位置
                self.write(sector_num, data)  # 每次需要新Nonce

            # 问题3:垃圾回收后,物理移动数据需要保持Nonce?

            # XTS解决方案:tweak从扇区号派生,天然唯一
  • 问题4:性能问题(特别是小写操作)

基准测试场景:

测试:4KB随机写操作

  void benchmark_random_writes() {
      // XTS性能
      double xts_time = measure_time([]{
          xts_encrypt_sector(data, sector_num);  // 一次SM4调用/tweak
      });

      // GCM性能  
      double gcm_time = measure_time([]{
          gcm_encrypt(data, nonce);  // 需要GHASH + CTR
          // GHASH:有限域乘法,比XTS的简单变换慢
      });

      // 典型结果(SM4软件实现):
      // XTS: 2.1µs 每扇区
      // GCM: 3.8µs 每扇区  (慢80%)
  }

数据库OLTP场景影响:

TPC-C基准测试(订单处理系统):

  • 90%操作是随机4-8KB读写
  • 要求亚毫秒级延迟

使用XTS:平均延迟 0.8ms
使用GCM:平均延迟 1.4ms (增加75%)
TPS下降:~30%
问题5:与现有存储栈的兼容性
Linux磁盘加密栈(dm-crypt):

  • XTS是Linux标准

     	cryptsetup luksFormat --cipher aes-xts-plain64 /dev/sda1
    

尝试使用GCM:

		cryptsetup luksFormat --cipher aes-gcm /dev/sda1

错误:不支持!

原因:

    # 1. 需要存储/管理Nonce
    # 2. 随机访问性能差
    # 3. 与TRIM/discard命令不兼容

文件系统层的不匹配:

文件系统期望的行为

    struct storage_driver {

        int (*read)(sector_t sector, void *buffer);
        int (*write)(sector_t sector, const void *buffer);
        // 隐含假设:扇区操作是独立的、幂等的
    };

GCM违反这些假设:

  1. write不是幂等(需要新Nonce)
  2. 独立read需要全局验证

问题6:数据恢复的复杂性
灾难恢复场景:

硬盘部分损坏,需要恢复数据:

XTS方案:

  • 损坏扇区:仅丢失该扇区数据
  • 健康扇区:可直接解密
  • 恢复工具:可逐个扇区尝试恢复

GCM方案(全局tag):

  • 任何损坏 → tag验证失败
  • 整个卷无法解密
  • 恢复几乎不可能

GCM方案(每扇区tag):

  • 损坏扇区:tag损坏无法验证
  • 即使数据完好,也无法解密
  • 恢复需要绕过认证(破坏安全目标)

4 实际应用场景分析

  • 场景1:全盘加密(FDE)

Linux LUKS配置对比
XTS方案(生产标准):

    cryptsetup luksFormat \
        --cipher sm4-xts-plain64 \
        --key-size 512 \          # 两个256位密钥
        /dev/nvme0n1p1

为什么不用GCM?原因:

  1. /boot分区需要随机访问(GRUB无法处理GCM)
  2. 休眠到磁盘:需要直接写入内存镜像
  3. SSD TRIM:XTS允许标记扇区为空
  • 场景2:数据库透明加密(TDE)

– MySQL表空间加密
– XTS方案:

    INSTALL PLUGIN keyring_file SONAME 'keyring_file.so';
    CREATE TABLESPACE encrypted_ts 
      ADD DATAFILE 'encrypted.ibd'
      ENCRYPTION='Y' 
      ENCRYPTION_KEYRING='keyring_file'

– 内部使用类似XTS的模式
– 每页(16KB)独立加密

– 尝试GCM的问题:
– 1. InnoDB的doublewrite buffer:需要独立页加密
– 2. 缓冲池管理:页可任意换入换出
– 3. 物理备份:需要逐页验证或全局tag

  • 场景3:云存储服务端加密

对象存储加密设计

  class ObjectStorageEncryption:
      def __init__(self):
          # AWS S3的实际选择:
          # - 小对象(<1MB):AES-GCM(一次处理)
          # - 大对象(>1MB):AES-CTR + HMAC(流式)
          # - 但底层EBS卷:AES-XTS!

          # 为什么分层?
          self.small_obj_cipher = AES_GCM()    # 对象级,完整
          self.large_obj_cipher = AES_CTR_HMAC() # 流式,可分片
          self.block_storage = AES_XTS()       # 卷级,随机访问
  • 场景4:固态硬盘(SSD)主控加密

SSD硬件加密引擎

      struct ssd_encryption_engine {
          // 必须使用XTS的原因:
          // 1. 逻辑到物理地址映射(FTL)
          uint32_t lba_to_ppa(uint32_t lba);  // 动态重映射

          // 2. 写放大优化
          void garbage_collection() {
              // 移动数据时,XTS:tweak基于LBA,不变
              // GCM:需要新Nonce,但数据未改!
          }

          // 3. TRIM/UNMAP支持
          void process_trim(uint32_t lba) {
              // XTS:直接标记扇区可加密擦除
              // GCM:需要保持Nonce一致性?复杂!
          }
      };

国密标准中的定位

GB/T 17964-2021 中的角色

存储加密标准体系:

  1. 基础算法:SM4
  2. 存储模式:SM4-XTS(GB/T XXXXX,待发布)
  3. 完整性补充:可搭配SM3-HMAC(上层)
  4. 密钥管理:配合SM9/密码机

定位:XTS是存储加密的"传输层",不是完整解决方案
完整存储加密方案

企业级存储加密架构

    class EnterpriseStorageEncryption:
        def __init__(self):
            # 分层安全设计
            self.layers = {
                # 层1:物理加密(XTS)
                "physical": SM4_XTS_Disk_Encryption(),

                # 层2:文件系统加密(可选GCM)
                "filesystem": {
                    "metadata": SM4_GCM(),  # 元数据需要完整保护
                    "small_files": SM4_GCM(),  # 小文件
                    "large_files": SM4_CTR_HMAC(),  # 大文件流
                },

                # 层3:应用层加密(业务逻辑)
                "application": {
                    "database": Column_Level_Encryption(),
                    "backup": SM4_GCM_With_Key_Rotation(),
                }
            }

        def encrypt_data(self, data, context):
            # 根据上下文选择合适层
            if context == "disk_block":
                return self.layers["physical"].encrypt(data)
            elif context == "database_record":
                # 应用层加密 + 物理层加密
                app_encrypted = self.layers["application"]["database"].encrypt(data)
                return self.layers["physical"].encrypt(app_encrypted)

什么情况下存储可以用GCM?
适合GCM的存储场景:
备份归档:

备份文件(一次性写入,顺序读取)

      def encrypt_backup(backup_file):
          # 整个备份文件一个GCM tag
          nonce = generate_nonce()
          ciphertext, tag = sm4_gcm_encrypt(
              backup_file.read(), 
              key, 
              nonce
          )

存储:nonce(12B) + tag(16B) + ciphertext
优点:强完整性验证
缺点:无法随机恢复部分文件
对象存储的小对象:

对象大小 < 1MB,且一次性读写
例如:用户头像、配置文件、API密钥
加密的通信协议中的存储:

如:TLS会话票据缓存
特点:体积小,需要强认证,与网络协议一致.

5 小结

为什么存储专用XTS,而不推荐GCM

  维度		XTS							GCM
  设计目标	存储设备随机访问				网络数据流保护
  核心假设	存储介质可信,完整性上层保障	传输信道不可信,需要端到端认证
  访问模式	任意位置O(1)访问				顺序访问或全局验证
  更新开销	扇区级,最小化写放大			Nonce管理复杂,可能全局重算
  兼容性	与文件系统、SSD、RAID完美集成		破坏存储栈假设

XTS像"加密的RAM":每个地址独立,直接访问

GCM像"加密的TCP流":需要顺序处理,整体验证

在国密体系中,SM4-XTS将是存储加密的标准选择,而SM4-GCM适用于通信和需要强认证的场景。两者各司其职,共同构建完整的安全体系。

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。