我需要在客户端和服务器之间建立两个通道,第一个是用于数据传输的UDP通道,第二个是用于发送密钥的TCP通道和用于UDP通道中的AES-128的iv通道。
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));
UDP套接字在服务器上创建如下:
sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
// local contains UDP port
error = bind(sock_fd, (struct sockaddr*) &local, sizeof(local));
服务器需要能够连接到多个客户端,TCP和UDP套接字在select()中使用如下:
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
}
}
当服务器在UDP套接字中接收数据时,服务器使用密钥和使用TCP连接接收的IV对其进行解密;解密代码如下:
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;
}
当从客户端接收的密码与密钥和IV一起传递给此函数时,结果纯文本结果不正确(大约8个字节是错误的)。现在,有人可能认为密码可能是错误的,或者密钥或iv可能有问题;我验证了所有这些。
但是当我认为我的服务器只连接到一个客户端时,存在奇怪的情况,即上面的解密代码正确解密;当我不在select()中使用我的TCP套接字并在外面(之前)使用它时,select()接受连接&amp;从一个客户端获取密钥/ iv(接受连接和从客户端接收密钥/ iv的代码与在select()中使用时完全相同),在select()中只使用UDP套接字发送/接收数据;收到的加密数据被正确破译。
我无法理解的是,通过将TCP套接字置于select()fd_set中,为什么相同的解密代码会产生问题,尽管我得到了正确的密码,密钥和IV。< / p>
有没有人对此有解释?
感谢。
答案 0 :(得分:1)
假设前8个字节确实是错误的并且后面的字节是正确的,那么您使用不同的IV进行解密而不是用于加密。解密时,IV仅影响第一个解密块(明文的前128位)。
假设最后的字节错误:您是否正确考虑了邮件扩展?即你是将完整的密文发送到另一端,还是只传递len(明文)字节的密文?
补充要点:
基本上,你正在做的是重新发明DTLS。