图片:诺亚方舟动物保护区

狮子、老虎和熊……哦,天哪!

在其中作者冒险通过荒野密码学图书馆

最近有机会深入研究OpenSSH、OpenSSL和GPG库的相当数量的细节(“逐步研究源代码广东发展银行因为它运行“某种细节),因为我努力创建一个替代版本的sftp提供文件端到端加密和与其他用户安全共享这些文件的实用程序。在这个过程中,我和我的同事决定让我们的关键数据和加密文件与GPG兼容,我在这里描述:

这需要一个非常深入的潜水GnuPG代码,很粗糙。当然,有一个规范-rfc4880, OpenPGP消息格式。这样就简单多了,对吧?嗯,不太好。规范有一些模糊性,这对规范来说不是很理想。例如,试着弄清楚数据包的签名应该是什么样的,并将其与公钥的签名进行对比。除此之外,GPG还引入了自己的一些特性。最重要的是,我们需要一个支持椭圆曲线算法的GPG的“现代”版本。这些现代版本已经开始使用不属于OpenPGP规范的结构来存储私钥文件等内容。我别无选择,只能挖出源头。因为我不想把它们连起来gpg / libgcrypt代码到OpenSSH,我不得不花一些时间弄清楚如何使用OpenSSL加密库做同样的事情。

照片Viapixabay

所以我是,libgcrypt.一侧的S表达式,opensslbignums另一边,我被夹在中间。这就相当于在一场对峙中担任裁判,一场是一只狂躁的剑齿虎在喝能量饮料,另一场是一只有愤怒管理问题、宿醉未醒的灰熊。好的,这可能只是一个双曲线。但有些日子感觉非常可怕。

这就相当于在一场对峙中担任裁判,一场是一只狂躁的剑齿虎在喝能量饮料,另一场是一只有愤怒管理问题、宿醉未醒的灰熊。

以下是一长串令人挠头的谜题中的几个例子。首先,GPG的一个小特性。OpenPGP消息格式以标签字节,然后是消息长度(可以是一个或多个字节,取决于它存储的值),然后是消息体。密钥文件中存储的消息之一是用户标识消息,或UID。UID只是文本,通常是像“Gumby ”这样的东西,它与作为标识符的键关联。除非你有真的长名称或电子邮件地址,这可能适合256字节。这意味着消息头的长度为两个字节。事实上,GPG在生成新密钥时就是这样写的。但是…当你散列公钥和相应的UID消息来生成签名时,GPG会这样做:

对于初学者,我甚至不知道“(void)sigversion;”做什么。我从未在C代码中见过这个。那么,我不知道为什么要强制将消息的长度设置为4个字节。对于这一点,我不确定为什么要在一个地方散列组成消息的字段,而在另一个地方序列化消息。GPG经常这样做。我更喜欢内部实现IronSSH:

附带的好处是,如果有人正在验证散列,她不需要反序列化数据并一次一个字段重新计算散列。这是一件好事。

在GPG兼容的数据中,大量存储为“多精度整数”(MPI) - 数据由位的两个字节长度组成,然后是足够的字节来保持多个位。嗯,除非最重要的位是1.然后,除了在Crypto中,否则所有的值都是无符号的,而且Gcrypt MPIS支持签名的数字,必须在前面添加一个字节的零字。好的,没问题。除非您为椭圆曲线公钥生成“keygrip”。(In GPG, a keygrip is a string representing a public key. It’s similar to, but not the same as, the key fingerprint. Why have two different shorthand names for a public key? That’s something you will need to ask the GPG developers.) Then, for some reason, you do not add the zero byte, even if the high bit is set. What the …?

照片Viapixabay

相似地,gpg在椭圆曲线点上使用前缀字节(如curve25519公钥)来指示值只是点的X坐标,而不是X和Y坐标。在你遇到这些点值的大多数地方都是这样。除非你还在努力计算椭圆曲线公钥的键握,在你弄清楚零字节填充之后。然后,你不加前缀。啊!弄清楚这两件事是一个有趣的小练习广东发展银行,因为生成的数据是通过散列运行的,所以从输出来看并不明显,为什么我的计算和gpgs。

libsodium更复杂的事情。我没有翻libsodium来源太多了,但我看了一些。它较新,历史纠葛较少,但仍有一些奇怪之处。例如,椭圆曲线密钥对由一个公钥(即曲线上的一个点)和一个密钥(即该点的乘数)组成。在曲线25519中,ECC的变体为libsodium实施方式,私钥是“钳位” - 它的最高比特和最低三位被设置为零,并且旁边的最高位设置为一个。我已经读过这篇文章,但在重点生成代码中寻找它并找不到它后,我不得不投降,加入邮件列表,并恳求提示。据透露,当它生成时,私钥不会被钳位 - 相反,钳位操作连接到乘以标量的函数。呵呵?

