2015-04-03 3 views
3

Итак, у меня есть этот код, который в основном шифрует два текстовых сообщения, а затем пытается их расшифровать и распечатать. Проблема в том, что первое сообщение восстанавливается отлично, а второе - мусор. Я загрузил этот код с this tutorial, а затем модифицировал его для работы со строками вместо файлов как Мне нужно его для отправки зашифрованного текста поверх сокетов. Так что длина открытого текста не будет известна другой конечной точке, есть ли способ найти длину или мне придется как-то отправить длину открытого текста вместе с шифром?Шифрование и дешифрование AES CTR

Теперь, я думаю, что есть проблема в режиме разрыва дешифрования.

Кроме того, является основным() кодом права концептуально: шифрование сообщений с обновлением состояния, а затем сброс состояния и дешифрование сообщений с обновлением состояния?

И есть ли способ узнать фактическую длину шифрованного текста (а не буфера)?

Это всего лишь манекен, который я пытался понять, как работает AES CTR.

#include <openssl/aes.h> 
#include <openssl/rand.h> 
#include <openssl/hmac.h> 
#include <openssl/buffer.h> 
#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <math.h> 

// Code example uses partail code from: http://stackoverflow.com/questions/3141860/aes-ctr-256-encryption-mode-of-operation-on-openssl 
// Mostly in the ctr_ state, and init_ctr functions. 

struct ctr_state 
{ 
    unsigned char ivec[AES_BLOCK_SIZE]; 
    unsigned int num; 
    unsigned char ecount[AES_BLOCK_SIZE]; 
}; 

int init_ctr(struct ctr_state *state, const unsigned char iv[16]) 
{   
    /* aes_ctr128_encrypt requires 'num' and 'ecount' set to zero on the 
    * first call. */ 
    state->num = 0; 
    memset(state->ecount, 0, AES_BLOCK_SIZE); 

    /* Initialise counter in 'ivec' to 0 */ 
    memset(state->ivec + 8, 0, 8); 

    /* Copy IV into 'ivec' */ 
    memcpy(state->ivec, iv, 8); 
} 

void fencrypt(char* text, char* cipher, const unsigned char* enc_key, struct ctr_state* state) 
{ 
    AES_KEY key; 
    unsigned char indata[AES_BLOCK_SIZE]; 
    unsigned char outdata[AES_BLOCK_SIZE]; 
    int offset=0; 
    //Initializing the encryption KEY 
    if (AES_set_encrypt_key(enc_key, 128, &key) < 0) 
    { 
     fprintf(stderr, "Could not set encryption key."); 
     exit(1); 
    } 

    //Encrypting Blocks of 16 bytes and writing the output.txt with ciphertext 
    while(1)  
    { 
     printf("while going\n"); 
     memcpy(indata, text+offset, AES_BLOCK_SIZE); 
     AES_ctr128_encrypt(indata, outdata, AES_BLOCK_SIZE, &key, state->ivec, state->ecount, &state->num); 

     memcpy(cipher+offset, outdata, AES_BLOCK_SIZE); 
     offset=offset+AES_BLOCK_SIZE; 
     if (offset > strlen(text)) 
     { 
      break; 
     } 
    } 
} 

void fdecrypt(char* cipher, char* text, const unsigned char* enc_key, struct ctr_state* state) 
{ 
    AES_KEY key; 
    unsigned char indata[AES_BLOCK_SIZE]; 
    unsigned char outdata[AES_BLOCK_SIZE]; 
    int offset=0; 
    //Initializing the encryption KEY 
    if (AES_set_encrypt_key(enc_key, 128, &key) < 0) 
    { 
     fprintf(stderr, "Could not set decryption key."); 
     exit(1); 
    } 

    //Encrypting Blocks of 16 bytes and writing the output.txt with ciphertext  
    while(1)  
    { 
     memcpy(indata, cipher+offset, AES_BLOCK_SIZE); 
     //printf("%i\n", state.num); 
     AES_ctr128_encrypt(indata, outdata, AES_BLOCK_SIZE, &key, state->ivec, state->ecount, &state->num); 

     memcpy(text+offset, outdata, AES_BLOCK_SIZE); 
     offset=offset+AES_BLOCK_SIZE; 
     if (offset > strlen(cipher)) 
     { 
      break; 
     } 
    } 
} 

