使用Java

时间:2018-01-18 13:30:05

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

根据我的研究,我了解到这是使用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?
  • 密钥包装与密钥封装相同吗?
  • 我是否需要以某种方式清除secretKey使用的内存,就像我们使用数组一样(例如Arrays.fill(array, (byte)0)),或者只是调用getEncoded()

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

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的初始化参数?

1 个答案:

答案 0 :(得分:3)

  

我应该继续使用Cipher.getInstance(&#34; RSA&#34;),切换到Cipher.getInstance(&#34; RSA / ECB / PKCS1Padding&#34;)或其他什么?

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

然而,PKCS#1 v1.5填充容易受到某些填充oracle攻击,切换到OAEP填充会提供一定的安全性。

  

我怎样才能做同样的事情,而不是使用EC?

不容易。 RSA问题允许签名生成和加密,而(EC)DH问题允许签名生成和Diffie-Hellman。然而,可以使用ECDH来实现ECIES,其源自&#34;对称密钥,然后用于加密消息。

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

  

密钥包装与密钥封装相同吗?

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

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

  

我是否需要以某种方式清除secretKey使用的内存,就像我们使用数组一样(例如Arrays.fill(array,(byte)0))或者只是调用getEncoded()?

您无法直接访问这些字段。 Java 8及更高版本实现Destroyable.destroy(),因此您有一种方法来销毁密钥。如果密钥在硬件中,则此方法可能会抛出异常。

  

我相信一些优秀的候选人如下:

     

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

     

还有其他选择吗?

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

  

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

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

  

是否足以实例化ECGenParameterSpec对象来设置EC KeyPairGenerator的初始化参数?