我正在使用ECDH在Alice和Bob之间拥有共享秘密,其中一个在Android上运行,另一个在嵌入式上运行。我的理解是,最佳实践是双方都生成AES密钥来加密消息。有人可以发一些关于Alice和Bob双方在使用ECDH就共享秘密达成一致后生成相同AES密钥的例子吗?
答案 0 :(得分:4)
最好遵循NIST关于密钥协议方案的建议,例如:使用NIST SP 800-56A recommendations in the implementers guide和NIST SP 800-108中指定的一种密钥派生方法。它描述了如何将秘密转换为字节,然后可以使用其中一个KDF转换为(多个)密钥。
请注意,密钥派生在1.50之后的Bouncy Castle的轻量级API中,因此也应该出现在Spongy Castle中。最常见的NIST算法位于org.bouncycastle.crypto.generators.KDFCounterBytesGenerator
。你可以简单地在构造函数中给它任何HMAC(比如说HMAC SHA1),在初始化期间给它org.bouncycastle.crypto.params.KDFCounterParameters
。
请注意,与Perseids的答案相比,这更符合更好的加密实践,但可能更难理解/实施。
答案 1 :(得分:2)
ECDH成功运行后,你们两端都有相同的组元素。您现在需要将元素的统一编码定义为字节数组/八位字节流。使用散列函数(例如SHA256)可以将数组减少到256位值。如果需要派生几个键,可以在对每个键进行散列之前为每个键附加不同常量的字节数组。
一个简单的例子:让我们说你的椭圆曲线点是(51357992175,89175716892)。您可以将该曲线点表示为字符串"(51357992175,89175716892)"。对于不同的键,你可以附加一些字符串常量,如" MacKey"或"加密密钥"。要获得一些原始字节值,您可以使用utf8对这些字符串进行编码。总的来说,关键是:
macKey = sha256("(51357992175,89175716892)MacKey".getBytes("UTF-8"))
encryptionKey = sha256("(51357992175,89175716892)EncryptionKey".getBytes("UTF-8"))
编辑,关于您的评论引起的问题("在我的情况下,我有一台服务器和许多客户每天都要接近他几次,并且需要使用不同的AES每次基于共享密钥的密钥。")关于如何生成大量密钥,每个密钥对应一次:
您正在进入加密协议设计的相当复杂的领域。请考虑以下问题:
通过我们后面的扩展警告,回到您的问题:对于每个新密钥,您可以使用密钥派生中包含的 nonce (使用一次的数字)为此目的生成一个唯一的密钥。我基本上正在重建类似于" 5.1 KDF的计数器模式"来自NIST SP 800-108,owlstead已经提到过,使用纯文本组件。在这一点上,我建议以任何方式阅读它,因为它不是那么长,并包含很多背景考虑因素。除了nonce之外,你应该尽可能地缩小密钥的使用范围。例如,在服务器端使用:
macKey = sha256(sha256("(51357992175,89175716892); MacKey; ServerToClient; 2755".getBytes("UTF-8")))
用于为从服务器到客户端的通信进行消息身份验证而生成的第2755个密钥。您可以看到以下组件:共享密钥(椭圆曲线点),密钥(mac)的目的,通信方向,计数随机数。此外,我在这里使用双哈希来防止哈希上的任何类型的length extension; HMAC在这里同样出色。在某些情况下,nonce本身可以并且必须与消息一起发布。它本身不包含任何敏感信息。