使用公钥在客户端和服务器之间交换对称密钥

时间:2015-11-24 19:37:26

标签: java rmi public-key-encryption encryption-symmetric

我希望在通过Java RMI运行的客户端和服务器程序之间交换对称密钥。

我的服务器创建了一个公钥:

KeyPairGenerator keyGen = null;
try {
    keyGen = KeyPairGenerator.getInstance("DSA", "SUN");
} catch (NoSuchAlgorithmException e) {
    e.printStackTrace();
} catch (NoSuchProviderException e) {
    e.printStackTrace();
}
KeyPair pair = keyGen.generateKeyPair();
this.priv = pair.getPrivate();
this.pub = pair.getPublic();

我将公钥发送给客户端。客户端将使用服务器的公钥创建密码。我想使用此Cipher加密封装客户端创建的对称密钥并将其发送到服务器的SealedObject。

//create cipher using server's public key
Cipher cipher = null;
try {
    cipher = Cipher.getInstance(serverKey.getAlgorithm(), "SUN");
} catch (NoSuchAlgorithmException e) {
    e.printStackTrace();
} catch (NoSuchPaddingException e) {
    e.printStackTrace();
} catch (NoSuchProviderException e) {
    e.printStackTrace();
}
try {
    cipher.init(Cipher.ENCRYPT_MODE, serverKey);
} catch (InvalidKeyException e) {
    e.printStackTrace();
}

但是当我运行程序时,我在初始化密码时遇到异常:

java.security.NoSuchAlgorithmException: No such algorithm: DSA
at javax.crypto.Cipher.getInstance(Cipher.java:646)
at javax.crypto.Cipher.getInstance(Cipher.java:568)
at Client.main(Client.java:91)

我不明白为什么我得到这个NoSuchAlgorithm异常。如果我用RSA而不是DSA制作公钥,我不会得到这个,但RSA给了我:

javax.crypto.IllegalBlockSizeException: 
Data must not be longer than 117 bytes

那么我应该用什么来安全地发送包含对称密钥的密封对象?

1 个答案:

答案 0 :(得分:0)

作为@zapl评论,DSA不是加密算法,RSA只能加密大小小于密钥大小减去大部分固定开销的数据(PKCS1为11个字节,这是默认值,因此您使用;对于OAEP来说更多。

虽然不在您发布的代码中,但我敢打赌问题是您正在尝试封锁SecretKey对象。加密仅适用于字节(或位)序列,在Java中由字节数组或有时是数组的部分表示,因此SealedObject实际上将您提供给它的对象序列化为字节并加密这些字节,相反地解密这些字节并反序列化他们重新组建对象。 Java序列化有一些开销,特别是各种Key类型组织在一个层次结构中,这加剧了这种情况。例如,从SecretKey序列化KeyGenerator.getInstance("TDES")是282字节,对于RSA-1024而言太大了,正如您的异常所说的那样只能是117字节。

而是仅密封由SecretKey.getEncoded()获取的键值的字节。在接收器(服务器)上将字节放回SecretKeySpec(使用正确的算法;如果没有事先修复则发送它)并且您实际上可以将其用作对称的Key即使不运行它通过工厂(不同于具有更多结构的非对称键)。即使是简单的byte[]也有某些序列化开销,但这还不足以导致问题。