[Duda]Obtener hash MD5 con C++

Iniciado por final_frontier, 3 Septiembre 2010, 06:16 AM

0 Miembros y 1 Visitante están viendo este tema.

final_frontier

Buenas, investigando investigando encontré una supuesta librería con la que podría obtener el MD5 de una cadena de texto (sigo sin distinguir bien si esto va aquí o en criptografía >_>) y estoy usando la función md5 de openssl:

Código (cpp) [Seleccionar]
#include <iostream>
#include <openssl/md5.h>
#include <cstdlib>
#include <cstdio>

using namespace std;

int main()
{

   unsigned char* cad1;
   unsigned char* cad2 = (unsigned char*)malloc(sizeof(char)*256);

   cad1 = (unsigned char*)"ejemplo";

   cad2 = MD5(cad1, sizeof(cad1), cad2);

   cout<<cad1<<endl<<cad2<<endl;
   cout<<"Presiona una tecla para continuar...";
   getchar();
   return 0;
}


Y el resultado que da por consola es este:

ejemplo
"�\�<��8D?��o
Presiona una tecla para continuar...


Me he leído la doc que hay en man 3 md5 pero no encuentro el problema  :huh:
Alguna ayuda?

Un saludo
Sie ist der hellste Stern von allen und wird nie vom Himmel fallen...

Littlehorse

En estos momentos no tengo la implementación de openssl como para probar, pero viendo el código, se ven dos errores:

Código (cpp) [Seleccionar]

cad1 = (unsigned char*)"ejemplo";


Las cadenas literales son constantes, por tanto, el puntero debería tener el calificador const. Ademas, generalmente las cadenas literales se encuentran en una sección de solo lectura.

En casos como estos, lo ideal es:

Código (cpp) [Seleccionar]
const unsigned char* cad1="Ejemplo";

lo cual implica que cualquier intento de asignación posterior devuelve un error.

O bien, inicializar un arreglo:

Código (cpp) [Seleccionar]
unsigned char cad1[]="Ejemplo";

El segundo error:

Código (cpp) [Seleccionar]
cad2 = MD5(cad1, sizeof(cad1), cad2);

cad1 es un puntero, sizeof(cad1) devolverá 4 bytes (tamaño del puntero) y sizeof(*cad1) devolverá el tamaño del primer elemento de la cadena, es decir 1 byte, lo cual es incorrecto debido al objetivo de ese parámetro.

Saludos!
An expert is a man who has made all the mistakes which can be made, in a very narrow field.

final_frontier

#2
Pues tengo un problema :\

Si hago
Código (cpp) [Seleccionar]
const unsigned char* cad1="Ejemplo";
me tira este error:
main.cpp:11: error: invalid conversion from 'const char*' to 'const unsigned char*'

Y el primer argumento de la función MD5 me da un error si subsano el error anterior con un casting:
main.cpp:16: error: invalid conversion from 'const unsigned char*' to 'const char*'
main.cpp:16: error:   initializing argument 1 of 'size_t strlen(const char*)'

Si hago otro casting para evadir eso me sigue tirando basura

Prototipo de la función MD5:
Código (cpp) [Seleccionar]
unsigned char *MD5(const unsigned char *d, unsigned long n,
                        unsigned char *md);


Según man:

MD2(), MD4(), and MD5() compute the MD2, MD4, and MD5 message digest of the n bytes at d and place it in md (which must have space for MD2_DIGEST_LENGTH == MD4_DIGEST_LENGTH == MD5_DIGEST_LENGTH == 16 bytes of output). If md is NULL, the digest is placed in a static array.

Así que en el 3º parámetro se puede poner NULL y la cadena la devuelve, así que lo hice habiendo hecho castings para que dejara de tirarme errores (pero la variable por fuerza ya no es del tipo que debiera)

Código (cpp) [Seleccionar]
cad2 = MD5(cad1, strlen((char*)cad1)*sizeof(char), NULL);

En esta parte ya empiezo a perder los nervios...

