通过 UDP 发送 RC4 加密数据会导致解密明文发生变化

Posted

技术标签:

【中文标题】通过 UDP 发送 RC4 加密数据会导致解密明文发生变化【英文标题】:Sending RC4 encrypted data over UDP causes changes in decrypted plaintext 【发布时间】:2020-07-28 23:44:52 【问题描述】:

我正在尝试使用 Java 通过 UDP 连接发送一些数据。

在客户端,我使用返回字符串的 RC4 算法加密数据。这个字符串,我转换成字节数组,作为数据报包发送。

但是,在服务器端,解密后的明文给出的结果与原始文本相似,但有一些不同。

当我独立运行 RC4 加密程序并且客户端和服务器使用相同的源代码时,它运行良好,所以我真的不明白为什么会发生这种情况。

这是客户端的代码:

import java.net.*; import javax.crypto.Cipher; import java.io.*; import java.security.*; import java.security.spec.*; import java.util.*; import java.util.Base64.*;  
 
class EchoClient 

    public static void main( String args[] ) throws Exception 
    
        Scanner sc = new Scanner (System.in);
        
        DatagramSocket socket = new DatagramSocket();
        socket.setSoTimeout(120000);
        
        //Encrypting and sending data
        System.out.print("Enter data: ");
        String password = sc.nextLine();
        String credentials = password;
        String encryptedCredentials = RC4.encryptRC4(credentials, "637443");
        byte encCred[] = encryptedCredentials.getBytes();
        DatagramPacket packetCred = new DatagramPacket(encCred,encCred.length,InetAddress.getByName(args[0]),1500);
        socket.send(packetCred);
        System.out.println("\nEncrypted Credentials sent");
        System.out.println("Plain: " + credentials);
        System.out.println("Encrypted data: " + encryptedCredentials);
    
    

这是服务器:

import java.net.*; import javax.crypto.Cipher; import java.io.*; import java.security.*; import java.security.spec.*; import java.util.*; import java.util.Base64.*;
 
class EchoServer 

    public static void main( String args[] ) throws Exception 
    
        System.out.println("Server running. Awaiting Connection Request...\n");

        Scanner sc = new Scanner (System.in);
        
        DatagramSocket socket = new DatagramSocket(1500);
        
        
        //Recieving Credentials
        DatagramPacket packetCred = new DatagramPacket(new byte[512],512);
        socket.receive(packetCred);
        String stringCred = new String(packetCred.getData(),0,packetCred.getLength());
        String decryptedCred = RC4.decryptRC4(stringCred, "637443");
        System.out.println("\nReceived Authentication Data");
        System.out.println("Bob at: "+new Date()+" "+packetCred.getAddress()+":"+packetCred.getPort()+"\nData: "+new String(packetCred.getData(),0,packetCred.getLength()));
        System.out.println("Decrypted Credentials: " + decryptedCred);

这是客户端输出:

输入数据:你好。怎么样了?我很好;谢谢。

正在设置 RC4...

开始 RC4 加密...

加密完成:

已发送加密凭据

Plain:你好。怎么样了?我很好;谢谢。

加密数据:?d¥érSÿ?dNé?=P°?Whéá=Nù?H!)îërC??f@?ï

这是服务器终端输出:

服务器正在运行。正在等待连接请求...

正在设置 RC4...

开始 RC4 解密...

解密完成:

收到的认证数据

鲍勃时间:2020 年 7 月 29 日星期三 05:01:51 IST /127.0.0.1:54835

数据:?d¥érSÿ?dNé?=P°?Whéá=Nù?H!)îërC??f@?ï

解密的凭据:你好。 How'Æ it goinÆ?我很好; 谢谢。

【问题讨论】:

问题是String不是二进制数据的容器。您的解密方法应该有一个字节数组参数,而不是String。你为什么使用RC4?它已被弃用多年,并于 2015 年被 IETF 禁止用于 TLS。 欢迎来到 ***。所有常规加密算法都基于字节数组作为 INPUT 和 OUTPUT 的源。您的 RC4 方法确实有输入字符串和返回字符串。请编辑您的问题并向我们展示用于加密和解密的 RC4 方法。我敢肯定,您的问题与其他 cmets/answers 争论的问题一样。 【参考方案1】:

我认为这是字符串编码的问题。除非您绝对确定两端使用相同的平台编码,否则切勿在未指定编码的情况下使用 String.getBytes()

在需要转换byte[]/String 的任何地方(RC4.decryptRC4()/RC4.encryptRC4()new String()String.getBytes())都这样做:

Stringbyte[].getBytes(StandardCharsets.UTF_8)

byte[]Stringnew String(byte[], int, int, StandardCharsets.UTF_8)

UTF-8 还是 ISO-8859-1 并不重要,只要两端相同

哦,正如@MarquisofLorne 所说,请不要使用 RC4,除非它仅用于教育目的。

【讨论】:

这真的很有帮助。非常感谢你!下次在字节数组和字符串之间转换时,我会一直使用它。 是的,我正在使用 RC4 进行网络协议分配。我们的老师说他不关心RC4加密,只要它有效并且协议是正确的。再次感谢!

以上是关于通过 UDP 发送 RC4 加密数据会导致解密明文发生变化的主要内容,如果未能解决你的问题,请参考以下文章

PHP 中实现 rc4加密解密

加密技术

对称加密算法和非对称加密算法

RC4加密原理

AES加密算法

数据加密总结