VeraCrypt内存加密旨在保护存储在易失性内存中的磁盘加密密钥免受某些类型的攻击。该机制的主要目标是:
以下是内存加密实现方式的总结:
HashSeedMask
和 CipherIVMask
。通过使用大内存页进行密钥派生,可以减轻冷启动攻击的影响。这确保攻击者无法恢复主密钥,因为关机后这个大内存区域的部分内容可能会损坏且无法恢复。有关冷启动攻击和缓解技术的更多详细信息,请参阅参考论文:
VeraCrypt的内存加密与Windows休眠和快速启动功能不兼容。在激活内存加密之前,VeraCrypt会禁用这些功能,以确保加密机制的安全性和功能性。
算法的选择基于安全性和性能之间的平衡:
有两个核心算法是内存加密过程的基础:
为要加密的内存缓冲区计算一个唯一ID。
- 输入:pCryptoInfo,一个用于加密/解密的CRYPTO_INFO变量
- 输出:一个64位整数,用于标识pCryptoInfo变量
- 步骤:
- 计算pCryptoInfo的ks和ks2字段的虚拟内存地址之和:encID = ((uint64) pCryptoInfo->ks) + ((uint64) pCryptoInfo->ks2)
- 返回结果
使用VcGetEncryptionID生成的唯一ID对内存缓冲区进行加密。
- 输入:
- encID,要加密的内存的唯一ID
- pbData,指向要加密的内存的指针
- pbKeyDerivationArea,驱动程序在启动时分配的内存区域
- HashSeedMask和CipherIVMask,启动时生成的两个64位随机整数
- 输出:
- 无;pbData处的内存将在原地加密
- 步骤:
- 派生哈希种子:hashSeed = (((uint64) pbKeyDerivationArea) + encID) ^ HashSeedMask
- 计算128位哈希值:hash128 = t1h2 (pbKeyDerivationArea,hashSeed)。
- 将hash128分解为两个64位整数:hash128 = hash128_1 || hash128_2
- 为ChaCha12创建一个256位密钥:chachaKey = hash128_1 || hash128_2 || (hash128_1 OR hash128_2) || (hash128_1 + hash128_2)
- 使用ChaCha12以hashSeed作为IV对chachaKey本身进行加密:ChaCha256Encrypt (chachaKey, hashSeed, chachaKey)
- 派生ChaCha12的64位IV:chachaIV = (((uint64) pbKeyDerivationArea) + encID) ^ CipherIVMask
- 使用ChaCha12对pbData处的内存进行加密:ChaCha256Encrypt (chachaKey, chachaIV, pbData)
- 安全擦除临时值
值得注意的是,由于ChaCha12是一种流密码,加密和解密过程是相同的,因此 VcProtectMemory
函数可同时用于加密和解密。
要深入了解并查看代码库,可以访问VeraCrypt仓库,并在 src/Common/Crypto.c
文件中探索上述函数。
从1.24版本开始,VeraCrypt集成了一种机制,当系统加密处于活动状态时,该机制会检测新设备插入系统的情况。如果插入了新设备,主密钥会立即从内存中清除,导致Windows蓝屏死机(BSOD)。这可以防范使用专用设备从运行中的系统中提取内存的攻击。但是,为了达到最高效率,此功能应与内存加密结合使用。
要启用此功能,请导航至菜单“系统” -> “设置”,并勾选 “如果插入新设备,则从内存中清除加密密钥” 选项。
Windows休眠和快速启动功能会将内存内容保存到硬盘。在VeraCrypt的内存加密上下文中,支持这些功能存在一个重大挑战,即所谓的“先有鸡还是先有蛋”的问题。
为了保持安全性,内存加密中用于密钥派生的大内存区域必须以加密格式存储,与通常应用于当前驱动器的VeraCrypt加密分开。这个单独的加密存储还必须能够使用与预启动身份验证相同的密码解锁。此外,此过程必须在启动序列的早期进行,在文件系统访问可用之前,这就需要将加密数据原始存储在不同磁盘的特定扇区中。
虽然这在技术上是可行的,但这种解决方案的复杂性和对用户不友好性使其不适合标准部署。因此,启用内存加密需要禁用Windows休眠和快速启动功能。