quarta-feira, 5 de novembro de 2014

Verificando Seguranca de Modulo RSA em Relacao ao Expoente Publico e

O algoritmo de "criptografia"(cifragem) do RSA eh descrito da seguinte forma:

C = M ^ e (mod N)

Onde temos:

C = Texto Cifrado
M = Texto Limpo
e = expoente publico
N = Modulo N (Numero inteiro gigante gerado a partir de dois primos(p e q)).

Nesse tipo de ataque(que podemos chamar de recuperacao de mensagens), nao nos interessa
o algoritmo de decriptografia.

Pela aritmetica modular, nos sabemos que se o valor de "e" for pequeno e o valor
de N for gigante, a segurança da mensagem vai passar a depender do tamanho da mesma,
exemplo:

M = ABCD

A = 41
B = 42
C = 43
D = 44

podemos ter M = 41424344. Elevando esse valor por um numero "e" pequeno, exemplo 3, teremos:

C = 41424344 ^ 3 (mod N)

Abaixo temos um programa para calcular isso:

----------- RSA_m_elevado_e.c ---------------
/*
 * Intruders Tiger Team Security
 * http://www.intruders.com.br/
 *
 * Brute Force Colision using RSA.
 *
 * Glaudson Ocampos - <glaudson@securitylabs.com.br>
 *
 * Compile com:
 * $ gcc -o RSA_m_elevado_e RSA_m_elevado_e.c -lssl -Wall
 */

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/engine.h>

#define  ERRO                           -1

void
uso(char *progname){
  fprintf(stdout,"BigNUM - M elevado a e.\n");
  fprintf(stdout,"Uso: %s <M> <expoente>\n", progname);
  fflush(stdout);
}

int
main(int argc, char *argv[]){
 BIGNUM *e = NULL; 
 BIGNUM *m = NULL;
 BIGNUM *r = NULL;
 BN_CTX *ctx = NULL;

 if(argc < 2){
  uso(argv[0]);
  _exit(0);
 }

 ctx = BN_CTX_new();
 if(ctx == NULL){
  fprintf(stderr,"Erro na criacao de BN_CTX\n");
  fflush(stderr);
  _exit(ERRO);
 }


 m = BN_CTX_get(ctx);  
 BN_hex2bn(&m,argv[1]);

 e = BN_CTX_get(ctx);    
 BN_hex2bn(&e,argv[2]);

 r = BN_CTX_get(ctx);
 if(BN_exp(r,m,e,ctx) == 0){
   fprintf(stderr,"Erro na elevacao a potencia!\n");
   BN_free(m);
   BN_free(r);
   BN_free(e);
   _exit(ERRO);
 }

 fprintf(stdout,"Valor: %s\n",BN_bn2hex(r));

 BN_free(m);
 BN_free(e); 
 BN_free(r); 

 return 0;
} 

---------------------------------------------

Vamos compilar e executar para ver o output:

bash-4.2# gcc -o RSA_m_elevado_e RSA_m_elevado_e.c -lssl -Wall
bash-4.2# ./RSA_m_elevado_e 
BigNUM - M elevado a e.
Uso: ./RSA_m_elevado_e <M> <expoente>
bash-4.2# ./RSA_m_elevado_e 3 2
Valor: 09
bash-4.2# ./RSA_m_elevado_e 41424344 3
Valor: 043D9EDD651B18EA9ABF5C40

Apenas olhando, ja sabemos que esse valor eh pequeno se comparado
com modulos N gigantes como de 1024 bits, 2048 e por ai vai:

bash-4.2# itts_rsa_analyzer 
Intruders Tiger Team Security
http://www.intruders.com.br
ITTS - RSA Analyzer - Versao v1.0
Desenvolvido por Glaudson Ocampos <glaudson@intruders.com.br>

itts_rsa_analyzer [opcoes]

-n <bignum>                     Checa tamanho de BIGNUM (em hexadecimal)
-p <bignum>                     Checa se BIGNUM (em hexadecimal) eh primo
-x <certificado>                Extrai Informacoes de um Certificado
-a <tamanho_modulo_N>           Exibe valor aceitavel para expoente publico (e) em relacao ao modulo N (mod N)
-h                              Exibe essa tela de ajuda.


bash-4.2# itts_rsa_analyzer -n 043D9EDD651B18EA9ABF5C40
Intruders Tiger Team Security
http://www.intruders.com.br
ITTS - RSA Analyzer - Versao v1.0

*** Numero de Bits: 91 ***
------------------------------------


Ou seja, apenas 91 bits. Vamos fazer entao uma simples
verificacao da aritmetica modular, usando um valor alto para N,
para isso podemos usar o seguinte programa:

------------- RSA_checa_m_em_relacao_N.c ---------------
/*
 * Intruders Tiger Team Security
 * http://www.intruders.com.br/
 *
 * RSA - Verificar Mensagem cifrada com expoente pequeno em relacao
 * ao Modulo N.
 * Glaudson Ocampos - <glaudson@securitylabs.com.br>
 *
 *
 */

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/engine.h>

#define  ERRO   -1

void
uso(char *progname){
  fprintf(stdout,"RSA - Checa se mensagem cifrada eh menor que mod N.\n");
  fprintf(stdout,"Uso: %s <M_elevado_e> <modulo_N>\n", progname);
  fflush(stdout);
}

int
main(int argc, char *argv[]){
 BIGNUM *N = NULL;
 BIGNUM *m = NULL;
 BIGNUM *C = NULL;
 BN_CTX *ctx = NULL;

 if(argc < 2){
  uso(argv[0]);
  _exit(0);
 }

 ctx = BN_CTX_new();
 if(ctx == NULL){
  fprintf(stderr,"Erro na criacao de BN_CTX\n");
  fflush(stderr);
  _exit(ERRO);
 }

 m = BN_CTX_get(ctx);
 BN_hex2bn(&m,argv[1]);

 N = BN_CTX_get(ctx);  
 BN_hex2bn(&N,argv[2]);

 /* Executamos C = M (mod N) */

 C = BN_CTX_get(ctx);
 BN_nnmod(C,m,N,ctx);   
 
 fprintf(stdout,"Valor: %s\n",BN_bn2hex(C));

 BN_free(N);
 BN_free(m); 
 BN_free(C); 

 return 0;
} 

----------------------------

Compilando e executando o mesmo, temos:

bash-4.2# gcc -o RSA_checa_m_em_relacao_N RSA_checa_m_em_relacao_N.c -lssl -Wall
bash-4.2# ./RSA_checa_m_em_relacao_N 
RSA - Checa se mensagem cifrada eh menor que mod N.
Uso: ./RSA_checa_m_em_relacao_N <M_elevado_e> <modulo_N>
bash-4.2# ./RSA_checa_m_em_relacao_N 2 11
Valor: 02
bash-4.2# ./RSA_checa_m_em_relacao_N 043D9EDD651B18EA9ABF5C40 
B87BD0B4783DF3CB4611F36F5B1FB7DDDCF1860E9FF745DED447AE50FA372C4682D969EAFD93DB4F10E779666591D4C4F3C1512667DE1F86859FDB5F4AD8DC7FBFB7D0696621E54D031135286E40DF478CC101EFA832E143206AE112450476559439CA6F49CAEDCD18D12F28A44DCE2DC23465A41E51767186168A700914CD33
Valor: 043D9EDD651B18EA9ABF5C40

Podemos verificar que o valor de saida eh o mesmo valor gerado em M elevado a "e".

Entao, se de algum modo, capturamos o dado (seja via sniffing, man-in-the-middle e etc)
e a chave RSA tiver um expoente publico "e" pequeno e um "modulo N" grande, entao podemos
resolver uma simples equacao para "extrair" o texto em modo limpo.

A equeacao eh a enesima raiz de C.

     e_____
M =  V C


Abaixo podemos ver um programa pra isso:

-------------- RSA-extrai.c ---------------
/*
 * Intruders Tiger Team Security
 * http://www.intruders.com.br/
 * 
 * RSA - Extrai a raiz enezima.
 * Glaudson Ocampos - <glaudson@securitylabs.com.br>
 * 
 * 
 * Compile com:
 * $ gcc -o RSA_extrai RSA_extrai.c -lmpir -Wall
 */


#include <stdio.h> 
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <mpir.h>

void
uso(char *progname){   
        fprintf(stdout,"%s <texto_cifrado> <valor_de_e>\n",progname);
        fflush(stdout);
        _exit(0);
}       
        

int
main(int argc, char *argv[]){
        mpz_t rop;
        mpz_t op;
        unsigned long int n =0;
        
 
        if(argc < 3){
                uso(argv[0]);  
        }
   
        mpz_init(rop);
        mpz_init(op);
 
        mpz_init_set_str(op,argv[1],16 ); //hexadecimal to int;
        n = atoi(argv[2]);

        mpz_root(rop,op, n);

        gmp_printf("Valor: %Zx\n",rop, rop);

        mpz_clear(rop);
        mpz_clear(op);

        return 0;
}
        
---------------------------------

bash-4.2# ./RSA_extrai                           
./RSA_extrai <texto_cifrado> <valor_de_e>
bash-4.2# ./RSA_extrai 043D9EDD651B18EA9ABF5C40 3
Valor: 41424344
bash-4.2#


Entao, eh possivel extrairmos o texto limpo quando o valor de "e"
eh pequeno em relacao ao valor de N.


Referencias:

"Cryptanalysis of RSA and Its Variantes" - M. Jason Hinek;

"Cryptanalytic Attacks on RSA" - Song Y. Yan.

Nenhum comentário:

Postar um comentário

Comentários são moderados visando evitar spams e permitir discussões sadias.