首页 > 解决方案 > Java:SecretKey 到 String 并重建回 SecretKey 会产生不同的解密结果

问题描述

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

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

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

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

我如何将 SecretKey 转换为 String 并使用 SecretKeySpec 重建:

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

当我 println "originalSecretKey" 和 "rebuiltSK" 进行检查时,我意识到重建的值完全不同,因此我无法使用 rebuiltSK 解密任何 originalSecretKey 加密的消息。

Edit1:愚蠢的我,感谢“A Developer”和“Daniel”指出“originalSecretKey”和“rebuiltSK”的实际 .getEncoded() 值是相同的。

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

Edit2:下面是我目前用于 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() 是否相同,但它不会产生正确的明文。

标签: javacryptographysecret-key

解决方案


您对 SecretKey 的重建按预期工作,加密后解密检索原始明文。

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

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

这是结果:

plaintext equals decryptedtext: true
decryptedtext: my secret

安全警告:下面的代码使用了 UNSECURE 算法“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("https://stackoverflow.com/questions/63185927/java-secretkey-to-string-and-rebuilding-back-to-secretkey-produces-different-de");
        // 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;
    }
}

推荐阅读