JAVA - AES key 长度不匹配

标签 java encryption client-server aes rsa

我有两种方法用于在客户端和服务器之间加密/解密 JSON 消息。服务器有一对 RSA key (一个私有(private),一个公共(public)),客户端也有。此外,双方都可以访问首次建立通信时生成的对称 session key ,该 key 用于加密 JSON 消息,因为 channel 本身并不安全。客户端生成一个 AES key ( session key ),然后使用服务器的公钥(所有人都知道)对其进行加密,并将其发送到服务器,服务器解密 session key 并将其存储在 HashMap 下客户的 ID。

但问题是:我在发送之前检查了 key 长度,它是 16 个字节长。当服务器收到加密的 session key 并解密时,它的长度为 24 字节。我认为在加密或解密操作期间,中间出现了问题。这是一个问题,因为当客户端想要开始发送请求(以加密 JSON 消息的形式)时,服务器无法解密和读取该请求,因为 key 的大小错误(它会抛出 java.lang.Error 异常)。 security.InvalidKeyException:非法 key 大小或默认参数)。

加密/解密方法如下:

public String cipher(Key key, String alg, String msg){
    try {
        Cipher c = Cipher.getInstance(alg);
        c.init(Cipher.ENCRYPT_MODE, key);
        return encoder.encodeToString(c.doFinal(msg.getBytes("UTF-8")));
    } catch (IllegalBlockSizeException e) {
        (...)
    }
}

编码器/解码器来自java.util.Base64

public String decipher(Key key, String alg, String msg){
    try {
        Cipher c = Cipher.getInstance(alg);
        c.init(Cipher.DECRYPT_MODE,key);
        return new String(c.doFinal(decoder.decode(msg)), "UTF-8");
    } catch (IllegalBlockSizeException e) {
        (...)
    }
}

客户端加密并发送 session key :

SecretKey sk = KeyGenerator.getInstance("AES/CBC/PKCS5Padding").generateKey();

System.out.println(sk.getEncoded().length) //length = 16 bytes

String sessionKey = cipher(client.getServerPublicKey(),
    "RSA/ECB/PKCS5Padding", encoder.encodeToString(sk.getEncoded()));

printWriter.write("{(...), \"key\":\"" + sessionKey + "\"}");

服务器接收加密的 session key 并将其保存在HashMap中:

byte[] aux = decipher(registry.getServerPrivateKey(),
    "RSA/ECB/PKCS5Padding", data.get("key").toString().replace("\"", ""))
        .getBytes("UTF-8");

System.out.println(aux.length) //length = 24 bytes

registry.addSession(..., new SecretKeySpec(aux, 0, aux.length, "AES"));

我尝试了不同的算法和不同的填充,但我似乎无法弄清楚错误在哪里。

最佳答案

您在使用以下语句加密之前对 key 进行 Base64 编码:

String sessionKey = cipher(client.getServerPublicKey(),
    "RSA/ECB/PKCS5Padding", encoder.encodeToString(sk.getEncoded()));

.. 将 16 字节 key 转换为 24 字符长的 Base64 表示形式。您无需在加密之前对 key 进行 Base64 编码,因为加密完全能够处理二进制数据。试试这个:

String sessionKey = cipher(client.getServerPublicKey(),
    "RSA/ECB/PKCS5Padding", sk.getEncoded());

同时更改您的 cipher(..) 方法以接受 msg 作为 byte[]

public String cipher(Key key, String alg, byte[] msg){
    try {
        Cipher c = Cipher.getInstance(alg);
        c.init(Cipher.ENCRYPT_MODE, key);
        return encoder.encodeToString(c.doFinal(msg));
    } catch (IllegalBlockSizeException e) {
        (...)
    }
}

另外,将您的 decipher(..) 更改为二进制,如下所示:

public byte[] decipher(Key key, String alg, String msg){
    try {
        Cipher c = Cipher.getInstance(alg);
        c.init(Cipher.DECRYPT_MODE,key);
        return c.doFinal(decoder.decode(msg));
    } catch (IllegalBlockSizeException e) {
        (...)
    }
}

关于JAVA - AES key 长度不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48015552/

相关文章:

sql - 同步客户端-服务器数据库

java - 网络圈。获取线程池ID

java - 如何在 Java 中每毫秒调用一次方法

java - Java中如何为特定方法实现Thread?

Java 8 - 将 <Map> 列表到单个映射中

C: 使用 crypt(3) 实现 Sha512 加密

java - 用 Python 解密用 Java 加密的字符串

java - 使用不同的 Cipher 对象解密时出现 BadPaddingException

java - Android客户端无法连接到Java服务器

sql - 为什么不直接从客户端连接到 SQL 服务器?为什么我们需要客户端-服务器模型中的应用服务器?