Si no saben de que va el tema aquí dejo unos links.
Block cipher mode of operation
https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
Wikipedia Padding oracle attack
https://en.wikipedia.org/wiki/Padding_oracle_attack
Padding oracle attack
https://robertheaton.com/2013/07/29/padding-oracle-attack/
Este tipo de Ataque tiene ciertas condiciones iniciales para ser llevado acabo.
- El cliente solo puede saber si su paquete fue aceptado o no.
- El servidor no Cambia de KEY utilizada durante el proceso de cifrado y descifrado.
- El servidor tiene algún leak de información ya sea por error o mediante otro tipo de ataque.
- El cliente solo podrá descifrar Una parte de la información, excepto por el Bloque inicial
Dejo a continuación una imagen de prueba y el código, proximamente subire un video hablando del tema.
Codigo, este codigo ejemplifica el cliente y servidor mediante un hilo distinto, lo hice de esta manera para no complicarme con el protocolo en RED de los mismo, se puede hacer sin hilos, y solo con llamadas a funcion, pero la idea es garantizar que el cliente no tiene acceso al servidor.
Código
/* Desarollado por AlbertoBSD email alberto.bsd@gmail.com g++ -O3 -o opk_example opk_example.c -Wint-to-pointer-cast -pthread */ #include <time.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include<pthread.h> #include<unistd.h> #include"ctaes/ctaes.c" #define AES_BLOCKSIZE 16 struct timespec tim, tim2,sim,sim2; void crear_server(); char *tohex(char *ptr,int length); void *process_server(void *vargp); int MyCBCEncrypt(AES256_ctx *ctx, const unsigned char iv[AES_BLOCKSIZE], const unsigned char* data, int size, bool pad, unsigned char* out); int MyCBCDecrypt(AES256_ctx *ctx, const unsigned char iv[AES_BLOCKSIZE], const unsigned char* data, int size, bool pad, unsigned char* out); /* Values between Server and client */ int values_do; int values_pad; int values_length; int values_leaked; char *values_enc; char *values_leak; pthread_mutex_t mtx_values; //Mutex for those values int main(){ /* Set global values; */ tim.tv_sec = 0; tim.tv_nsec = 50000; sim.tv_sec = 0; sim.tv_nsec = 50000; values_do = 0; values_pad = 0; values_length = 0; values_leaked = 0; crear_server(); //create child "server" //This main process is the client int i,j,k,entrar; char *secret,*temp,*try_enc; char *decrypted; unsigned char GUESS; do { sleep(1); }while(values_leaked==0); //We need to wait to the leaked data temp = tohex(secret,48); i = 0; j = 0; while(i < 16) { pthread_mutex_lock(&mtx_values); switch(values_do) { case 0: GUESS = j; decrypted[15-i] = GUESS; for(k = 0; k <= i;k++) { try_enc[15-k] = try_enc[15-k] ^ decrypted[15-k] ^ (unsigned char)(i+1); } values_do = 1; values_length = 32; break; case 1: break; case 2: if(values_pad) { i++; j = 0; } else { j++; } values_do = 0; break; } pthread_mutex_unlock(&mtx_values); nanosleep(&tim , &tim2); } } void *process_server(void *vargp) { AES256_ctx ctx; FILE *urandom; const char *secret = "The password is: Ywgo/@g:2$0Qsz<"; char *key,*dec,*enc,*iv,*temp; int length,i,pad_valid,outlen; unsigned char pad; AES256_init(&ctx,(const unsigned char*) key); /* LEAK THE secret */ pthread_mutex_lock(&mtx_values); outlen = MyCBCEncrypt(&ctx, (const unsigned char*) iv, (const unsigned char*) secret, strlen(secret), true, (unsigned char*) enc); values_leaked = 1; pthread_mutex_unlock(&mtx_values); /*END LEAK*/ do { nanosleep(&sim , &sim2); pthread_mutex_lock(&mtx_values); if(values_do == 1) { length = values_length; pad_valid = 0; if(length <= 48) { outlen = MyCBCDecrypt(&ctx,( const unsigned char*) iv, (const unsigned char*) enc, length, true, (unsigned char*) dec); if(outlen > 0) { pad_valid = 1; temp = tohex(dec,length); } else { temp = tohex(dec,length); } } values_do = 2; values_pad = pad_valid; } pthread_mutex_unlock(&mtx_values); }while(1); pthread_exit(NULL); } void crear_server() { int s; pthread_t tid; pthread_attr_t attr; s = pthread_attr_init(&attr); if (s != 0) { } s = pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); if(s != 0) { } s = pthread_create(&tid,&attr,process_server,NULL); if(s != 0) { } pthread_attr_destroy(&attr); } char *tohex(char *ptr,int length){ char *buffer; int offset = 0; unsigned char c; for (int i = 0; i <length; i++) { c = ptr[i]; offset+=2; } buffer[length*2] = 0; return buffer; } int MyCBCDecrypt(AES256_ctx *ctx, const unsigned char iv[AES_BLOCKSIZE], const unsigned char* data, int size, bool pad, unsigned char* out) { int written = 0; bool fail = false; const unsigned char* prev = iv; if (!data || !size || !out) return 0; if (size % AES_BLOCKSIZE != 0) return 0; while (written != size) { AES256_decrypt(ctx, 1, out, data + written); for (int i = 0; i != AES_BLOCKSIZE; i++) *out++ ^= prev[i]; prev = data + written; written += AES_BLOCKSIZE; } if (pad) { unsigned char padsize = *--out; fail = !padsize | (padsize > AES_BLOCKSIZE); padsize *= !fail; for (int i = AES_BLOCKSIZE; i != 0; i--) fail |= ((i > AES_BLOCKSIZE - padsize) & (*out-- != padsize)); written -= padsize; } return written * !fail; } int MyCBCEncrypt(AES256_ctx *ctx, const unsigned char iv[AES_BLOCKSIZE], const unsigned char* data, int size, bool pad, unsigned char* out) { int written = 0; int padsize = size % AES_BLOCKSIZE; unsigned char mixed[AES_BLOCKSIZE]; if (!data || !size || !out) return 0; if (!pad && padsize != 0) return 0; // Write all but the last block while (written + AES_BLOCKSIZE <= size) { for (int i = 0; i != AES_BLOCKSIZE; i++) mixed[i] ^= *data++; AES256_encrypt(ctx, 1, out + written, mixed); written += AES_BLOCKSIZE; } if (pad) { // For all that remains, pad each byte with the value of the remaining // space. If there is none, pad by a full block. for (int i = 0; i != padsize; i++) mixed[i] ^= *data++; for (int i = padsize; i != AES_BLOCKSIZE; i++) mixed[i] ^= AES_BLOCKSIZE - padsize; AES256_encrypt(ctx, 1, out + written, mixed); written += AES_BLOCKSIZE; } return written; }
Saludos!