c - 如何正确使用 libsodium 以使其在版本之间兼容?

标签 c cryptography compatibility libsodium

我计划将一堆记录存储在一个文件中,然后用 libsodium 对每个记录进行签名。 .但是,我希望我的程序的 future 版本能够检查当前版本所做的签名,反之亦然。

对于当前版本的钠,签名是使用 Ed25519 算法进行的。我想默认原语可以在新版本的钠中改变(否则 libsodium 不会公开一种选择特定的方法,我认为)。

我是不是该...

  • 始终使用默认原语(即 crypto_sign )
  • 使用特定的原语(即 crypto_sign_ed25519 )
  • 执行 (1),但存储 sodium_library_version_major() 的值在文件中(在专用的“钠版本”字段或一般的“文件格式修订版”字段中)并在当前运行的版本较低时退出
  • 做(3),还要存储crypto_sign_primitive()
  • 做(4),还要存储crypto_sign_bytes()和 friend 们

  • ……还是我应该完全做其他事情?

    我的程序将用 C 编写。

    最佳答案

    让我们首先确定可能出现的问题集,然后尝试解决它。我们有一些数据(记录)和签名。签名可以用不同的算法计算。程序可以进化和改变它的行为,libsodium 也可以(独立地)进化和改变它的行为。在签名生成方面,我们有:

  • crypto_sign() ,它使用一些默认算法来生成签名(在编写时只是调用 crypto_sign_ed25519() )
  • crypto_sign_ed25519() ,它根据特定的 ed25519 生成签名算法

  • 我假设对于一个给定相同输入数据和相同 key 的特定算法,我们总是会得到相同的结果,因为它是数学问题,任何与此规则的偏差都会使库完全无法使用。

    让我们来看看两个主要选项:
  • 使用 crypto_sign_ed25519()一直并且从不改变这一点。不错的选择,因为它很简单而且只要 crypto_sign_ed25519()存在于 libsodium 中并且其输出稳定,您无需担心稳定的固定大小签名和零管理开销。当然,将来有人会发现这个算法的一些可怕的问题,如果你不准备改变算法,这对你来说可能意味着可怕的问题。
  • 使用 crypto_sign() .有了这个我们突然有很多问题,因为算法可以改变,所以你必须在签名的同时存储一些元数据,这就引出了一组问题:
  • 要存储什么?
  • 这个元数据应该是记录级还是文件级?

  • 对于第二种方法,我们在提到的函数中有什么?
  • sodium_library_version_major()是一个告诉我们库 API 版本的函数。它与支持/默认算法的更改没有直接关系,因此它对我们的问题几乎没有用。
  • crypto_sign_primitive()是一个函数,它返回一个字符串来标识 crypto_sign() 中使用的算法。 .这是我们需要的完美匹配,因为据说它的输出会在算法发生变化的时候发生变化。
  • crypto_sign_bytes()是一个返回由 crypto_sign() 生成的签名大小的函数以字节为单位。这对于确定签名所需的存储量很有用,但如果算法发生变化,它很容易保持不变,因此它不是我们需要显式存储的元数据。

  • 现在我们知道要存储什么,接下来是处理存储数据的问题。您需要获取算法名称并使用它来调用匹配验证函数。不幸的是,据我所知,libsodium 本身并没有提供任何简单的方法来获得给定算法名称的正确函数(如 openssl 中的 EVP_get_cipherbyname()EVP_get_digestbyname()),因此您需要自己制作一个(当然应该未知名称失败)。如果您必须自己制作一个,那么存储一些数字标识符而不是库中的名称会更容易(尽管代码更多)。

    现在让我们回到文件级与记录级。为了解决这个问题,还有另外两个问题要问——您是否可以在任何给定时间为旧记录生成新签名(技术上可行,政策允许),您是否需要将新记录附加到旧文件中?

    如果您无法为旧记录生成新签名,或者您需要追加新记录并且不希望签名重新生成的性能损失,那么您没有太多选择,您需要:
  • 为您的签名设置动态大小字段
  • 存储用于生成签名的算法(动态字符串字段或内部(对于您的应用程序)ID)以及签名本身

  • 如果您可以生成新签名,或者特别是如果您不需要附加新记录,那么当您将算法存储在特殊的文件级字段中时,如果签名算法发生变化,您可以使用更简单的文件级方法, 在保存文件时重新生成所有签名(或在附加新记录时使用旧签名,这也是一个兼容性策略问题)。

    其他选择?那么,crypto_sign() 有什么特别之处? ?它的行为不受您的控制,libsodium 开发人员为您选择算法(毫无疑问他们选择了好的算法),但是如果您的文件结构中有任何版本信息(不是特定于签名的,我的意思是)没有什么可以阻止您做出您自己的特定选择,将一种算法用于一种文件版本,另一种算法用于另一种(当然,需要时使用转换代码)。同样,这也是基于您可以生成新签名并且策略允许的假设。

    这让我们回到了最初的两个选择,问题是与仅使用 crypto_sign_ed25519() 相比,这样做是否值得麻烦。 .这主要取决于您的程序生命周期,我可能会说(仅作为意见)如果不到 5 年,那么只使用一种特定的算法会更容易。如果它很容易超过 10 年,那么不,你真的需要能够经受住算法(甚至可能是整个加密库)的变化。

    关于c - 如何正确使用 libsodium 以使其在版本之间兼容?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37526846/

    相关文章:

    java - C++/Openssl 从编码字节中获取 RSA key (由 java 编码)

    go - 从 go-ethereum 实现 Ethereum personal_sign (EIP-191) 给出了与 ethers.js 不同的签名

    android - 是否可以将设备 ROM 闪存到 AVD 模拟器或 genymotion?

    compatibility - Berkeley Db 4 及更高版本兼容性

    C 代码排列

    python - 使用 Intel MKL 计算 `trans(a)*inv(b)*a` 的正确方法(后续问题)

    java - 在 JAVA 中构建一个 'Activation Key' 生成器

    c - fork() 情况下的全局变量值

    c - 指向 C 中指针数组的指针数组

    jquery - 在现有网站上安装 jQuery 幻灯片插件时出现 IE 错误