风险无法消除,但可以减轻。
创建一个单独的静态内存区域,该区域将是您存储明文密钥的唯一位置。并创建一个随机数据缓冲区,您将使用它来异或任何未存储在这个静态缓冲区中的键。
每当您将密钥从密钥文件或其他内容读入内存时,您只需将其直接读入这个静态缓冲区,与随机数据进行异或并将其复制到您需要的任何地方,然后立即用零清除缓冲区。
您可以通过比较它们的掩码版本来比较任意两个键。您甚至可以比较屏蔽键的哈希值。
如果您需要对明文密钥进行操作 - 例如生成哈希或验证他们的密钥以某种方式将屏蔽的异或密钥加载到这个静态缓冲区中,将其异或返回到明文并使用它。然后将零写回该缓冲区。
unmasking、operating 和 remasking 的操作应该很快。不要让缓冲区长时间处于未屏蔽状态。
如果有人尝试进行冷启动攻击,拔掉硬件插头并检查内存芯片,那么只有一个缓冲区可以保存明文密钥,而且在冷启动的特定时刻很有可能攻击缓冲区将是空的。
在对密钥进行操作时,您甚至可以在需要验证密钥之前一次只取消屏蔽密钥的一个字,这样完整的密钥就不会存储在该缓冲区中。
@update:我只是想解决以下 cmets 中的一些批评:
“通过默默无闻的安全”这一短语通常被误解。在安全算法的形式分析中,“模糊性”或隐藏非密码安全数据的方法不会增加密码算法的形式安全性。在这种情况下确实如此。鉴于密钥存储在用户机器上,并且必须由该机器上的该程序使用,因此无法使该机器上的密钥加密安全。无论您使用什么过程来隐藏或锁定数据,程序都必须在某些时候使用它,而坚定的黑客可以在代码中设置断点并观察程序何时使用数据。但是这个帖子中没有任何建议可以消除这种风险。
有人建议 OP 找到一种方法来使用带有锁定内存芯片的特殊硬件或锁定芯片的某种操作系统方法。这在密码学上不再安全。最终,如果您对机器有物理访问权,那么足够坚定的黑客可以使用内存总线上的逻辑分析仪并恢复任何数据。此外,OP 已经声明目标系统没有这样的专用硬件。
但这并不意味着您无法采取任何措施来降低风险。使用最简单的访问密钥——密码。如果您对机器有物理访问权限,则可以放入键盘记录器,或获取正在运行的程序的内存转储等。因此,从形式上讲,密码并不比以明文形式写在粘在键盘上的便签上更安全。然而,每个人都知道在便签上保留密码是一个坏主意,而且对于程序以明文形式向用户回显密码是不好的做法。当然,实际上,这大大降低了攻击者的门槛。然而,正式的带有密码的便签也同样安全。
我上面提出的建议具有真正的安全优势。除了安全密钥的“异或”屏蔽之外,任何细节都不重要。并且有一些方法可以使这个过程变得更好一些。异或密钥将限制程序员必须考虑作为攻击向量的位置数量。一旦密钥被异或,您可以在整个程序中拥有不同的密钥,您可以复制它们,将它们写入文件,通过网络发送它们等。除非攻击者拥有异或缓冲区,否则这些事情都不会危及您的程序。所以有一个你必须担心的单一缓冲区。然后,您可以放松系统中的所有其他缓冲区。 (并且您可以 mlock 或 VirtualLock 那个缓冲区)
一旦您清除了异或缓冲区,您就可以永久且安全地消除攻击者从您程序的内存转储中恢复任何密钥的可能性。您正在限制您的曝光,无论是地点数量还是可以恢复密钥的时间。而且您正在建立一个系统,该系统允许您轻松使用密钥,而无需在对包含密钥的对象进行每次操作时担心恢复密钥的可能简单方法。
因此,您可以想象一个系统,其中键引用异或缓冲区,当不再需要所有键时,您将异或缓冲区归零并删除,所有键都变得无效和不可访问,而无需跟踪它们并担心关于内存页面是否被换出并仍然保存明文密钥。
您也不必真正保留随机数据的缓冲区。例如,您可以使用加密安全的随机数生成器,并根据需要使用单个随机种子来生成异或缓冲区。攻击者恢复密钥的唯一方法是访问单个生成器种子。
您还可以根据需要在堆栈上分配明文缓冲区,并在完成后将其清零,这样堆栈极不可能留在芯片缓存中。如果完整的密钥从未被解码,而是根据需要一次解码一个单词,即使访问堆栈缓冲区也不会泄露密钥。