磁盘和文件加密xts实现示例

举报
码乐 发表于 2026/01/13 08:40:56 2026/01/13
【摘要】 1 简介XTS (XEX-based Tweaked-Codebook Mode with Ciphertext Stealing) - XTS 模式定义:XTS 专为磁盘加密设计,基于 XEX(XOR-Encrypt-XOR)调整码本,支持无填充的变长块。 2 工作原理:使用两个密钥:数据密钥 K1 和调整密钥 K2(从主密钥派生)。加密:对于第 j 个扇区,第 i 个块:T = E_{...

1 简介

XTS (XEX-based Tweaked-Codebook Mode with Ciphertext Stealing) - XTS 模式

定义:XTS 专为磁盘加密设计,基于 XEX(XOR-Encrypt-XOR)调整码本,支持无填充的变长块。

2 工作原理:

使用两个密钥:数据密钥 K1 和调整密钥 K2(从主密钥派生)。
加密:对于第 j 个扇区,第 i 个块:T = E_{K2}(j) \otimes \alpha^i(Galois 乘法),C_i = E_{K1}(P_i \oplus T) \oplus T。

支持 ciphertext stealing 处理最后不完整块。

优点:无填充、随机访问、防模式泄露、适合固定大小单元。
缺点:无认证(需额外 MAC)、不适合流数据。

安全考虑:提供语义安全,但不防篡改。SM4-XTS 在 IEEE 1619 标准中定义,用于全盘加密。
SM4 应用:硬盘/SSD 加密,如 BitLocker 或 LUKS。

3 服务端示例

一个完整但精简的示例,演示如何用 Go 实现基于 AES-XTS 的“磁盘文件加解密服务 + 客户端”。
示例强调 XTS 的磁盘语义(扇区/块号 tweak、无填充、定长块),而不是网络安全本身。

前提

		Go 1.20+(crypto/cipher.NewXTSCipher 是 1.20 引入的)

XTS 必须使用两把 AES key(总长度 32/48/64 字节)

XTS 不适合流式网络加密,只适合磁盘/文件块

  • 整体设计

架构

    client  --->  http service  --->  磁盘文件
               (XTS 加解密)

关键点

按固定块大小处理(如 4KB,模拟磁盘扇区)

		tweak = sectorIndex(uint64)

不使用 padding

文件大小必须是 blockSize 的整数倍(真实磁盘也是如此)

  • 核心:AES-XTS 工具函数

      package xtsutil
    
      import (
          "crypto/aes"
          "crypto/cipher"
          "encoding/binary"
          "errors"
      )
    
      const BlockSize = 4096 // 模拟磁盘扇区
    
      func newXTSCipher(key []byte) (*cipher.XTSCipher, error) {
          if len(key) != 32 && len(key) != 48 && len(key) != 64 {
              return nil, errors.New("XTS key must be 32/48/64 bytes")
          }
          c, err := aes.NewCipher(key[:len(key)/2])
          if err != nil {
              return nil, err
          }
          return cipher.NewXTSCipher(c, key[len(key)/2:]), nil
      }
    
      func EncryptBlock(key []byte, sector uint64, data []byte) error {
          xts, err := newXTSCipher(key)
          if err != nil {
              return err
          }
          if len(data)%aes.BlockSize != 0 {
              return errors.New("data must be multiple of AES block size")
          }
    
          var tweak [16]byte
          binary.LittleEndian.PutUint64(tweak[:8], sector)
          xts.Encrypt(data, data, tweak[:])
          return nil
      }
    
      func DecryptBlock(key []byte, sector uint64, data []byte) error {
          xts, err := newXTSCipher(key)
          if err != nil {
              return err
          }
          var tweak [16]byte
          binary.LittleEndian.PutUint64(tweak[:8], sector)
          xts.Decrypt(data, data, tweak[:])
          return nil
      }
    

4 服务端:磁盘加解密服务

功能

接收文件

按 4KB 块进行 XTS 加密

写入磁盘

      var key = []byte("0123456789abcdef0123456789abcdef") // 32 bytes

      func encryptHandler(w http.ResponseWriter, r *http.Request) {
          in, _ := os.Create("disk.enc")
          defer in.Close()

          buf := make([]byte, xtsutil.BlockSize)
          sector := uint64(0)

          for {
              n, err := io.ReadFull(r.Body, buf)
              if err == io.EOF || err == io.ErrUnexpectedEOF {
                  break
              }
              if err != nil {
                  http.Error(w, err.Error(), 500)
                  return
              }

              if err := xtsutil.EncryptBlock(key, sector, buf[:n]); err != nil {
                  http.Error(w, err.Error(), 500)
                  return
              }
              in.Write(buf[:n])
              sector++
          }

          w.Write([]byte("encrypted"))
      }

      func decryptHandler(w http.ResponseWriter, r *http.Request) {
          f, _ := os.Open("disk.enc")
          defer f.Close()

          buf := make([]byte, xtsutil.BlockSize)
          sector := uint64(0)

          for {
              n, err := io.ReadFull(f, buf)
              if err == io.EOF || err == io.ErrUnexpectedEOF {
                  break
              }
              if err != nil {
                  http.Error(w, err.Error(), 500)
                  return
              }

              if err := xtsutil.DecryptBlock(key, sector, buf[:n]); err != nil {
                  http.Error(w, err.Error(), 500)
                  return
              }
              w.Write(buf[:n])
              sector++
          }
      }

      func main() {
          http.HandleFunc("/encrypt", encryptHandler)
          http.HandleFunc("/decrypt", decryptHandler)

          log.Println("XTS disk service on :8080")
          log.Fatal(http.ListenAndServe(":8080", nil))
      }
  • 客户端:上传并恢复文件

      func main() {
          data, _ := os.ReadFile("plain.img")
    
          // 上传并加密
          http.Post(
              "http://localhost:8080/encrypt",
              "application/octet-stream",
              bytes.NewReader(data),
          )
    
          // 下载并解密
          resp, _ := http.Get("http://localhost:8080/decrypt")
          defer resp.Body.Close()
    
          out, _ := os.Create("plain.dec.img")
          defer out.Close()
          io.Copy(out, resp.Body)
      }
    
  • 运行方式

    go run server.go
    go run client.go
    

验证:

sha256sum plain.img plain.dec.img

应完全一致

4 使用限制

真实磁盘/生产注意事项(非常重要)

XTS key 管理

每块磁盘唯一 key

不要重复 tweak + key

tweak 设计

通常 = 物理扇区号

不能重复

文件大小

必须是块大小整数倍

不要用于普通文本/网络数据

不要

不要用 XTS 保护传输

不要复用同一 key + sector

5 小结

这些模式的选择取决于需求:ECB/CBC 简单但安全性较低;CFB/OFB/CTR 适合流式;GCM/CCM 提供认证;XTS 专为存储。

SM4 在中国标准(如 GM/T 0002-2012)中支持这些模式,实际使用时需注意 IV/nonce 管理、填充和密钥派生。推荐优先使用 AEAD 模式如 GCM 以确保完整性。

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

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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