磁盘和文件加密xts实现示例
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 以确保完整性。
- 点赞
- 收藏
- 关注作者
评论(0)