简体   繁体   English

openSSL:解密不会产生正确的纯文本

[英]openSSL: decryption not resulting in correct plain text

I need to establish two channels between client and server, first is a UDP channel for data transmission and second is TCP channel for sending key and iv for AES-128 in UDP channel. 我需要在客户端和服务器之间建立两个通道,第一个是用于数据传输的UDP通道,第二个是用于发送密钥的TCP通道,第四个是UDP通道中的AES-128。

The TCP socket is created at server as follows: TCP套接字在服务器上创建如下:

listen_fd = socket (AF_INET, SOCK_STREAM, 0);
// sa_serv contains TCP port
error = bind(listen_fd, (struct sockaddr*) &sa_serv, sizeof (sa_serv));

The UDP socket is created at server as follows: UDP套接字在服务器上创建如下:

sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
// local contains UDP port
error = bind(sock_fd, (struct sockaddr*) &local, sizeof(local));

Server needs to be able to connect to multiple clients, the TCP and UDP socket are used in select() as follows: 服务器需要能够连接到多个客户端,在select()中使用TCP和UDP套接字,如下所示:

max = (listen_fd > sock_fd) : listen_fd : sock_fd;
fd_set set;
FD_ZERO(&set);
FD_SET(listen_fd, &set); FD_SET(sock_fd, &set);

while(1)
{
      select(max + 1, &set, NULL, NULL, NULL);

      if(FD_ISSET(listen_fd, &set){
          // server accepts connection
          // server receives key and IV over TCP connection
      }
      if(FD_ISSET(sock_fd, &set){
          // server receives encrypted data from client using UDP socket
      }
}

When the server receives the data in UDP socket, the server decrypts it using the key and IV received using TCP connection; 当服务器在UDP套接字中接收到数据时,服务器将使用密钥和通过TCP连接接收到的IV对数据进行解密; the decryption code is as follows: 解密代码如下:

 int decrypt(unsigned char *plain, unsigned char *key, unsigned char *iv, unsigned char *cipher, int len)
{
   int i;

    unsigned char buf[3000];
    int outlen, tmplen;
    EVP_CIPHER_CTX ctx;
    EVP_CIPHER_CTX_init(&ctx);
    EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv);

    if(!EVP_DecryptUpdate(&ctx, buf, &outlen, cipher, len))
    {
            EVP_CIPHER_CTX_cleanup(&ctx);
            return 0;
    }

    if(!EVP_DecryptFinal_ex(&ctx, buf + outlen, &tmplen))
    {
            EVP_CIPHER_CTX_cleanup(&ctx);
            return 0;
    }

    outlen += tmplen;
    EVP_CIPHER_CTX_cleanup(&ctx);

    printf("\nLength decrypted :%d\n",outlen);

    printf("\nBuf: ");
    for(i=0; i<outlen; i++){
           plain[i] = outbuf[i];    
       printf(" %02x ",buf[i]);
    }
     printf("\n");

     return outlen;
 }

When a cipher received from client is passed to this function along with key and IV, the result plain text does not turn out to be correct (around 8 bytes are wrong). 当从客户端接收到的密码与密钥和IV一起传递给此函数时,结果纯文本证明不是正确的(大约8个字节是错误的)。 Now, one may argue that the cipher may be wrong, or the key or iv may have a problem; 现在,有人可能会认为密码可能是错误的,或者密钥或iv可能存在问题; I verified all of them. 我验证了所有人。

But the strange situation exists that the decryption code above deciphers correctly when I consider my server to be connected to only one client; 但是,奇怪的情况是,当我认为我的服务器仅连接到一个客户端时,上面的解密代码会正确解密。 when I don't use my TCP socket in select() and use it outside (before) select() to accept connection & get key/iv from just one client (the code for accepting connection and receiving key/iv from client is exactly the same as when used inside select()), and in select() just use UDP socket to send/receive data; 当我不在select()中使用TCP套接字并在select()之外使用它时,仅从一个客户端接受连接并获取密钥/ iv(用于接受连接并从客户端接收密钥/ iv的代码正是与在select()中使用时相同,在select()中仅使用UDP套接字发送/接收数据; encrypted data received is correctly deciphered. 正确解密了接收到的加密数据。

What I am not able to understand is that by putting the TCP socket in the select() fd_set, why the same decryption code is creating a problem, inspite of the fact that I get the correct cipher, key and IV. 我无法理解的是,尽管我得到了正确的密码,密钥和IV,但通过将TCP套接字放入select()fd_set中,为什么相同的解密代码也会造成问题。

Does anyone have an explanation for this? 有人对此有解释吗?

Thanks. 谢谢。

Assuming exactly the first 8 bytes are wrong and the following bytes are correct, then you are using a different IV for decryption than you have used for encryption. 假设前8个字节恰好是错误的,随后的字节是正确的,那么您使用的IV加密与加密使用的IV不同。 When decrypting, the IV only affects the first decrypted block (the first 128 bits of plaintext). 解密时,IV仅影响第一个解密块(明文的前128位)。

Assuming bytes at the end are wrong: are you correctly taking message expansion into account? 假设末尾的字节是错误的:您是否正确考虑了消息扩展? Ie are you sending the full ciphertext to the other end, or are you passing only len(plaintext) bytes of ciphertext? 即您是将完整的密文发送到另一端,还是仅传递len(明文)个字节的密文?

Additional points: 其他要点:

  • In case you are re-using the same IV for multiple UDP packets: you should use a different IV for each message (each separately encrypted UDP packet). 如果要对多个UDP数据包重新使用相同的IV:对于每个消息(每个单独加密的UDP数据包)应使用不同的IV。
  • You might want to use a random IV and prepend it to the ciphertext you send over UDP instead of passing it via an out-of-band channel. 您可能要使用随机IV,并将其放在通过UDP发送的密文之前,而不是通过带外通道传递。
  • TCP is not a good out-of-band channel because it is insecure. TCP不安全,因此不是一个好的带外通道。

Essentially, what you are doing is reinventing DTLS. 本质上,您正在做的是重新发明DTLS。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM