loadrunner提交http中的密文AES数据和脚本中的参数不一致,该怎么解决??

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了loadrunner提交http中的密文AES数据和脚本中的参数不一致,该怎么解决??相关的知识,希望对你有一定的参考价值。

用loadrunner的函数web_submit_data测试一个接口,用户、密码是AES密文,参数如下:
ITEMDATA,
"Name=userID", "Value=hdT09fbu8yMa%2B%2FNQ4b3fPg==", ENDITEM,
"Name=passWord", "Value=25FkDkh6MTRsF9OT11OtSw==", ENDITEM,
LAST);
用户密码正确,返回结果失败,查看HTTPS流发现userID的值发生变化
Connection: Keep-Alive
Host: ip:8080
Content-Length: 164
userID=hdT09fbu8yMa%252B%252FNQ4b3fPg%3D%3D&passWord=25FkDkh6MTRsF9OT11OtSw%3D%3D
脚本中的值:hdT09fbu8yMa%2B%2FNQ4b3fPg
HTTPS的值:hdT09fbu8yMa%252B%252FNQ4b3fPg

我认为是是脚本提交的时候转码的问题,请教高手怎么解决此问题,万分感谢!!!

这个属于urlEncoding字符串编码问题,使用了两次urlEncoding当然会不对啦。
在客户端和服务器端的协议要一致,是否都强制使用了urlEncoding,相同次数的urlEncoding。要保证传输的字符集在http协议传输字符集以内;否则,就要进行url encoding进行转义,转义的次数客户端和服务器端要相同。
在传输的过程中,使用encodeURIComponent,可以将一些字符转换为适宜http传输的字符,例如'='会被转换为'%3d'或者'%3D',即字符转义。服务器会将'%3D'解释为一个'='。
AES密文是BASE64编码,其字符集是A-Z|a-z|0-9|+,/,其中'+'和'/'可以转义为'%2B'以和'%2F','='是AES加密用来补足尾数的数位的,会被转义为'%3D'。因此对AES进行一次urlEncoding即可,服务器收到后解析使用url decoding一次,即可将密文进行AES解密。

如果对AES密文进行了两次urlEncoding,那么'%2B', '%2F', '%3D'中的'%'会被转义为'%25', 这样原本为'%2B'的字符串就会转换为'%252B', 如何服务器只进行了一次urldecoding,直接拿去AES解密,当然会报错。
参考技术A 系统里修改密码为已知值 比如111111或者123456
然后看数据库 保存密码的字段 看看加密之后是什么东西 复制出来
然后去改脚本 直接提交加密之后的东西

OpenSSL AES 256 CBC 通过 C 中的 EVP api

【中文标题】OpenSSL AES 256 CBC 通过 C 中的 EVP api【英文标题】:OpenSSL AES 256 CBC via EVP api in C 【发布时间】:2014-09-11 10:32:33 【问题描述】:

我想要做什么: 用 C 语言编写一个程序,打开一个任意大小的文件并读取其内容。读取内容后,它将在 AES 256 CBC 中对其进行加密,并将密文保存到名为 ciphertext 的文件中。保存后,它将关闭这两个文件。然后将从刚刚保存的文件中打开密文并解密密文并将其保存到一个名为decrypted的文件中。

我的问题: 它似乎永远不会解密我的密文。我得到垃圾,我不知道我做错了什么。请帮忙。

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/evp.h>
#include <openssl/aes.h>

void encrypt(FILE *ifp, FILE *ofp)

  //Get file size
  fseek(ifp, 0L, SEEK_END);
  int fsize = ftell(ifp);
  //set back to normal
  fseek(ifp, 0L, SEEK_SET);

  int outLen1 = 0; int outLen2 = 0;
  unsigned char *indata = malloc(fsize);
  unsigned char *outdata = malloc(fsize*2);
  unsigned char ckey[] =  "thiskeyisverybad";
  unsigned char ivec[] = "dontusethisinput";

  //Read File
  fread(indata,sizeof(char),fsize, ifp);//Read Entire File

  //Set up encryption
  EVP_CIPHER_CTX ctx;
  EVP_EncryptInit(&ctx,EVP_aes_256_cbc(),ckey,ivec);
  EVP_EncryptUpdate(&ctx,outdata,&outLen1,indata,fsize);
  EVP_EncryptFinal(&ctx,outdata,&outLen2);
  fwrite(outdata,sizeof(char),fsize,ofp);


void decrypt(FILE *ifp, FILE *ofp)

  //Get file size
  fseek(ifp, 0L, SEEK_END);
  int fsize = ftell(ifp);
  //set back to normal
  fseek(ifp, 0L, SEEK_SET);

  int outLen1 = 0; int outLen2 = 0;
  unsigned char *indata = malloc(fsize);
  unsigned char *outdata = malloc(fsize*2);
  unsigned char ckey[] =  "thiskeyisverybad";
  unsigned char ivec[] = "dontusethisinput";

  //Read File
  fread(indata,sizeof(char),fsize, ifp);//Read Entire File

  //setup decryption
  EVP_CIPHER_CTX ctx;
  EVP_DecryptInit(&ctx,EVP_aes_256_cbc(),ckey,ivec);
  EVP_DecryptUpdate(&ctx,outdata,&outLen1,indata,fsize);
  EVP_DecryptFinal(&ctx,outdata,&outLen2);
  fwrite(outdata,sizeof(char),fsize,ofp);