por la explicación que diste, calculé el tamaño de la cadena y lo multipliqué por lo que ocupa un char un memoria, ya que: MD5 message digest of the n bytes at d and place it in md

Código (cpp) [Seleccionar]
#include <iostream>
#include <openssl/md5.h>
#include <cstdlib>
#include <cstdio>
#include <cstring>

using namespace std;

int main()
{
   const unsigned char* cad1 = (unsigned char*)"Ejemplo";
   unsigned char* cad2 = (unsigned char*)malloc(sizeof(char)*256);

   cad2 = MD5(cad1, strlen((char*)cad1)*sizeof(char), NULL);
   cout<<cad1<<endl<<cad2<<endl;
   cout<<"Presiona una tecla para continuar...";
   getchar();
   return 0;
}


Ejecuto el code, y sigue igual D:
y si dejo esas partes como me dijiste me tira error el compilador, el caso es que tengo un code en C casi igual

#include <openssl/md5.h>
#include <stdio.h>
#include <string.h>
// code testing by p0fk!

int main(int argc, char *argv[]){

       unsigned char* hash;
       int i;
       printf("Frase : %s\n", argv[1]);
       hash = MD5(argv[1], strlen(argv[1]), NULL);

       for (i = 0;i < strlen(hash);i++){
       printf("%x",hash[i]);
       }

printf("\n");
return 0;

}


Y aquí es ya cuando perdí los nervios del todo:

1.- Porqué si paso el code de C a C++ me da error con los parámetros de las funciones cuando lo dejo EXACTAMENTE IGUAL?

2.- Porqué C++ es así de ca**** con los tipos de las variables y C no?

3- Cómo voy a hacer bien el code si me obliga el compilador a usar castings por todas partes?

Un saludo

Para la pregunta 1 tengo una prueba:

finalfrontier@rabidalap:~/Downloads$ gcc main.c -lssl -lcrypto -o main
finalfrontier@rabidalap:~/Downloads$ g++ main.cpp -lssl -lcrypto -o main
main.cpp: In function 'int main(int, char**)':
main.cpp:12: error: invalid conversion from 'char*' to 'const unsigned char*'
main.cpp:12: error:   initializing argument 1 of 'unsigned char* MD5(const unsigned char*, size_t, unsigned char*)'
main.cpp:14: error: invalid conversion from 'unsigned char*' to 'const char*'
main.cpp:14: error:   initializing argument 1 of 'size_t strlen(const char*)'
finalfrontier@rabidalap:~/Downloads$

Versión de gcc creo que la 4.4, Debian Squeeze 2.6.32-5-686
Sie ist der hellste Stern von allen und wird nie vom Himmel fallen...

Littlehorse

 ;D, vamos por partes:

Primero que nada, si no solucionas los errores en un código en determinado lenguaje, no lo intentes con otro solo por probar. C++ y C comparten muchas cosas pero también difieren en otras, por tanto en gran parte de los casos lo único que vas a obtener es dolores de cabeza extras.


CitarY el primer argumento de la función MD5 me da un error si subsano el error anterior con un casting:
main.cpp:16: error: invalid conversion from 'const unsigned char*' to 'const char*'
main.cpp:16: error:   initializing argument 1 of 'size_t strlen(const char*)'

Normal, es lo que debería suceder debido a que son distintos tipos a pesar que compartan el mismo tamaño y los mismos requerimientos de alineación.


Citar
   
Código (cpp) [Seleccionar]
const unsigned char* cad1 = (unsigned char*)"Ejemplo";
    unsigned char* cad2 = (unsigned char*)malloc(sizeof(char)*256);

    cad2 = MD5(cad1, strlen((char*)cad1)*sizeof(char), NULL);

No es necesario el *sizeof, al menos que en algún punto planees utilizar unicode, pero en el código actual no es lo que ocurre. Un char es 1 byte.

Proba esto:

Código (cpp) [Seleccionar]
     
