英文:
Java: SecretKey to String and rebuilding back to SecretKey produces different decryption result
问题
目前我已经为我的任务创建了一个用于RC4加密的SecretKey。在RC4加密之后,我会将这个密钥转换成字符串,然后通过UDP发送到服务器,但是当我在服务器端使用SecretKeySpec重新构建它时,它会产生一个完全不同的密钥。
我已经在stackoverflow上寻找了解决方案,但最终重建的SecretKey仍然与我的原始SecretKey不同。
我尝试在客户端代码中从字符串格式重建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的加密相关的一些非常基本的东西,对不起,因为这是我第一次使用它们。提前感谢您的帮助!
Edit2:
以下是我目前用于RC4加密和解密的代码:
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;
}
上面的代码是我在接收到来自客户端的byte[]后尝试在服务器端重建SecretKey的原因。
我尝试使用"rebuiltSK"作为SecretKey参数运行解密,但它不会产生正确的明文,尽管我已经检查了客户端和服务器上的packet.getData()是相同的。
英文:
Currently i've created a SecretKey for use in a RC4 encryption for my assignment. After the RC4 encryption i would then convert this key into string and send it to a server via UDP however when i rebuild it on the server side using SecretKeySpec, it would produce a completely different secret key.
I've looked around stackoverflow for solutions but the end would still result in a rebuilt SecretKey being different from my original SecretKey.
I've tried rebuilding the Secret Key from the String format on the client code and the result would still be a different SecretKey compared to the original so i doubt my UDP tranmission has anything to do with the result.
Below are how i went about creating the initial SecretKey for use in a RC4 encryption:
KeyGenerator keygen = KeyGenerator.getInstance("RC4");
SecretKey originalSecretKey = keygen.generateKey();
How i converted the SecretKey to String and rebuilt using SecretKeySpec:
String k = Base64.getEncoder().encodeToString(originalSecretKey.getEncoded());
byte[] decodedKey = Base64.getDecoder().decode(k);
SecretKey rebuiltSK = new SecretKeySpec(decodedKey, "RC4");
When I println "originalSecretKey" and "rebuiltSK" for checking, this is where I realised the rebuilt values are completely different and therefore i wouldnt be able to decrypt any originalSecretKey-encrypted message using the rebuiltSK.
Edit1: Silly me, thank you to "A Developer" and "Daniel" for pointing out that the actual .getEncoded() values of "originalSecretKey" and "rebuiltSK" are the same.
Apologies if I'm missing something extremely basic regarding Key generation and java's cryptography as this is my first time using them. Thank you in advance for your help !
Edit2:
Below is the code i'm currently using for my RC4 encryption and decryption:
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;
}
The code above is the reason why I'm trying to rebuild the secretKey on the server end after receiving it in byte[] from the client.
I've tried running the decryption with the "rebuiltSK" as the SecretKey argument however it doesn't produce the correct plaintext although I've checked the packet.getData() on both client and server to be the same.
答案1
得分: 1
你重建的SecretKey正常工作,加密后解密可以还原原始明文。
我只能争辩(与@Daniel一样)密钥在传输过程中发生了变化,或者(byte[] with the)密文没有完全传输到服务器。
下面的完整示例代码展示了密钥生成、加密和解密的完整过程。
这是结果:
明文等于解密文本:true
解密文本:我的秘密
安全警告:下面的代码使用了不安全的算法'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");
// 安全警告:算法'RC4'或'ARCFOUR'不安全,
// 仅用于教育目的,请不要在生产中使用此代码
// 密钥生成
KeyGenerator keygen = KeyGenerator.getInstance("RC4");
SecretKey originalSecretKey = keygen.generateKey();
// 加密
byte[] plaintext = "my secret".getBytes(StandardCharsets.UTF_8);
byte[] ciphertext = encryptRC4(plaintext, originalSecretKey);
// 解密
String k = Base64.getEncoder().encodeToString(originalSecretKey.getEncoded());
byte[] decodedKey = Base64.getDecoder().decode(k);
SecretKey rebuiltSK = new SecretKeySpec(decodedKey, "RC4");
byte[] decryptedtext = decryptRC4(ciphertext, rebuiltSK);
// 输出
System.out.println("明文等于解密文本:" + Arrays.equals(plaintext, decryptedtext));
System.out.println("解密文本:" + 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;
}
}
英文:
Your rebuilding of the SecretKey works like expected and the encryption followed by the decryption retrieves the
original plaintext.
I can only that argue (same as @Daniel) that the key was changed during transmission or the (byte[] with the)
ciphertext was not fully transmitted to the server.
The below full example code shows a complete round with key generation, encryption and decryption.
This is the result:
plaintext equals decryptedtext: true
decryptedtext: my secret
Security warning: The code below uses an UNSECURE algorithm 'RC4' or 'ARCFOUR'.
Please do not copy below code or use it in production - it is for educasional purposes only.
The code does not have any proper exception handling !
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;
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论