enc aes256 c openssl aes

enc - openssl aes256



Modo de cifrado AES CTR 256 de operaciĆ³n en OpenSSL (2)

Parece que el problema básico con su programa de prueba es que los valores de modo de las llamadas de fopen no son correctos. Creo que necesitas cambiar tus llamadas de cierre en cifrado a esto:

fp=fopen("input.txt","rb"); op=fopen("output.txt","wb");

Y los que desciframos a:

rp=fopen("recovered.txt","wb"); op=fopen("output.txt","rb");

Otra cosa que vale la pena señalar es que ckey probablemente debería declararse como un búfer de 32 bytes (256 bits). Es cierto que el cifrado de 128 bits solo utiliza 16 bytes de los datos de la clave. Pero la función de OpenSSL AES_set_encrypt_key (al menos en la versión que estoy usando) lee 32 bytes de ese búfer. Solo usa el número apropiado de bytes, pero la lectura ocurre. Eso significa que si el búfer tiene solo 16 bytes y el final de la página es adyacente a una página no legible en la memoria, esto resultaría en una violación de acceso.

Ah, y acabo de notar que hay una llamada extraña para free allí. El free(buffer); La llamada no es válida ya que el búfer nunca fue asignado. Me doy cuenta de que su código es solo una prueba simple, pero ... bueno, somos programadores y no podemos ayudarnos a nosotros mismos.

Soy nuevo en OpenSSL, ¿alguien puede darme una pista sobre cómo inicializar el modo CTR AES desde un archivo C. Sé que esta es la firma del método, pero tengo problemas con los parámetros, no hay mucha documentación ni un ejemplo claro de cómo hacer un cifrado simple. Apreciaría si alguien pudiera ejemplificar una llamada a este método. ¡Gracias por adelantado!

void AES_ctr128_encrypt(const unsigned char *in, unsigned char *out, const unsigned long length, const AES_KEY *key, unsigned char ivec[AES_BLOCK_SIZE], unsigned char ecount_buf[AES_BLOCK_SIZE], unsigned int *num);

Hola, Caf. Aprecio mucho tu respuesta rápida. Ha sido realmente útil, y definitivamente el mejor ejemplo que he encontrado en la web. Estoy tratando de abrir un archivo con una longitud indeterminada, cifrarlo y escribir otro archivo con el texto cifrado generado, luego abrir el archivo cifrado y recuperar el texto plano. Necesito usar un archivo de una cantidad considerable de MB porque me gustaría comparar el rendimiento de la CPU. Sin embargo todavía estoy teniendo un problema al descifrar. De alguna manera, al descifrar un considerable archivo de texto (1504KB) no se descifra, y obtengo la mitad en texto plano y la otra mitad aún está cifrada. Creo que esto podría estar relacionado con el tamaño del iv o la forma en que llamo al contador. Aquí está lo que tengo hasta ahora:

#include <openssl/aes.h> #include <stdio.h> #include <string.h> struct ctr_state { unsigned char ivec[16]; unsigned int num; unsigned char ecount[16]; }; FILE *fp; FILE *rp; FILE *op; size_t count; char * buffer; AES_KEY key; int bytes_read, bytes_written; unsigned char indata[AES_BLOCK_SIZE]; unsigned char outdata[AES_BLOCK_SIZE]; unsigned char ckey[] = "thiskeyisverybad"; // It is 128bits though.. unsigned char iv[8] = {0};//This should be generated by RAND_Bytes I will take into consideration your previous post struct ctr_state state; int init_ctr(struct ctr_state *state, const unsigned char iv[8]){ state->num = 0; memset(state->ecount, 0, 16); memset(state->ivec + 8, 0, 8); memcpy(state->ivec, iv, 8); } void encrypt(){ //Opening files where text plain text is read and ciphertext stored fp=fopen("input.txt","a+b"); op=fopen("output.txt","w"); if (fp==NULL) {fputs ("File error",stderr); exit (1);} if (op==NULL) {fputs ("File error",stderr); exit (1);} //Initializing the encryption KEY AES_set_encrypt_key(ckey, 128, &key); //Encrypting Blocks of 16 bytes and writing the output.txt with ciphertext while (1) { init_ctr(&state, iv); //Counter call bytes_read = fread(indata, 1, AES_BLOCK_SIZE, fp); AES_ctr128_encrypt(indata, outdata, bytes_read, &key, state.ivec, state.ecount, &state.num); bytes_written = fwrite(outdata, 1, bytes_read, op); if (bytes_read < AES_BLOCK_SIZE) break; } fclose (fp); fclose (op); free (buffer); } void decrypt(){ //Opening files where text cipher text is read and the plaintext recovered rp=fopen("recovered.txt","w"); op=fopen("output.txt","a+b"); if (rp==NULL) {fputs ("File error",stderr); exit (1);} if (op==NULL) {fputs ("File error",stderr); exit (1);} //Initializing the encryption KEY AES_set_encrypt_key(ckey, 128, &key); //Encrypting Blocks of 16 bytes and writing the output.txt with ciphertext while (1) { init_ctr(&state, iv);//Counter call bytes_read = fread(indata, 1, AES_BLOCK_SIZE, op); AES_ctr128_encrypt(indata, outdata, bytes_read, &key, state.ivec, state.ecount, &state.num); bytes_written = fwrite(outdata, 1, bytes_read, rp); if (bytes_read < AES_BLOCK_SIZE) break; } fclose (rp); fclose (op); free (buffer); } int main(int argc, char *argv[]){ encrypt(); //decrypt(); system("PAUSE"); return 0; }

