neliva/Neliva.Security.Cryptography.PackageProtector
GitHub: neliva/Neliva.Security.Cryptography.PackageProtector
PackageProtector 提供一种基于分块认证加密的静态数据保护机制,专为不可信远程存储中的安全长期数据存储而设计。
Stars: 2 | Forks: 0
## PackageProtector
本仓库描述了针对不可信远程存储的安全静态数据保护机制。其规范和参考实现均已进入公共领域。请参阅 [UNLICENSE](UNLICENSE.md) 文件。
[](https://github.com/neliva/Neliva.Security.Cryptography.PackageProtector/actions/workflows/main.yml)
[](https://dotnet.microsoft.com/en-us/download/dotnet/10.0)
[](https://www.nuget.org/packages/Neliva.Security.Cryptography.PackageProtector)
## 概述
PackageProtector 结合了 SP800-108 CTR KDF、HMAC-SHA512 和 AES256-CBC 算法,构成了一种密钥承诺且消息/上下文承诺的认证加密设计。数据流被分割为大小相等的块(最后一个块除外),每个块被单独签名和加密。这种方案允许对任意长度的流进行随机读写,并保证返回的数据已通过认证。PackageProtector 专为安全的长期存储而设计。
受保护的流没有标头、标记或标识符。这使得受保护的流与随机数据无法区分。如果没有密钥,就无法确定受保护的流是否由 PackageProtector 生成,也无法进行流量分析。
### 用法
```
// using Neliva.Security.Cryptography;
// Use the system protector (32-byte IV, 64 KiB package size)
var protector = PackageProtector.System;
var keyBytes = new byte[32];
RandomNumberGenerator.Fill(keyBytes);
using var key = new PackageKey(keyBytes);
// Protect
await protector.ProtectAsync(srcContentStream, destProtectedStream, key /*, associatedData */);
// Unprotect
await protector.UnprotectAsync(srcProtectedStream, destContentStream, key /*, associatedData */);
```
### 算法
许多认证加密算法(例如 AES-GCM 或 ChaCha20-Poly1305)在现代硬件上表现非常出色。然而,这些算法存在一些不足:
* 在流加密中重用密钥和 nonce 是灾难性的。
* 认证标签仅为 16 字节。
* 没有密钥承诺或消息承诺。
分组密码存在其自身的问题,例如填充预言攻击。PackageProtector 采用 PKCS7 填充方案,并以*先填充、后认证、再加密*的模式运行,以防范填充预言攻击。CBC 模式为密钥/IV 的重用以及(在需要时)对单个块的重新加密提供了额外的安全性。算法性能并非 PackageProtector 的首要目标。该设计在 MAC 和加密操作中特意采用了分离的算法和密钥。
## 流格式
PackageProtector 将任意数据流分割成多个块。块的**内容**被封装在**包**中。包的大小是可配置的,并且必须是 16 字节的倍数。PackageProtector 允许使用 0、16 或 32 字节的 KDF IV。每个包的最大内容大小取决于 KDF IV 的大小。
对于 16 字节的 KDF IV,包的布局如下:
```
| package, 64 bytes - 1GiB |
+-----------------------------------------------------------------------------------+
| KDF IV | MAC(content || pad) | chunk content | PKCS7 pad |
+-------------+------------------------+--------------------------+-----------------+
| 16 bytes | 32 bytes | 0 - (1GiB - 49 bytes) | 1 - 16 bytes |
+-------------+---------------------------------------------------------------------+
| | encrypted (no padding) |
```
KDF **IV** 由为每个包生成的加密强随机字节组成。当更新包时,必须生成新的随机字节。放置在块内容之前的 MAC 同时也作为 CBC 模式的合成 IV。当 KDF IV 大小为零时,内容将以确定性方式加密。
所有包(包括可能不完整的最后一个包)都具有相同的格式。*流结束*由不完整或空的包表示。不完整的包含有不止一个填充字节。空的包具有零长度的*内容*。
*包大小*用于控制在保护和取消保护单个包期间保存在内存中的数据量。推荐的默认大小为 64 KiB,但可以根据应用程序的需求进行更改。
## 流密钥
给定数据流的**包密钥**,PackageProtector 使用计数器模式(SP800-108)下的 KDF-HMAC-SHA512 为每个包派生出 MAC 和 ENC 密钥。这提供了一定程度的密钥间接性。恢复出的每个包的密钥不能用于恢复其他包或该流的包密钥。
KDF 使用以下**派生密钥上下文**:
* 密钥用途(加密或签名)
* **包编号**(64 位整数,从 0 开始顺序递增)
* **包大小**(32 位无符号整数,所有流包的值相同)
* 最大包填充大小
* KDF IV(0/16/32 字节,为每个包随机生成)
* 流**关联数据**(0 - 80 字节,由用户提供)
```
32 - 64 bytes 64 bytes
+----------------+ +-------+ +----------+ +--------------+ +-------+
| package key |---->| |---->| MAC key |---->| HMAC-SHA512 |---->| |
+----------------+ | ----- | +----------+ +--------------+ | |
| KDF | | PKG N |
+----------------+ | ----- | +----------+ +--------------+ | |
| key context N |---->| |---->| ENC key |---->| AES256-CBC |---->| |
+----------------+ +-------+ +----------+ +--------------+ +-------+
102 bytes 32 bytes
```
KDF 上下文经过优化,可适配单个 HMAC-SHA512 块以减少计算开销。PackageProtector 将包密钥大小限制为 32-64 字节以提供足够的安全性。**推荐的密钥大小为 64 字节。**
数据流可以包含可选的*关联数据*上下文(最多 80 字节),供 KDF 使用。在取消保护流时必须提供相同的值。使用*关联数据*不会产生额外开销,但是 KDF IV 和关联数据的总大小不能超过 80 字节。
## 流安全性
只要每个数据流的包密钥和*关联数据*组合是唯一的,PackageProtector 就能保证检测出以下情况:
* 包重排
* 流截断
* *流结束*标记后的额外数据
* 来自不同流的包替换
## 流限制
每个包都独立地受到密钥的保护,该密钥由流的包密钥和包密钥上下文派生而来。PackageProtector 使用 *int64* 表示包编号。给定最大为 9223372036854775807 的*包编号*、默认的 64 KiB *包大小*以及 16 字节的 KDF IV,可受保护的数据量为:
* 每个包 *64 KiB - 49 字节*的内容
* 每个包密钥和*关联数据*组合 *~511 ZiB* 的内容
标签:ProjectDiscovery, 加密解密, 多人体追踪, 密码学, 手动系统调用, 数据保护