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

时间:2016-05-30 13:24:48

标签: c cryptography compatibility libsodium

我计划将一堆记录存储在一个文件中,然后用libsodium对每条记录进行签名。但是,我希望我的程序的未来版本能够检查当前版本的签名,理想情况下反之亦然。

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

我应该......

  1. 始终使用默认基元(即crypto_sign
  2. 使用特定原语(即crypto_sign_ed25519
  3. 执行(1),但将sodium_library_version_major()的值存储在文件中(在专用的钠版本'字段或一般'文件格式版本'字段中)并在当前运行的版本较低时退出
  4. 执行(3),但也存储crypto_sign_primitive()
  5. 做(4),但也存储crypto_sign_bytes()和朋友
  6. ......或者我应该完全做其他事情吗?

    我的程序将以C语言编写。

2 个答案:

答案 0 :(得分:2)

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

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

我假设对于一个特定的算法,给定相同的输入数据和相同的密钥,我们总会得到相同的结果,因为它的数学和任何偏离此规则将使库完全无法使用。

让我们来看看两个主要选项:

  1. 始终使用crypto_sign_ed25519()并且永远不会更改此内容。这个选项并不是那么糟糕,因为它很简单,只要在libsodium中存在crypto_sign_ed25519()并且在输出中是稳定的,你就不用担心稳定的固定大小签名和零管理开销。当然,将来有人可以通过这种算法发现一些可怕的问题,如果你不准备改变算法,这对你来说可能意味着可怕的问题。
  2. 使用crypto_sign()。有了这个,我们突然遇到很多问题,因为算法可以改变,所以你必须存储一些元数据和签名,这会打开一组问题:
    • 要存储什么?
    • 此元数据应该是记录级还是文件级?
  3. 对于第二种方法,我们在提到的功能中有什么作用?

    • 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年,那么不,你真的需要能够存活算法(甚至可能是整个加密库)的变化。

答案 1 :(得分:2)

只需使用高级API。

高级API中的函数不会使用不同的算法,如果没有碰撞库的主要版本。

在libsodium 1.x.y中可以预期的唯一重大变化是删除已弃用/未记录的函数(在使用--enable-minimal开关编译的当前版本中甚至不存在)。其他一切都将保持向后兼容。

新的算法可能会在没有高级包装器的1.x.y版本中引入,并且将通过libsodium 2中的新高级API进行稳定和公开。

因此,请不要打扰crypto_sign_ed25519()。只需使用crypto_sign()