Cada función de cifrado y descifrado se llama en diferentes ejecuciones, por lo que todo se inicializa siempre con los mismos valores. Gracias de nuevo por los consejos que me pueden proporcionar por adelantado y saludos!


Por lo general, tendrá la intención de llamar a AES_ctr128_encrypt() repetidamente para enviar varios mensajes con la misma clave y IV, y un contador incremental. Esto significa que necesita realizar un seguimiento de los valores ''ivec'', ''num'' y ''ecount'' entre las llamadas, así que cree una struct para mantener estos y una función de inicialización:

struct ctr_state { unsigned char ivec[16]; /* ivec[0..7] is the IV, ivec[8..15] is the big-endian counter */ unsigned int num; unsigned char ecount[16]; }; int init_ctr(struct ctr_state *state, const unsigned char iv[8]) { /* aes_ctr128_encrypt requires ''num'' and ''ecount'' set to zero on the * first call. */ state->num = 0; memset(state->ecount, 0, 16); /* Initialise counter in ''ivec'' to 0 */ memset(state->ivec + 8, 0, 8); /* Copy IV into ''ivec'' */ memcpy(state->ivec, iv, 8); }

Ahora, cuando comience a comunicarse con el destino, deberá generar un IV para usar e inicializar el contador:

unsigned char iv[8]; struct ctr_state state; if (!RAND_bytes(iv, 8)) /* Handle the error */; init_ctr(&state, iv);

A continuación, deberá enviar el 8 byte IV al destino. También deberá inicializar un AES_KEY desde sus bytes de clave sin AES_KEY :

AES_KEY aes_key; if (!AES_set_encrypt_key(key, 128, &aes_key)) /* Handle the error */;

Ahora puede comenzar a cifrar los datos y enviarlos al destino, con llamadas repetidas a AES_ctr128_encrypt() esta manera:

if (!AES_ctr128_encrypt(msg_in, msg_out, msg_len, &aes_key, state->ivec, state->ecount, &state->num)) /* Handle the error */;

( msg_in es un puntero a un búfer que contiene el mensaje de texto sin formato, msg_out es un puntero a un búfer donde debe ir el mensaje cifrado, y msg_len es la longitud del mensaje).

El descifrado es exactamente el mismo, excepto que no genera el IV con RAND_bytes() , sino que toma el valor que le da el otro lado.

Importante:

  1. No llame a init_ctr() más de una vez durante el proceso de cifrado. El contador y el IV deben inicializarse solo una vez antes del inicio del cifrado.

  2. Bajo ninguna circunstancia, RAND_bytes() obtener el IV en otro lugar que no sea RAND_bytes() en el lado del cifrado. No lo establezca en un valor fijo; no use una función hash; no use el nombre del destinatario; no lo lea desde el disco RAND_bytes() con RAND_bytes() y envíelo al destino. Siempre que comience con un contador cero, debe comenzar con un IV completamente nuevo que nunca haya usado antes.

  3. Si es posible que esté enviando 2 ** 64 bytes sin cambiar el IV y / o la clave, tendrá que probar el desbordamiento del contador.

  4. No omita la comprobación de errores. Si falla una función y la ignora, es muy posible (incluso probable) que su sistema parezca funcionar normalmente, pero en realidad funcionará de forma totalmente insegura.