domingo, 1 de octubre de 2017

Una debilidad del cifrado RC4 - Reutilizacion del KeyStream


RC4 es un cifrado de flujo. Los cifrados de flujo funcionan expandiendo una clave secreta en una clave larga de bits pseudo-aleatorios (KeyStream).  Una debilidad bien conocida de los algoritmos de cifrado de flujo es que cifrando dos mensajes (P1, P2) con la misma clave (K) y vector S[] se puede revelar información sobre ambos mensajes, en esta ocasión esto es lo que vamos a realizar.


Si          C1 = P1 (+) RC4(S, K)
y           C2 = P2 (+) RC4(S, K)

entonces:

     C1 (+) C2 = (P1 (+) RC4(S, K)) (+) (P2 (+) RC4(S, K)) = P1 (+) P2


Es decir, si aplicamos un XOR a los dos texto cifrados (C1 y C2) el keystream se cancela, y el resultado que obtenemos de eso es el XOR de los textos iniciales (P1 XOR P2).

Si disponemos de uno de los textos iniciales (P1) o (P2), esto nos permitiria obtener el otro texto inicial (P1) o (P2), con tan solo aplicar un XOR entre el texto inicial que tenemos (P) y el resultado de aplicar XOR entre los dos textos cifrados (C1 XOR C2).


RC4


Como anteriormente vimos, en este caso utilizaremos de nuevo el programa anterior RC4.c para obtener 2 textos cifrados que nosotros mismos ingresemos y la misma clave de cifrado para ambos. Debo agregar que para facilidad del ejemplo ingresemos 2 textos del mismo tamaño:



*Nota: Los textos ingresados del primer parámetro son del mismo tamaño y las claves son las mismas.


Implementación


Para realizar la implementación, como casi siempre utilizando el lenguaje de programación C. El programa anteriormente implementado del cifrado RC4 lo he pasado como libreria y he agregado un archivo "Make" para la compilación de los archivos del programa.


*Nota: Al ejecutar make en la ubicacion donde se encuentra nuestro archivo make, compilara lo indicado en el archivo, generala los objetos y luego el ejecutable.


Continuando, ejecutamos el ejecutable que tiene 4 parametros (./attrc4 texto1 clave1 texto2 clave2) , para nuestro ejemplo las cadenas tienen que ser de la misma longitud y las claves las mismas para ambos:


*Nota: El programa attrc4 cifra los textos 1 y 2 con las claves 1 y 2 ingresadas por parametro. Luego a partir del texto 1 ingresado y al aplicar XOR entre los textos cifrados, obtiene el segundo texto ingresado (texto 2).


Como podemos visualizar, el programa cifra el primer parámetro (P1) con la clave ingresada en el segundo parámetro y nos muestra en pantalla el texto cifrado 1 (C1), luego cifra el tercer parametro (P2) con la clave ingresada en el cuarto parámetro y nos muestra en pantalla el texto cifrado 2 (C2).

A partir de aplicar el XOR entre C1 y C2, obtenemos el texto 2 (P2) al de nuevo aplicar XOR entre el resultado de (C1 XOR C2) y el texto 1 (P1).


Código


En la parte del código, es lo ya explicado anteriormente y bueno, adicional mente existe una función para obtener el máximo de 2 números, que utilicé para obtener el tamaño de la cadena de mayor caracteres, en caso de que ingreses cadenas iniciales de diferente longitud, veras que retorna una cadena de N caracteres, donde N es el máximo(longitud(P1), longitud(P2)), pero solo los caracteres correctos serán el mínimo(longitud(P1), longitud(P2)) los caracteres restantes corresponden a la parte sin descifrar.
Pueden ver el codigo fuente aqui.

El código de la función principal:



/**
    Autor: PaoloRamirez
    Tema: Debilidad cifrado RC4 - Reutilizacion del KeyStream
    Link: https://www.facebook.com/PaoloProgrammer/
**/

#include <stdio.h>
#include <string.h>
#include <stdlib.h> 
#include "rc4.h"

int maximo(int a, int b)
{
    if (a>b)
    {
        return a;
    }
    else
    {
        return b;
    }
}

int main(int argc, char **argv) 
{
    int i=1;
    int indice=0; //Indica el texto que utilizamos (texto 1, texto2)

    int len;
    len=maximo(strlen(argv[1]), strlen(argv[3])); //Tamaño maximo de los 2 textos del parametro
    unsigned char text_cifrado[2][len+1];
    memset(text_cifrado[0],0,sizeof(text_cifrado[0]));
    memset(text_cifrado[1],0,sizeof(text_cifrado[1]));

    for (i = 1; i < 5; i+=2)
    {

        int len_texto,len_clave;
        len_texto=strlen(argv[i]);
        len_clave=strlen(argv[i+1]);

        /**
            Texto inicial
            Clave de cifrado
        **/
        //Tamaño de cadena = len+fincadena \0
        char texto[len_texto+1];
        char clave[len_clave+1];

        //Format
        memset(texto,0,sizeof(texto));
        memset(clave,0,sizeof(clave));

        //Copiar a variables
        strcpy(texto,argv[i]);
        strcpy(clave,argv[i+1]);
     
        
        int x;
        rc4_generar_vector(clave, strlen(clave));
        printf("Texto cifrado(%i):\n",indice+1);
        for (x = 0; x < strlen(texto); x++)
        {
            //Cifrado por flujo
            text_cifrado[indice][x] = texto[x] ^ rc4_salida();
            printf("%02X", text_cifrado[indice][x]);
        }

        indice++;
        printf("\n\n");
    }

    /**
        Suponiendo que sabemos el texto 1
        Y tenemos el texto cifrado de 1 (C1) y el texto cifrado de 2 (C2)
        Obtendremos el texto 2
    **/
    int x;

    /*Texto 1*/
    int len_texto_1;
    len_texto_1 = strlen(argv[1]);
    char texto_1[len_texto_1+1];
    
    //Format
    memset(texto_1,0,sizeof(texto_1));
    
    //Agregando contenido del texto 1 a nuestra cadena
    strcpy(texto_1, argv[1]);

    printf("Texto 1:\n%s\n\n",texto_1);

    /**
        1. Obtener el resultado de aplicar XOR entre textos cifrados-> C1 XOR C2
    **/

    /*Resultado del XOR entre C1 y C2*/
    unsigned char c1_xor_c2[len+1];
    memset(c1_xor_c2, 0, sizeof(c1_xor_c2));

    
    printf("XOR entre textos cifrados:\n");
    for (x = 0; x < len; x++)
    {
        c1_xor_c2[x] = text_cifrado[0][x] ^ text_cifrado[1][x]; //Obteniendo C1 XOR C2
        printf("%02X", c1_xor_c2[x]);
    }
    printf("\n\n");

    
    /**
        2. Obtener el texto 2 al aplicar XOR entre texto 1 XOR c1_xor_c2
    **/

    /*Texto 2*/
    int len_texto_2;
    len_texto_2 = len;
    char texto_2[len_texto_2+1];
    //Format
    memset(texto_2,0,sizeof(texto_2));

    printf("Texto 2 obtenido:\n");
    for (x = 0; x < len; x++)
    {
        texto_2[x] = c1_xor_c2[x] ^ texto_1[x]; //Obteniendo texto 2
        printf("%c", texto_2[x]);
    }
    printf("\n");    

}


Enlaces

Referencias

No hay comentarios.:

Publicar un comentario