是否有一个文件系统提供一个每个人都可以写入但只有目录所有者可以读取文件的目录?理论上它可以通过在写入时使用公钥加密来完成,但我发现它比对称磁盘加密要复杂得多。目的是让每个人都有自己的目录,其他人可以将文件放入其中,即一种安全的消息传递系统,只是在文件系统级别。
除了所有者之外,任何人(甚至不是root)都应该被允许读取文件,因此访问权限无济于事。让我们假设系统受到键盘记录器等的保护。
是否有一个文件系统提供一个每个人都可以写入但只有目录所有者可以读取文件的目录?理论上它可以通过在写入时使用公钥加密来完成,但我发现它比对称磁盘加密要复杂得多。目的是让每个人都有自己的目录,其他人可以将文件放入其中,即一种安全的消息传递系统,只是在文件系统级别。
除了所有者之外,任何人(甚至不是root)都应该被允许读取文件,因此访问权限无济于事。让我们假设系统受到键盘记录器等的保护。
据我所知,这种方案在使用全块级仅 RSA 非混合加密的通用操作系统中的通用文件系统中不可用。这是因为软件中的 RSA 之类的操作通常比它们的对称操作慢,并且需要大量的额外实现,当用户级应用程序足以满足此目的时,这些操作被认为是不必要的。linux 内核和其他内核关心在用户空间中支持广泛的通用应用程序,因此通常不会包含任何对普通通用用户功能不必要的功能。但是,这并不是说您不能这样做。人们已经在内核空间中实现了 Web 服务器。如果你愿意,你可以这样做。
只是为了覆盖我所有的基地;显然,内核可选地支持很多硬件,包括一些可以提供硬件辅助加密的硬件。在这种情况下,您的生活会变得容易得多。
PGP/TLS 等实现的混合方案的弱点在于对称密钥本质上是对加密数据的读写。如果你能截获它,你就可以读取数据。毫无疑问,这很难做到,但却是可能的。在文件系统中,您的生活变得更轻松,因为读/写系统调用将在其缓冲区中包含未加密的数据,如果您是 root,您可以拦截这些数据。
我相信您会问为什么鉴于公钥密码术允许您在技术上实现这种形式的访问控制(写入,不读出),为什么还没有完成。是的,我试图回答您为什么不进行逐块 RSA。所以,分两个部分:
关于为什么 RSA 没有包含在内核中
您可能会惊讶地发现您的 linux 内核(或者可能在 Windows 内核中 - 我敢打赌它在用户空间中)中没有 RSA 的实现。
首先,让我们看看内核中有什么:这是来自 Linus 主树的加密文件夹。看不到不对称算法。请记住,我们仍然在这里讨论文件系统。
下一步,我们如何实现 RSA。在寄存器级别,x64(如与 AMD64/EM64T 兼容)处理器每个寄存器可以准确地保存 64 位。这就是为什么你有像uint32_t
和uint64_t
in这样的类型stdint.h
以及为什么会发生整数溢出的原因。
如果您不完全理解为什么这是相关的,那么 RSA 密钥要求您生成一定位长的模数;建议使用 2048 我相信尽管因式分解 1024 已经够难了(搜索 Thomas Pornin 的帖子以获取关于此处和加密的因式分解的讨论)。假设是 2048 位。您可能已经注意到,在单个寄存器中,我们实际上无法存储该数字。所以我们有点忙于将它加载到寄存器中并随后对其进行操作,不是吗?
好的,那么我们如何处理 RSA 所需大小的整数。将大量 64 位块链接在一起基本上就是答案。x86 处理器支持adc
add with carry 等操作。当您添加两个将最高有效位设置在一起并因此溢出的寄存器时,会发生什么情况是进位标志已设置,并且下一次adc
运行将在最低有效位上添加额外的 1。
这个事实使我们能够开始接近任意精度的算术。现在,我们只需要 32 个 64 位的内存块来存储我们乘法的一侧和结果,以及更多x
的 64 位内存块来存储另一个数字。这使我们能够实际生成我们的模数。
让我们加快这个理论的速度,否则我们会在这里整晚。无论您在 bignum 库中以何种方式查看,加法基本上都是 O(N)。如果其中一个运算符只是一个分支(64 位块;分支是它的大数项),则乘法和求幂之类的事情可以减少到 O(N);但是,对于两个任意数字,诸如乘法和除法之类的运算总是更糟。为了加快这一进程,我们付出了巨大的努力。我所知道的关于算法及其运行时的最佳总结可以在这里找到:现代计算机算术。但是,我想说它实际上是高度理论化的算法列表,并且Don Knuth 的半数字算法包含更易于理解的介绍。
现在,bignum 操作很快。不只是快,就像愚蠢的快。快得惊人。循环展开的手按平台组装快速优化。GNU MP被广泛认为是地球上最快的通用 bignum 库,被 Mathematica、Maple、Pari/GP 和其他任何进行任意精度算术的人使用。事实证明,GPG 或 OpenSSL 都没有使用它来支持他们自己的 bignum 实现,但这是他们的选择。
相比之下,AES,一旦你扩展了 SBox 和密钥扩展,实际上是两件事:一个你永远不会添加到(SBox)的哈希表(因此总是 O(1))和一个用于密钥扩展的查找表(还有 O(1)) 和一些异或运算。
所以,我认为相对于 AES 来说,RSA 相当慢,对吧?每次操作的计算成本更高。
编辑我刚刚醒来时想到了另一个原因,那就是你为什么不这样做。请参阅此链接:
Linux 内核代码和数据是不可交换的,并且永远不会移动到交换位置。
因此,现在您强制物理内存始终包含您的 bignum、RSA 实现和密钥,从而为用户级应用程序留出更少的空间,从而强制进行更多交换。
这些对于内核来说都是巨大的问题。内核的工作是尽可能高效。很简单的。这实际上为内核开发增加了一些其他限制,例如具有固定的堆栈大小以及大多数 libc 被认为对内核空间来说过多的事实。您也不应该在内核中使用浮点运算。让我们明确我的意思:在内核中实现 RSA 在技术上是完全可能的,但在实际层面上,没有人这样做,因为它在用户空间中更好,所有这些节省效率的牺牲最终都会做出。
RSA 也不太适合块层存储——在任何人开始之前,这不一定是一个坏主意。让我们实际阅读我上次链接的讨论。在那里直接引用托马斯的回答:
没有人在他们的正确心态下进行这种 RSA-with-CBC 加密。其中的原因包括:
- 该建筑没有经过足够的审查而被认为是安全的;
- 大小开销意味着加密消息将比明文消息长约 9.4%;
- RSA 加密不是很快(现代 CPU 仍然可以成功地加密,例如,每秒 2 MB 的数据)。
最后一个原因是最常被引用的,但在我看来,这三个原因中最没有说服力的。
我主要处理了最后一个问题,因为这是最明显的缺点,但是假设这不是问题并且您对在块级别上相对较慢感到满意,那么您还会发现每个字节的开销很大你想存储。不能大量有效地使用您的存储设备。
我警告所有这一切,如果你想这样做,在技术上是可行的。没有什么能阻止你这样做。我只是想真正解释为什么它还没有完成。
所以,这就是每个块的 RSA。当其他人都在大喊大叫时,另一种选择是使用 RSA 来处理少量真正有价值的数据——AES 或其他对称密钥。这行得通。这就是 TLS 的工作原理。这就是 PGP/GPG/OpenPGP 以及互联网上几乎所有其他加密协议的工作方式。这个想法是您使用慢速 RSA 加密密钥,将其传输给接收者(唯一可以解密它的人),然后你们都拥有对称密钥,并且可以在显着减少开销的情况下进行大量数据传输,假设正确所有算法的使用。
关于为什么同一操作系统上的加密和密钥可以,但不是完全安全
那么,现在让我们谈谈操作系统。你的电脑就像一个有室友的房子和一个住在房东的房子。楼主是内核,室友是程序。现在,为了实现您的系统,Bob 就是您,并且希望确保这发生。于是,他买了两个保险柜,并指导爱丽丝和卡罗尔制造挂锁,还分别买了一个保险柜。与此同时,他为他的一个保险箱发明了一个组合,把它安好,然后把保险箱放在走廊里。现在,为了保护这个密码,他把密码写下来,并要求爱丽丝、卡罗尔(和他自己)把密码的副本放在他们自己的保险箱里,并用自己的挂锁锁上他们自己的保险箱。所以,要打开走廊里的保险箱,爱丽丝必须先打开她自己的保险箱,只有她有钥匙,然后读取密码,锁上她的保险箱,然后去打开走廊里的保险箱。
夏娃是一个邪恶的室友,非常生气,没有人告诉她保险箱里有什么。她不能进别人的房间,但她可以说服房东进,因为他可以去任何地方。她只需要:
就那么简单。我最初的答案中最好的一点是:
理论上,只要有人可以进入 root 或管理员权限,您的操作系统之战就会失败,就这么简单
现在,相比之下,网络服务是这样工作的。Bob 想给 George 发消息。所以,他让乔治在邮局寄给他一把挂锁。乔治和他们都完全信任的房东住在一起。于是鲍勃在走廊里设置了保险箱的密码,把它写下来,放在保险箱里,把戈尔格的挂锁放在上面,然后把两者都交给邮递员。他一点也不信任邮递员,但他不会很快邀请邮递员进来,就到门口。除非他在门口的台阶上做了什么让他暴露了,或者除非保险箱或挂锁有问题,或者除非邮递员能说服他透露任何东西,否则他的信息应该安全地送达乔治。
这就是我想要达到的目标。即使您使用 GPG 或基于用户空间的文件系统,例如 FUSE(完全有可能),您仍然必须信任您正在制作这些密钥并在其上进行加密的系统。否则,你所能期望的最好的结果是相当难以拦截的。您可以同时使用公钥密码术和对称密码术,但它们并没有达到您认为的效果——即使是作为访问控制的磁盘加密对于可以物理访问您系统的人来说也是毫无价值的;使用它的唯一原因是因为它会在您将硬盘扔掉 6 个月后对您的硬盘进行取证分析。
密码学只有在密钥和数据分开的情况下才有效。就是这么简单。这就是为什么互联网上的 TLS 可以正常工作(因为攻击者没有密钥),但本地加密(密钥要去哪里,在某些时候接触系统)却没有。因此,一定要实现一个加密的文件系统,并使用非对称密钥保护用于加密它的密钥。这是使用这种方案可以获得的最安全的方法,但是:
只写文件系统是可行的,即使是加密的,但它几乎没有额外的功能,比如GnuPG。
精确定义你想要的东西需要一些努力。有很多行为选择:
将系统作为内核驱动的文件系统只有在您希望能够通过文件的普通 API (open()
... write()
支持“普通 API”是为了那些不知道您的特定自动加密文件系统的应用程序的利益。另一方面,如果您接受希望将文件存放在此类目录中的用户可能必须调用特定命令,那么就没有理由在内核中实现该功能。一个纯粹的用户空间解决方案同样可以很好地工作,并且可能更好,因为用户空间编程比内核编程具有更少的限制。现有的用户空间解决方案已经存在,称为“电子邮件”,使用 GnuPG。
此外,如果根是您的敌人,那么您注定要失败。Root在Unix系统上是万能的;他可以根据需要更改内核,从而激活键盘记录器,或者只是获取写入文件的每个字节的副本。另一方面,如果 root不是敌人,那么系统的正常非加密安全功能(例如文件访问权限)应该足以强制执行数据机密性;请参阅其他回复。
使用密码学。如果您不想依赖文件系统权限,可以使用公钥加密直接解决此问题。
细节。就是这样。所有这些消息的接收者 Radia 可以使用 GPG 创建一个公钥密钥对。然后,Radia 应该将她的公钥传达给每个人:例如,她可能会将公钥存储在某个每个人都可以阅读的只读文件中。Radia 应该将她的私钥安全地存储在只有她可以读取的文件中。
要发送消息,Alice 可以将 Radia 的公钥导入她的 GPG 密钥文件,然后使用 GPG 将她的消息加密为 Radia 的公钥,然后将加密后的文件发送给 Radia。加密文件如何到达 Radia 并不重要。它可以通过明文电子邮件传输、存储在全球可写目录或任何其他不安全的介质中。
要接收消息,Radia 可以使用 GPG 对其进行解密(使用 Radia 的私钥)。
只有 Radia 能够解密该消息。Bob 不知道 Radia 的公钥,因此即使 Bob 截获了加密文件,Bob 也无法读取 Alice 试图发送的消息。
讨论。这都是公钥密码学的一个完全直接的应用。我建议您使用一些现有的、经过时间考验的、经过严格审查的文件加密软件,而不是自己实施公钥加密。为此,强烈推荐 GPG。如果您愿意花钱购买,您也可以使用 PGP 的商业产品。S/MIME 加密的电子邮件也将是一个完全合理的实现。该解决方案不需要文件系统的任何特殊支持;相反,安全性是在应用层实现的。
警告。Root 将能够读取所有文件并读取所有消息。你说你不想要这个。然而,你想要的却是无法实现的。在任何现有的操作系统上,如果 root 是恶意的,root 可以监视每个用户所做的一切。(您说“让我们假设系统对键盘记录程序是安全的”,但如果 root 是试图进行键盘记录的人,则没有办法做到这一点。)因此,这可以实现您的目标。
根据定义,root 用户将能够在其运行时绕过本地加密[1]。因此,您的目标是一个完全控制机器的对手,该机器想要在存储数据 2 小时或 2 周后解密所有数据。并且用户应该具有只写权限。
我建议使用访问控制和具有定期基于文件加密的 cronjob。使用随机密钥的对称加密和使用非对称密钥的密钥加密。简单的 GPG 加密应该自动为您使用这种混合方法。您应该使用不同的分区/文件夹将您加密的文件与暂存区域中的文件分开。
由于文件名和元数据的泄漏,基于文件的加密可能不如块层加密安全。但它也使您摆脱了用户可能会覆盖他们自己或其他人的文件的问题。从您的情况来看,我想您不希望发生这种情况。
[1] 我知道root不是root,但显然发帖人不想在这里依赖访问控制。