根据我的研究,我了解到这是使用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")
还是别的什么?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
的初始化参数?
答案 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
对象来设置ECKeyPairGenerator
的初始化参数?
是