int main(int argc, char *argv[]) 
{ 
    unsigned char iv[AES_BLOCK_SIZE]; 
    struct ctr_state state; 
    char* plain="quick brown fox jumped over the lazy dog what "; 
    char* plain2="a dog he is idiot who is the genius "; 
    char cipher[128]; 
    char cipher2[128]; 
    char recovered[128]; 
    char recovered2[128]; 
    const unsigned char* enc_key="123456789abcdef0"; 

    if(!RAND_bytes(iv, AES_BLOCK_SIZE)) 
    { 
     fprintf(stderr, "Could not create random bytes."); 
     exit(1);  
    } 
    init_ctr(&state, iv); //Counter call 
    printf("Plain text length:%lu\n",strlen(plain)); 
    // BIO_dump_fp(stdout, plain, strlen(plain)); 
    // printf("Plain text:%s\n",plain); 
    fencrypt(plain, cipher,enc_key,&state); 
    fencrypt(plain2, cipher2,enc_key,&state); 
    // cipher[strlen(plain)]='\0'; 
    // BIO_dump_fp(stdout, cipher, strlen(plain)); 
    init_ctr(&state, iv); //Counter call 
    fdecrypt(cipher,recovered,enc_key,&state); 
    fdecrypt(cipher2,recovered2,enc_key,&state); 
    // printf("Cipher text length:%lu\n",strlen(cipher)); 
    printf("Recovered text:%s\n",recovered); 
    printf("Recovered text:%s\n",recovered2); 
    return 0; 
} 

ответ

4

режим CTR не требует отдельного шифрования и дешифрования метод. Ключ шифрования можно установить один раз. OpenSSL's AES_ctr128_encrypt выполняет большую часть работы, поэтому код можно упростить.

Также нам действительно нужен векторный тест. Здесь мы просто тестируем со случайным текстом «быстрая коричневая лиса ...», мы возвращаем один и тот же текст, но нет никакой гарантии, что «шифр» был прав, а не шифрование - качество AES. Я добавлю быстрый векторный тест позже, если будет время.

void init_ctr(struct ctr_state *state, const unsigned char iv[16]) 
{   
    state->num = 0; 
    memset(state->ecount, 0, 16); 
    memcpy(state->ivec, iv, 16); 
} 

void crypt_message(const u8* src, u8* dst, unsigned int src_len, const AES_KEY* key, const u8* iv) 
{ 
    struct ctr_state state; 
    init_ctr(&state, iv); 
    AES_ctr128_encrypt(src, dst, src_len, key, state.ivec, state.ecount, &state.num); 
} 

int main() 
{ 
    int len; 
    char source[128]; 
    char cipher[128]; 
    char recovered[128]; 
    unsigned char iv[AES_BLOCK_SIZE]; 

    const unsigned char* enc_key = (const unsigned char*)"123456789abcdef0"; 

    if(!RAND_bytes(iv, AES_BLOCK_SIZE)) 
    { 
     fprintf(stderr, "Could not create random bytes."); 
     exit(1);  
    } 

    AES_KEY key; 
    AES_set_encrypt_key(enc_key, 128, &key); 

    strcpy(source, "quick brown fox jumped over the lazy dog what."); 
    len = strlen(source); 
    memset(recovered, 0, sizeof(recovered)); 
    crypt_message((const u8*)source, (u8*)cipher, len, &key, iv); 
    crypt_message((const u8*)cipher, (u8*)recovered, len, &key, iv); 
    printf("Recovered text:%s\n", recovered); 

    strcpy(source, "a dog he is idiot who is the genius."); 
    len = strlen(source); 
    memset(recovered, 0, sizeof(recovered)); 
    crypt_message((const u8*)source, (u8*)cipher, len, &key, iv); 
    crypt_message((const u8*)cipher, (u8*)recovered, len, &key, iv); 
    printf("Recovered text:%s\n", recovered); 

    return 0; 
} 

Для шифрования/дешифрования файлов, или отправить/получить:

void crypt_file(const u8* src_file, const u8* dst_file, const AES_KEY* key, const u8* iv) 
{ 
    struct ctr_state state; 
    init_ctr(&state, iv); 

    const int buffer_size = 512; //not less than 16 
    unsigned char buffer_in[buffer_size]; 
    unsigned char buffer_out[buffer_size]; 
    int bytes_read; 

    //open files and/or socket 
    //file/message loop 
    { 
     //read source, obtain buffer_in and bytes_read 
     AES_ctr128_encrypt(buffer_in, buffer_out, bytes_read, key, state.ivec, state.ecount, &state.num); 
     //write buffer_out/bytes_read to destination 
    } 
    //close handles 
} 