图片由托马斯Lefebvre

弄清楚互通libsodiumgpg / libgcrypt很有趣。例如,在生成一个curve25519密钥对之后,我将其存储在一个gpg兼容的密钥文件中。在这个过程中,我(艰难地)发现libsodium以小endian格式生成私钥,因此阵列中的第一个字节保持了值的最低有效位。libgcrypt.期望以相反的顺序的字节。好的 - 经过更多的代码审查来弄清楚这个,在编写文件之前反转键。当然,你会反转公钥(曲线上的点的x坐标),对吗?不!到这一天,我不明白为什么libsodium对两个值的操作不同。我确信这与在小端处理器上计算产品的效率有关,但这只是一种猜测。

如果你认为OpenSSL只是这个恐怖故事中的一个勇敢的助手,请仔细思考一下这个函数:

是的,整件事中唯一的评论是一些神秘的TODO注释,可能不再有意义,甚至对原作者!

我是一个不行性的C骑师,所以我喜欢我的指针算术和下一个书呆子。不过实话说?!?甚至涉及以下知识:

  • 这些字段D, p, q, dmp1, dmq1,iqmp是RSA私钥的参数
  • 每一个都是一个指向BIGNUM的指针
  • dBignum中的字段是一个指向包含数据的BN_ULONG数组的指针
  • 在BIGNUM中,字段保存了在d

要弄清楚这里发生了什么有点牵强。似乎有一种更容易理解的方式将一组参数的内容复制到一些锁定的内存中。你有多确信这个密码正确地“锁定”了存储RSA密钥的内存?也许您是测试驱动开发的支持者,并且您更喜欢让您的测试来解释。在任何地方找到这个代码的测试都是非常幸运的。

这些只是我遇到的几件事,同时通过gpg和openssl代码进行梳理,并尝试将它们与libsodium匹配。我不需要深入地深入挖掘加密代码的肠子。鉴于我发现的东西,我认为这将是邮寄

这里有龙。

在源头上,尽量避免!如果您发现无法避免代码,则以下是一些观察结果:

GPG / libgcrypt:比其他人更少的无评论。很多代码都支持旧的算法和格式。这种消息格式来自于人们担心每一个字节的每一位的时代(这对于14kbps的调制解调器来说可能很好,但对于试图破译数据的人来说就不太好了)。有些数据结构是令人讨厌的钝(例如,至少有三种不同的表示它们的普遍存在S-expressions)。代码组织可以更好一些。评级:D +。

OpenSSL:评论很难和异国情调。代码以相当可理解的方式组织。有足够的代码支持旧算法,并且有丰富的缩略语Gadore。评级:C -。

OpenSSH:评论少之又少。大多数加密代码都被推迟到OpenSSL;有一小部分核心代码可以让你在没有OpenSSL的情况下构建一个蹩脚的版本,而且这些代码非常神秘。该项目与SSHv1协议有一点向后兼容性。评级:C +。

LibSodium:相当简单的api。但是,实施洋葱有很多层。代码很好地组织,从漂亮新的福利。评级:B。

所有的老项目中都有很多改进的空间,特别是如果他们能够从支持他们从一开始就发布的每个版本的需求中解脱出来的话。

关于构建安全的提示、技巧、指针和透视图…

鲍勃墙

写的

咸的散列
鲍勃墙

写的

数据安全初创公司IronCore Labs的首席技术官。到加密,云计算,人工智能和机器学习,其他极客的东西。音乐迷。

咸的散列

关于构建安全、可测试、可维护的应用程序的提示、技巧、指针和观点。来自IronCore实验室的关于安全和隐私的想法和观察。

媒介是一个开放的平台,1.7亿读者可以在这里找到深刻和动态的思考。在这里,专家和未被发现的声音同样会深入任何话题的核心,并带来新的想法。了解更多

关注与你有关的作家、出版物和主题,你会在你的主页和收件箱中看到它们。探索

如果您有一个故事来讲述,知识分享,或者提供提供的视角 - 欢迎回家。很容易和免费发布您对任何主题的思考。写在媒介

有一个“在App Store上下载”的按钮,点击它就会引导你进入iOS App Store
一个按钮说'获得它,Google Play',如果点击它将导致您进入Google Play商店