【问题标题】:Elliptic curve key wrapping/encapsulation using Java使用 Java 的椭圆曲线密钥包装/封装
【发布时间】:2018-01-18 13:30:04
【问题描述】:

根据我的研究,我了解到这是使用 RSA 封装 AES 会话密钥的正确方法:

import java.security.*;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;

public class Main {
    public static void main(String args[]) throws Exception {
        KeyGenerator aesKeyGen = KeyGenerator.getInstance("AES");
        aesKeyGen.init(256);
        SecretKey secretKey = aesKeyGen.generateKey();

        Base64.Encoder encoder = Base64.getEncoder().withoutPadding();
        Cipher cipher = Cipher.getInstance("RSA");
        KeyPairGenerator rsaKeyGen = KeyPairGenerator.getInstance("RSA");
        rsaKeyGen.initialize(4096);
        KeyPair keyPair = rsaKeyGen.generateKeyPair();
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();

        cipher.init(Cipher.WRAP_MODE, publicKey);
        byte[] wrappedKey = cipher.wrap(secretKey);
        cipher.init(Cipher.UNWRAP_MODE, privateKey);
        SecretKey unwrappedKey = (SecretKey)cipher.unwrap(wrappedKey, "AES", Cipher.SECRET_KEY);

        System.out.println(encoder.encodeToString(wrappedKey));
        System.out.println(encoder.encodeToString(secretKey.getEncoded()));
        System.out.println(encoder.encodeToString(unwrappedKey.getEncoded()));
    }
}

我的问题是:

  • 我应该继续使用Cipher.getInstance("RSA"),改用Cipher.getInstance("RSA/ECB/PKCS1Padding") 还是其他方式?
  • 除了使用 EC 之外,我怎样才能做与上面相同的事情?
  • 密钥封装和密钥封装一样吗?
  • 我是否需要像处理数组一样(例如Arrays.fill(array, (byte)0))或调用getEncoded() 一样清除secretKey 使用的内存?

为了回答我的第二个问题,我发现我应该使用:

KeyPairGenerator ecKeyGen = KeyPairGenerator.getInstance("EC");

但是我不确定在这里使用什么来代替<name>

Cipher cipher = Cipher.getInstance("<name>");

我还发现我可以通过这样做来选择要使用的曲线:

...
ECGenParameterSpec ecsp = new ECGenParameterSpec("sect571k1"); 
ecKeyGen.initialize(571);
...

但是,我不知道我应该在这里使用什么参数来代替<name>

new ECGenParameterSpec("<name>");

我认为一些不错的候选人如下:

secp521r1, nistp521, sect571r1, nistb571, nistb571, sect571k1, nistk571 nistk571, sect163r2

还有其他选择吗?你能帮我选一个最好的吗?实例化一个ECGenParameterSpec对象来设置EC的初始化参数KeyPairGenerator够了吗?

【问题讨论】:

    标签: java cryptography rsa public-key-encryption elliptic-curve


    【解决方案1】:

    我应该继续使用 Cipher.getInstance("RSA"),还是改用 Cipher.getInstance("RSA/ECB/PKCS1Padding") 或其他方式?

    您至少应该切换到完全指定的字符串;不同的提供者可能有不同的默认值,并且指定完整的方案更容易阅读/维护;不是每个人都知道默认值。

    但是,PKCS#1 v1.5 填充容易受到某些填充 oracle 攻击,切换到 OAEP 填充将提供某些安全优势。

    除了使用 EC 之外,我怎样才能做与上面相同的事情?

    不容易。 RSA 问题允许生成签名和加密,而 (EC)DH 问题允许生成签名和 Diffie-Hellman。然而,可以使用 ECDH 来实现 ECIES,它“导出”一个对称密钥,然后用于加密消息。

    ECIES 不包含在正常的 Java 运行时中,但 Bouncy Castle 有实现,当然可以在 ECDH 之上构建功能,该功能包含在 KeyAgreement 类中。

    密钥封装和密钥封装一样吗?

    它们是相关的。密钥封装更多用于会话密钥,并且通常派生会话密钥而不是对其进行加密。 IE。如果是这种情况,您不能使用密钥封装(直接)加密现有密钥。密钥包装确实会加密现有密钥,并且可能使用专门的(确定性)加密方案 - 尽管 Java 运行时提供的方案并非直接如此。

    Java 中的包装主要是有用的,因为您不需要将被包装的键的中间键值存储在字节数组中;如果密钥是在硬件(例如智能卡)中管理的,这将是不可能的。

    我是否需要像处理数组一样(例如 Arrays.fill(array, (byte)0))或仅调用 getEncoded() 来清除 secretKey 使用的内存?

    您不能,因为这些字段不能直接访问。 Java 8 及更高版本实现了Destroyable.destroy(),因此您可以使用一种方法来销毁密钥。如果密钥在硬件中,那么此方法可能会引发异常。

    我认为一些不错的候选人如下:

    secp521r1, nistp521, sect571r1, nistb571, nistb571, sect571k1, nistk571 nistk571, sect163r2

    还有其他选择吗?

    当然,对于较少的位数:例如 secp384r1 和 secp256r1。

    你能帮我选一个最好的吗?

    定义最佳。性能与安全性,但即使是 secp256r1 也已经相当强大。不过,我会选择 SEC 素数 (p) 曲线,而不是 Koblenz 或扭曲曲线(k 或 t 曲线)。

    实例化一个ECGenParameterSpec对象来设置EC的初始化参数KeyPairGenerator够了吗?

    是的。

    【讨论】:

    • ECIES 不包含在正常的 Java 运行时中:实际上,它是 JCE 的 Cipher.getInstance() 例程支持/必需的算法名称。我还没有弄清楚如何使用它来使用 EC 创建的公钥包装现有的对称会话密钥,但至少名称存在。
    • @TiStrga 它在列表中,但定义不明确,并且它不包括在提供 JDK 附带的椭圆曲线加密的提供程序中。您可能必须包括像 Bouncy Castle 这样的东西。但即便如此,由于算法定义不明确,您最好自己使用KeyAgreement,然后使用您选择的密码。
    • 没错,它的规格非常低,而且除了抛出异常之外,我从来没有让 ECIES Cipher 做任何事情。我很犹豫要不要尝试用KeyAgreement 做任何事情,因为我不明白在我们自己的场景中第二个密钥来自哪里。 (我希望我能找到一些文档和示例;很可能它与原始提问者的情况大不相同。)
    • @TiStrga this answer的后半部分对你有帮助吗?
    • 确实做到了,非常感谢!似乎没有办法让 EC KeyAgreement 与其他类型的密钥包装、现有会话密钥和多方密钥一起工作——至少在密钥处理方面没有获得危险的“创造性”。我们暂时搁置该项目。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-17
    相关资源
    最近更新 更多