Java: SecretKey 到 String 和重建回 SecretKey 产生不同的解密结果

Java: SecretKey to String and rebuilding back to SecretKey produces different decryption result

目前我已经为我的作业创建了一个用于 RC4 加密的 SecretKey。在 RC4 加密之后,我会将此密钥转换为字符串并通过 UDP 将其发送到服务器,但是当我使用 SecretKeySpec 在服务器端重建它时,它会产生一个完全不同的密钥。 我查看了 Whosebug 的解决方案,但最终仍然会导致重建的 SecretKey 与我原来的 SecretKey 不同。

我已经尝试在客户端代码上从字符串格式重建密钥,结果与原始密钥相比仍然是不同的密钥,所以我怀疑我的 UDP 传输与结果有任何关系。

以下是我如何创建用于 RC4 加密的初始 SecretKey:

KeyGenerator keygen = KeyGenerator.getInstance("RC4");
SecretKey originalSecretKey = keygen.generateKey();

我如何将 SecretKey 转换为字符串并使用 SecretKeySpec 重建:

String k = Base64.getEncoder().encodeToString(originalSecretKey.getEncoded());
byte[] decodedKey = Base64.getDecoder().decode(k);
SecretKey rebuiltSK = new SecretKeySpec(decodedKey, "RC4");

当我打印“originalSecretKey”和“rebuiltSK”进行检查时,这是我意识到重建值完全不同的地方,因此我无法使用 rebuiltSK 解密任何 originalSecretKey 加密的消息。

Edit1:我真傻,感谢“A Developer”和“Daniel”指出“originalSecretKey”和“rebuiltSK”的实际 .getEncoded() 值都一样。

如果我遗漏了一些关于密钥生成和 java 密码学的极其基本的东西,我深表歉意,因为这是我第一次使用它们。预先感谢您的帮助!

编辑2: 以下是我目前用于 RC4 加密和解密的代码:

public static byte[] encryptRC4(byte[] b, SecretKey k) throws Exception
    {
        Cipher cipher = Cipher.getInstance("RC4");
        cipher.init(Cipher.ENCRYPT_MODE, k);
//Cipher.DECRYPT_MODE when on server program
        byte[] encrypted = cipher.doFinal(b);
        return encrypted;
    }

上面的代码是我在从客户端接收到 byte[] 中的 secretKey 后尝试在服务器端重建它的原因。

我已经尝试 运行 使用“rebuiltSK”作为 SecretKey 参数进行解密,但是它没有产生正确的明文,尽管我已经在两个客户端上检查了 packet.getData()和服务器相同。

您对 SecretKey 的重建工作与预期的一样,加密后解密会检索到 原始明文。

我只能争辩(与@Daniel 相同)密钥在传输过程中被更改或(byte[] 与) 密文没有完全传输到服务器。

下面的完整示例代码显示了包含密钥生成、加密和解密的完整回合。

这是结果:

plaintext equals decryptedtext: true
decryptedtext: my secret

安全警告:以下代码使用不安全算法'RC4'或'ARCFOUR'。 请不要复制以下代码或在生产中使用它——它仅用于教育目的。 该代码没有任何适当的异常处理!

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;

public class Main {
    public static void main(String[] args) throws Exception {
        System.out.println("
        // security warning: the algorithm 'RC4' or 'ARCFOUR' is unsecure and
        // should be used for educational purposes only
        // do not use this code in production
        // key generation
        KeyGenerator keygen = KeyGenerator.getInstance("RC4");
        SecretKey originalSecretKey = keygen.generateKey();
        // encryption
        byte[] plaintext = "my secret".getBytes(StandardCharsets.UTF_8);
        byte[] ciphertext = encryptRC4(plaintext, originalSecretKey);
        // decryption
        String k = Base64.getEncoder().encodeToString(originalSecretKey.getEncoded());
        byte[] decodedKey = Base64.getDecoder().decode(k);
        SecretKey rebuiltSK = new SecretKeySpec(decodedKey, "RC4");
        byte[] decryptedtext = decryptRC4(ciphertext, rebuiltSK);
        // output
        System.out.println("plaintext equals decryptedtext: " + Arrays.equals(plaintext, decryptedtext));
        System.out.println("decryptedtext: " + new String(decryptedtext));
    }

    public static byte[] encryptRC4(byte[] b, SecretKey k) throws Exception
    {
        Cipher cipher = Cipher.getInstance("RC4");
        cipher.init(Cipher.ENCRYPT_MODE, k);
        byte[] encrypted = cipher.doFinal(b);
        return encrypted;
    }
    public static byte[] decryptRC4(byte[] b, SecretKey k) throws Exception
    {
        Cipher cipher = Cipher.getInstance("RC4");
        cipher.init(Cipher.DECRYPT_MODE, k);
        byte[] decrypted = cipher.doFinal(b);
        return decrypted;
    }
}