unsigned char *hash=(unsigned char*)malloc(sizeof(char)*MD5_DIGEST_LENGTH);
const unsigned char cad1[]="Ejemplo";
  //Asegurarse que hash este terminada en NULL.
  MD5(cad1, strlen(reinterpret_cast<const char*>(cad1)),hash);
  //O podes hacer, en este caso, sizeof(cad1), ya que cad1 en este caso no es un puntero si no un array.
  cout<<"Frase: "<<cad1<<endl<<"Hash: "<<hash<<endl;



CitarPorqué si paso el code de C a C++ me da error con los parámetros de las funciones cuando lo dejo EXACTAMENTE IGUAL?

Habría que ver que tipos de errores, pero teniendo en cuenta que son dos lenguajes distintos no debería ser una sorpresa. Pasar de un lenguaje a otro sin mas como mínimo te garantiza algún que otro error.

Citar2.- Porqué C++ es así de ca**** con los tipos de las variables y C no?

No debería? es porque C++ utiliza un chequeo de tipos mas estricto, que en gran parte de los casos es una ventaja y no al revés.

Citar
3- Cómo voy a hacer bien el code si me obliga el compilador a usar castings por todas partes?

El problema es que estas acostumbrado a utilizar old-style casting, común en C pero obsoleto en C++. De hecho C++ provee toda una nueva gama de operadores para dicha tarea.

C++ Casting operators

Saludos!
An expert is a man who has made all the mistakes which can be made, in a very narrow field.

final_frontier

Nada, sigue sin funcionar ni con el code que has puesto, pero no he entendido una cosa (aunque no creo que importe si no va..)

Asegurarse que hash este terminada en NULL.

:huh: :huh:

Perdona mi ignorancia compañero, pero no se que quieres decir ahí
Sie ist der hellste Stern von allen und wird nie vom Himmel fallen...

Littlehorse

Lamentablemente mas no puedo hacer porque no tengo la implementación de openssl instalada, pero funcionar debería funcionar correctamente con el código que te puse al menos que dentro de la función haya errores de los cuales no estamos al tanto. En todo caso postea los errores así lo vemos.  :D

CitarPerdona mi ignorancia compañero, pero no se que quieres decir ahí

Si, las cadenas al estilo C, deben finalizar con un carácter nulo . '\0', 0, etc. Como desconozco la tarea que realiza la función MD5, lo aclare por las dudas.

Si no sabes lo que es el carácter nulo, te recomendaría que le des un repaso al manejo de cadenas.

Saludos
An expert is a man who has made all the mistakes which can be made, in a very narrow field.

final_frontier

#6
Ya entiendo, esque eso de la cadena terminada en NULL me quedé así como  :huh: :silbar:

El caso es que el code no tira error pero sigue sin funcionar  :(

Conoces en C/C++ alguna otra forma de obtener un md5??
He hecho de todo y parece no funcionar :(

Un saludo

Lh: Uniendo mensajes. Usa el botón modificar  ;D

Ya tengo la gracia del año :xD

La cadena no viene "digerida" del todo y cada carácter hay que representarlo como hexadecimal

        for (i = 0;i < strlen(hash);i++){
        printf("%x",hash[i]);
        }


Ahora lo que busco es guardarlo todo en una única cadena y ya está xD

Un saludo
Sie ist der hellste Stern von allen und wird nie vom Himmel fallen...

Littlehorse

 :laugh: ;-)

Nunca se me hubiese ocurrido que ese era tu problema, porque en el código que pusiste en C, ya tenias hecha la parte donde imprimías los caracteres, y lo hacías precisamente de esa forma  ;D.
En C++ podes usar el manipulador hex o ::setf.

Saludos
An expert is a man who has made all the mistakes which can be made, in a very narrow field.

Karman

#8
unsigned char *MD5String (int inlen,unsigned char *inString){
  static unsigned char rBuf[1024];
  unsigned char tBuf[512];int i;
  MD5(inString,inlen,tBuf);
  for(i=0;i<16;i++)
    sprintf((char*)&rBuf[i*2],"%02x",tBuf[i]&0xFF);
  return rBuf;
}


S2