7

我应该如何使用从服务器端传输的公钥加密客户端的会话密钥?

我应该使用Cipher.WRAP_MODEorCipher.ENCRYPT_MODE吗?

Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.WRAP_MODE, publicKey);
byte[] wrappedSessionKey = cipher.wrap(sessionKey);

我不太确定如何使用 encrypt_mode 来加密 sessionKey。有人可以帮我吗?

4

1 回答 1

32

包装和加密非常相似,但是包装更准确地表达了您计划做的事情。一般的“加密”对没有语义意义的原始数据进行操作,而已知包装与密钥有关。因此,该Cipher.unwrap()方法返回一个Key非字节数组。

如果您使用 wrap 进行密钥包装,您的代码将更具可移植性(特别是在硬件安全模块方面)。在某些情况下,密钥权限将允许包装操作,但不允许密钥字节的原始加密。

当然,由于整个 JCE 架构都基于提供者概念,因此您需要准确检查为所选提供者指定的算法以获得所需的输出格式。如果您将打包的密钥数据发送给第三方,这一点尤其重要。


WRAP在您的特定情况下,和将表现出相同的行为ENCRYPT,如下所示,我在其中交换结果:

KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "SunJSSE");
generator.initialize(2048);
KeyPair keyPair = generator.generateKeyPair();

SecretKey sessionKey = new SecretKeySpec(new byte[16], "AES");

Cipher c = Cipher.getInstance("RSA", "SunJCE");
c.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
byte[] result1 = c.doFinal(sessionKey.getEncoded());

c.init(Cipher.WRAP_MODE, keyPair.getPublic());
byte[] result2 = c.wrap(sessionKey);

c.init(Cipher.UNWRAP_MODE, keyPair.getPrivate());
SecretKey sessionKey1 = (SecretKey) c.unwrap(result1, "AES",
    Cipher.SECRET_KEY);

c.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
SecretKey sessionKey2 = new SecretKeySpec(c.doFinal(result2), "AES");

System.out.println(Arrays.equals(sessionKey1.getEncoded(),
    sessionKey2.getEncoded()));

这打印:true

于 2013-05-16T12:04:01.473 回答