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