int main(int argc, char *argv[])
    
  FILE *fIN, *fOUT;

  fIN = fopen("plain.txt", "rb");//File to be encrypted; plain text
  fOUT = fopen("cyphertext.txt", "wb");//File to be written; cipher text    
  encrypt(fIN, fOUT);

  fclose(fIN);
  fclose(fOUT);

  //Decrypt file now
  fIN = fopen("cyphertext.txt", "rb");//File to be written; cipher text
  fOUT = fopen("decrypted.txt", "wb");//File to be written; cipher text
  decrypt(fIN,fOUT);

  fclose(fIN);
  fclose(fOUT);

  return 0;

注意:可能有一些拼写错误。 编辑:似乎我在密钥和 IV 上犯了一个错误,它们都是 128 位的,我正在尝试使用 256 位的 CBC。这是我的问题,一旦我将其更改为

EVP_aes_128_cbc()

【问题讨论】:

您假设输出文件的长度与输入的长度相同是错误的。另外,您确定您的 C 编译器支持动态数组吗?通常你必须malloc indata 和 outdata。 好的,所以如果我说输出文件至少是输入大小的 2 倍,我会安全吗?或者,还有更好的方法?同样在动态数组方面,我不确定我的编译器是否这样做(代码块默认,应该是 GCC)。不管我做了 malloc(fsize) 和 malloc(fsize*2)。它仍然给我垃圾数据。 您的 EVP_*Update() 方法正在覆盖 outdata 数组的开头。你需要像EVP_EncryptFinal(&amp;ctx,outdata + outLen1,&amp;outLen2); 这样的东西。解密也是一样。 不完全确定它是如何工作的,不是第二个参数 unsigned char * 并且如果我添加一个 int 如何防止方法被覆盖? 感谢 GregS 得到了我的答复。虽然我仍然不确定为什么这个技巧有效,但确实有效。 【参考方案1】:

这是我的代码版本。当然,我更喜欢它,但我提供它只是作为替代品。请注意完全没有错误检查:真正的代码会有它。

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/evp.h>
#include <openssl/aes.h>

#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif


/**
 * Encrypt or decrypt, depending on flag 'should_encrypt'
 */
void en_de_crypt(int should_encrypt, FILE *ifp, FILE *ofp, unsigned char *ckey, unsigned char *ivec) 

    const unsigned BUFSIZE=4096;
    unsigned char *read_buf = malloc(BUFSIZE);
    unsigned char *cipher_buf;
    unsigned blocksize;
    int out_len;
    EVP_CIPHER_CTX ctx;

    EVP_CipherInit(&ctx, EVP_aes_256_cbc(), ckey, ivec, should_encrypt);
    blocksize = EVP_CIPHER_CTX_block_size(&ctx);
    cipher_buf = malloc(BUFSIZE + blocksize);

    while (1) 

        // Read in data in blocks until EOF. Update the ciphering with each read.

        int numRead = fread(read_buf, sizeof(unsigned char), BUFSIZE, ifp);
        EVP_CipherUpdate(&ctx, cipher_buf, &out_len, read_buf, numRead);
        fwrite(cipher_buf, sizeof(unsigned char), out_len, ofp);
        if (numRead < BUFSIZE)  // EOF
            break;
        
    

    // Now cipher the final block and write it out.

    EVP_CipherFinal(&ctx, cipher_buf, &out_len);
    fwrite(cipher_buf, sizeof(unsigned char), out_len, ofp);

    // Free memory

    free(cipher_buf);
    free(read_buf);


int main(int argc, char *argv[]) 

    unsigned char ckey[] = "thiskeyisverybad";
    unsigned char ivec[] = "dontusethisinput";
    FILE *fIN, *fOUT;

    if (argc != 2) 
        printf("Usage: <executable> /path/to/file/exe");
        return -1;
    

    // First encrypt the file

    fIN = fopen("plain.txt", "rb"); //File to be encrypted; plain text
    fOUT = fopen("cyphertext.txt", "wb"); //File to be written; cipher text

    en_de_crypt(TRUE, fIN, fOUT, ckey, ivec);

    fclose(fIN);
    fclose(fOUT);

    //Decrypt file now

    fIN = fopen("cyphertext.txt", "rb"); //File to be read; cipher text
    fOUT = fopen("decrypted.txt", "wb"); //File to be written; cipher text

    en_de_crypt(FALSE, fIN, fOUT, ckey, ivec);

    fclose(fIN);
    fclose(fOUT);

    return 0;

【讨论】:

为什么要分块读取文件?如果我们读取文件并将其存储到缓冲区中,然后加密它会怎样。这不会给我们不需要的数据。 IE 如果我们试图加密一个可执行文件,读取那些额外的字节会导致解密后执行所述程序出现问题吗? 我不明白你的问题。我在读什么“额外字节”? fread 读取的字节数永远不会超过文件中剩余的字节数。 这是真的,但我关心的是缓冲区中剩余的字节。假设在最后一次读取时,fread 读取 4000 个字节(因为要读取的字节数不超过 4000 个)并将其存储到缓冲区“read_buf”中。我们现在应该有 4000 字节从上次读取中读取,还有 96 字节未使用的分配空间。我们将读取和未使用空间中的整个数据缓冲区传递到 EVP_CipherUpdate 从而加密未使用空间。这会在解密时引起问题吗? @Kevin: 不,这不是问题,因为fread 读取的实际字节数被返回并保存在变量numRead 中,然后这个变量作为最后一个参数提供EVP_CipherUpdate(...)。所以 EVP_CipherUpdate(...) 不会触及 read_buf 中未使用的空间。 完美解释!我明白为什么要这样做了。欣赏它。【参考方案2】:

此代码有效,如果有人对它如何更清洁或更高效有一些建议,请发表评论。

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/evp.h>
#include <openssl/aes.h>

void encrypt(FILE *ifp, FILE *ofp)

    //Get file size
    fseek(ifp, 0L, SEEK_END);
    int fsize = ftell(ifp);
    //set back to normal
    fseek(ifp, 0L, SEEK_SET);

    int outLen1 = 0; int outLen2 = 0;
    unsigned char *indata = malloc(fsize);
    unsigned char *outdata = malloc(fsize*2);
    unsigned char ckey[] =  "thiskeyisverybad";
    unsigned char ivec[] = "dontusethisinput";

    //Read File
    fread(indata,sizeof(char),fsize, ifp);//Read Entire File

    //Set up encryption
    EVP_CIPHER_CTX ctx;
    EVP_EncryptInit(&ctx,EVP_aes_128_cbc(),ckey,ivec);
    EVP_EncryptUpdate(&ctx,outdata,&outLen1,indata,fsize);
    EVP_EncryptFinal(&ctx,outdata + outLen1,&outLen2);
    fwrite(outdata,sizeof(char),outLen1 + outLen2,ofp);


void decrypt(FILE *ifp, FILE *ofp)

    //Get file size
    fseek(ifp, 0L, SEEK_END);
    int fsize = ftell(ifp);
    //set back to normal
    fseek(ifp, 0L, SEEK_SET);

    int outLen1 = 0; int outLen2 = 0;
    unsigned char *indata = malloc(fsize);
    unsigned char *outdata = malloc(fsize);
    unsigned char ckey[] =  "thiskeyisverybad";
    unsigned char ivec[] = "dontusethisinput";

    //Read File
    fread(indata,sizeof(char),fsize, ifp);//Read Entire File

    //setup decryption
    EVP_CIPHER_CTX ctx;
    EVP_DecryptInit(&ctx,EVP_aes_128_cbc(),ckey,ivec);
    EVP_DecryptUpdate(&ctx,outdata,&outLen1,indata,fsize);
    EVP_DecryptFinal(&ctx,outdata + outLen1,&outLen2);
    fwrite(outdata,sizeof(char),outLen1 + outLen2,ofp);


int main(int argc, char *argv[])
        
    if(argc != 2)
        printf("Usage: <executable> /path/to/file/exe");
        return -1;
    
    FILE *fIN, *fOUT;
    fIN = fopen("plain.txt", "rb");//File to be encrypted; plain text
    fOUT = fopen("cyphertext.txt", "wb");//File to be written; cipher text

    encrypt(fIN, fOUT);
    fclose(fIN);
    fclose(fOUT);
    //Decrypt file now
    fIN = fopen("cyphertext.txt", "rb");//File to be written; cipher text
    fOUT = fopen("decrypted.txt", "wb");//File to be written; cipher text
    decrypt(fIN,fOUT);
    fclose(fIN);
    fclose(fOUT);

    return 0;

此外,根据这篇文章,EVP api 将处理任意大小的输入

AES Encryption- large files

【讨论】:

感谢您的反馈。请注意,加密操作*outdata 的输出缓冲区相当大。通常你只需要允许填充发生,这意味着输出缓冲区大小为fsize + EVP_CIPHER_block_size(ctx)(实际上可能仍然有点过大,但我想你可以多留出大约 15 个字节)。

以上是关于loadrunner提交http中的密文AES数据和脚本中的参数不一致,该怎么解决??的主要内容,如果未能解决你的问题,请参考以下文章

AES中输入和密文长度之间的关系

JS和利用openssl的object C加密得到相同的aes加密密文

AES加密算法原理

java AES加密

AES 填充并将密文写入磁盘文件

为啥带有 GCM 的 AES-256 会在密文大小上增加 16 个字节?