当前位置: 首页 > 知识库问答 >
问题:

AES CTR加密和解密

卢骏俊
2023-03-14

我有这段代码,它基本上对两条纯文本消息进行加密,然后尝试解密,然后打印。问题是第一条消息恢复得很好,但第二条消息是垃圾。我从本教程下载了这段代码,然后将其修改为使用字符串而不是文件,因为我需要它通过套接字发送加密文本。所以其他endpoint不知道明文的长度,有没有办法找到长度,或者我必须以某种方式将明文的长度与密码一起发送?

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

另外,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个答案

颜河
2023-03-14

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

我们还需要向量测试。在这里,我们只是使用随机文本“quick brown fox…”进行测试,我们返回相同的文本,但不能保证“密码”是正确的,加密与否取决于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是纯二进制数据,strlen不能处理它。您必须手动提供长度。我将len参数添加到fdecrypt。在main中,为了简单起见,我使用了strlen(纯文本),尽管它应该是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;
}
 类似资料:
  • 问题内容: 我迅速编写了一个应用程序,我需要AES加密和解密功能,我从另一个.Net解决方案中接收了加密数据,但是我找不到解决办法。 这是我的.net加密: 我需要迅速解密功能。 问题答案: 我找到了解决方案,它是一个很好的库。 跨平台256位AES加密/解密。 此项目包含在所有平台(C#,iOS,Android)上均可使用的256位AES加密的实现。关键目标之一是通过简单的实现使AES在所有平台

  • 问题内容: 我想使用128位AES加密和16字节密钥对密码进行加密和解密。解密值时出现错误。解密时我丢失任何内容吗? 错误信息 最后我基于@QuantumMechanic答案使用以下解决方案 } 问题答案: 如果对于块密码,您将不使用包含填充方案的转换,则需要使明文中的字节数为该密码的块大小的整数倍。 因此,要么将纯文本填充到16字节的倍数(即AES块大小),要么在创建对象时指定填充方案。例如,您

  • 问题内容: 我想将加密的密码存储在Java文件中。我在使用 javax.crypto 的解决方案中看到了一个问题,但是问题在于密钥是动态生成的,并且是随机的。 然后将在运行时在Java程序中获取并解密该密码。鉴于我要在文件中存储一个已经加密的密码-解密时我想要正确的文本。 有没有办法告诉javax.crypto方法: 可以将其替换为基于某个私钥生成的我自己的密钥吗? 谁能指出一些有关执行此操作的资

  • 问题内容: 我正在使用JavaScript加密用户密码,如下所示: 它工作正常,但现在我正尝试在服务器端的PHP中像这样解密: 它根本不起作用,解密后的密码字符串看起来很奇怪: 有用的注释后,这是我的JavaScript代码的当前状态: 我正在将saltHex和CipherTextHex发送到PHP服务器,并且正在使用mcrypt_decrypt(),如下所示: 仍然无法使用此更新的代码。 有人可

  • 前面小节介绍了如何存储密码,但是有的时候,我们想把一些敏感数据加密后存储起来,在将来的某个时候,随需将它们解密出来,此时我们应该在选用对称加密算法来满足我们的需求。 base64加解密 如果Web应用足够简单,数据的安全性没有那么严格的要求,那么可以采用一种比较简单的加解密方法是base64,这种方式实现起来比较简单,Go语言的base64包已经很好的支持了这个,请看下面的例子: package

  • 问题内容: 我想用Java加密和解密密码,然后以加密形式存储到数据库中。如果它是开源的,那就太好了。有什么建议/建议吗? 问题答案: 编辑 :这个答案是旧的。现在 不建议 使用MD5,因为它很容易被破坏。 我想象中的MD5必须足够好?您可以使用MessageDigest实现它。 这里还列出了其他算法。 如果确实需要,这是它的第三方版本: Fast MD5