AES CTR加密和解密

时间:2015-04-03 23:23:08

标签: c aes

所以我有这个代码,基本上,加密两个纯文本消息,然后尝试解密它们,并打印。问题是第一条消息恢复正常但第二条消息是垃圾。我从this tutorial下载了此代码,然后将其修改为使用字符串而不是文件我需要它来通过套接字发送加密文本。因此,明文的长度不会是其他端点知道,有没有办法找到长度,或者我必须以某种方式发送明文长度和密码?

现在,我认为解密的中断条件存在问题。

此外,main()代码在概念上是正确的:加密具有更新状态的消息然后重置状态并解密具有更新状态的消息吗?

有没有办法找出密文的实际长度(不是缓冲区)?

这只是一个虚拟程序,我试图了解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;
}

1 个答案:

答案 0 :(得分:4)

CTR模式不需要单独的加密和解密方法。加密密钥可以设置一次。 OpenSSL的AES_ctr128_encrypt负责大部分工作,因此可以简化代码。

我们真的需要矢量测试。在这里,我们只是测试随机文字&#34;快速棕色狐狸......&#34;,我们收回相同的文字,但无法保证&#39;密码&#39;是正确的,加密与否是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数据的真实长度。更改由## change

表示
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;
}