В своем коде, fdecrypt() содержит strlen(cipher). Однако cipher - это чистые двоичные данные, strlen не работает с ним. Вы должны указать длину вручную. Я добавил len параметр в fdecrypt. В main я использую strlen(plaintext) для простоты, хотя это должна быть истинная длина данных cipher. Изменения обозначены ## изменения

void fdecrypt(unsigned int len, char* cipher, char* text, const unsigned char* enc_key, struct ctr_state* state) 
{ 
    AES_KEY key; 
    unsigned char indata[AES_BLOCK_SIZE]; 
    unsigned char outdata[AES_BLOCK_SIZE]; 
    int offset=0; 
    //Initializing the encryption KEY 
    if (AES_set_encrypt_key(enc_key, 128, &key) < 0) 
    { 
     fprintf(stderr, "Could not set decryption key."); 
     exit(1); 
    } 

    //Encrypting Blocks of 16 bytes and writing the output.txt with ciphertext  
    while(1)  
    { 
     memcpy(indata, cipher+offset, AES_BLOCK_SIZE); 
     //printf("%i\n", state.num); 
     AES_ctr128_encrypt(indata, outdata, AES_BLOCK_SIZE, &key, state->ivec, state->ecount, &state->num); 

     memcpy(text+offset, outdata, AES_BLOCK_SIZE); 
     offset=offset+AES_BLOCK_SIZE; 
     //if (offset > strlen(cipher))##changed 
     if (offset > len) 
     { 
      break; 
     } 
    } 
} 

int main(int argc, char *argv[]) 
{ 
    unsigned char iv[AES_BLOCK_SIZE]; 
    struct ctr_state state; 
    char* plain="quick brown fox jumped over the lazy dog what "; 
    char* plain2="a dog he is idiot who is the genius "; 
    char cipher[128]; 
    char cipher2[128]; 
    char recovered[128]; 
    char recovered2[128]; 
    const unsigned char* enc_key=(const unsigned char*)"123456789abcdef0"; 

    if(!RAND_bytes(iv, AES_BLOCK_SIZE)) 
    { 
     fprintf(stderr, "Could not create random bytes."); 
     exit(1);  
    } 

    init_ctr(&state, iv); //Counter call 
    printf("Plain text length:%lu\n",strlen(plain)); 
    // BIO_dump_fp(stdout, plain, strlen(plain)); 
    // printf("Plain text:%s\n",plain); 
    fencrypt(plain, cipher,enc_key,&state); 
    fencrypt(plain2, cipher2,enc_key,&state); 
    // cipher[strlen(plain)]='\0'; 
    // BIO_dump_fp(stdout, cipher, strlen(plain)); 
    init_ctr(&state, iv); //Counter call 
    fdecrypt(strlen(plain), cipher,recovered,enc_key,&state);//##changed 
    fdecrypt(strlen(plain2), cipher2,recovered2,enc_key,&state);//##changed 
    // printf("Cipher text length:%lu\n",strlen(cipher)); 
    printf("Recovered text:%s\n",recovered); 
    printf("Recovered text:%s\n",recovered2); 
    return 0; 
} 
+0

Я понимаю, что вы говорите, и я знал, что раньше, но проблема (как я уже говорил в этом вопросе), я буду посылать сообщение зашифрованное в сети, так другая сторона не будет знать длину обычного текста, если я не отправлю длину отдельно. Итак, я ищу способ найти длину только от шифрования, как действительно реализуются схемы шифрования по сетям? – Wajahat

+1

Barmak здесь правильно; нет способа определить длину из случайных данных (а выход AES выглядит как случайные данные). Не думайте об этом как о «передаче зашифрованных данных в сети». Подумайте об этом как о «отправке данных по сети». Почти все двоичные протоколы включают в себя поле длины. –

+0

Хорошо, ваша точка зрения, поэтому, если я использую сокеты TCP-потока в C, могу ли я добавить длину полезной нагрузки в пакете (я знаю, что в заголовке IP есть поле длины), которое можно восстановить на другом конце? Как я буду это делать, извините, что я новичок в программировании сокетов. – Wajahat

Смежные вопросы