OpenSSL AES 加解密 及 aes 加密码后长度 及要注意的问题

      Openssl是很常用的第三方库,因为要用全平台的,所以选择了此库,以跨平台方便。 AES是常用对称加密算法,主要是速度快方便。

  1. 以下是openssl进行AES,CBC 加密和解密的示例:

int aes_encrypt(const unsigned char* in, const unsigned char* key, const unsigned char* out, int inLen)
{
    if (!in || !key || !out) return 0;
    unsigned char iv[AES_BLOCK_SIZE];//加密的初始化向量
    for (int i = 0; i<AES_BLOCK_SIZE; ++i)//iv一般设置为全0,可以设置其他,但是加密解密要一样就行
        iv[i] = 0;
    AES_KEY aes;
    if (AES_set_encrypt_key((unsigned char*)key, 128, &aes) < 0)
    {
        return 0;
    }
    int len = inLen;//这里的长度是char*in的长度,但是如果in中间包含'\0'字符的话

    //那么就只会加密前面'\0'前面的一段,所以,这个len可以作为参数传进来,记录in的长度

    //至于解密也是一个道理,光以'\0'来判断字符串长度,确有不妥,后面都是一个道理。
    AES_cbc_encrypt((unsigned char*)in, (unsigned char*)out, len, &aes, iv, AES_ENCRYPT);
    return 1;
}
 int aes_decrypt(const unsigned char* in, const unsigned char* key, const unsigned char* out, int inLen)
{
    if (!in || !key || !out) return 0;
    unsigned char iv[AES_BLOCK_SIZE];//加密的初始化向量
    for (int i = 0; i<AES_BLOCK_SIZE; ++i)//iv一般设置为全0,可以设置其他,但是加密解密要一样就行
        iv[i] = 0;
    AES_KEY aes;
    if (AES_set_decrypt_key((unsigned char*)key, 128, &aes) < 0)
    {
        return 0;
    }
    int len =inLen;
    AES_cbc_encrypt((unsigned char*)in, (unsigned char*)out, len, &aes, iv, AES_DECRYPT);
    return 1;
}

注意:传入数据长度必须是 16的倍数,否则会有异常,aes加密,解密,输入和输出长度是相同的。输出虽然没有给长度。

2.相关,如果做aes加密为一般是字节流,需要保存时字符串,一般是BASE64编码,或转成 bytes字符串;

BASE64编码示例:

string Base64Encode(const char * input, int length, bool with_new_line)
{
	BIO * bmem = NULL;
	BIO * b64 = NULL;
	BUF_MEM * bptr = NULL;

	b64 = BIO_new(BIO_f_base64());
	if (!with_new_line) {
		BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
	}
	bmem = BIO_new(BIO_s_mem());
	b64 = BIO_push(b64, bmem);
	BIO_write(b64, input, length);
	BIO_flush(b64);
	BIO_get_mem_ptr(b64, &bptr);

	//这里的第二个参数很重要,必须赋值
	std::string result(bptr->data, bptr->length);
	BIO_free_all(b64);
	return result;
}

string Base64Decode(const char * input, int length, bool with_new_line)
{
	BIO * b64 = NULL;
	BIO * bmem = NULL;
	unsigned char * buffer = (unsigned char *)malloc(length);
	memset(buffer, 0, length);

	b64 = BIO_new(BIO_f_base64());
	if (!with_new_line) {
		BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
	}
	bmem = BIO_new_mem_buf(input, length);
	bmem = BIO_push(b64, bmem);
	int ret = BIO_read(bmem, buffer, length);
	//这里的第二个参数很重要,必须赋值
	std::string result((char*)buffer, ret);

	BIO_free_all(bmem);

	return result;
}

字节流转化为十六进制字符串:

/*   Byte值转换为bytes字符串
*   @param src:Byte指针 srcLen:src长度 des:转换得到的bytes字符串
**/
 void Bytes2HexStr( unsigned char *src,int srcLen, unsigned char *des)
{
    unsigned char *res;
    int i=0;

    res = des;
    while(srcLen>0)
    {
        sprintf((char*)(res+i*2),"%02x",*(src+i));
        i++;
        srcLen--;
    }
}

/**
 * bytes字符串转换为Byte值
* @param String src Byte字符串,每个Byte之间没有分隔符
* @return byte[]
*/
 unsigned char * hexStr2Bytes(string src)
{
    char *strEnd;
    int m=0;
    int len = src.length()/2;
    unsigned char* ret = new unsigned char[len];

    for(int i =0;i<len;i++)
    {
        m = i*2;
        string subs = src.substr(m,2);
        ret[i] = strtol(subs.c_str(),&strEnd,16);
    }
    return ret;
}

一般作为本地客户端简单加密:

int main()
{
    string keyTemp= "cmV0U3VjYyA9IGJhc2U2NF9kZWNvZGUoYmFzZTY0U3RyLmNfc3RyKCksYmFzZTY0U3RyLmxlbmd0aCgpLERlY29kZVN0cmluZ1RlbXAsJmRlY29kZWxlbik=LERlY29kZVN0cmluZ1RlbXAsJmRlY29kZWxlbik=";
    int keylen = keyTemp.length();
    unsigned char sourceStringTemp[MSG_LEN]={0};
    unsigned char dstStringTemp[MSG_LEN]={0};
    unsigned char paint[MSG_LEN]={0};
   
    memcpy( sourceStringTemp, keyTemp.c_str(),keylen);
    memcpy( paint, keyTemp.c_str(),keylen);
 

    char key[AES_BLOCK_SIZE+1]={0};
    int i;
     for (i = 0; i < 16; i++)//可自由设置密钥
     {
         key[i] = 32 + i;
     }
    time_t now;
    time(&now);
   
    printf( "aes_encrypt starttime: %ld  ",now);
    if (!aes_encrypt(sourceStringTemp, (const unsigned char*)key, dstStringTemp,keylen))
    {
        printf("encrypt error\n");
        return -1;
    }

    time_t end;
    time(&end);
    LOGD("aes_encrypt endtime: %ld  ",end);

    unsigned char deshx[MSG_LEN]={0};
    Bytes2HexStr(dstStringTemp,keylen,deshx);
   // string* hexStr = Byte2Hex(dstStringTemp,keylen);

    string result((char*)deshx);
    LOGD(" Encode Byte2Hex: %s  ",result.c_str());
 
    unsigned char * dehex = hexStr2Bytes(result);
 
//    string base64Str = Base64Encode((const char*)dstStringTemp,keylen,false);
//
//    LOGD(" Encode base64Str: %s  ",base64Str.c_str());
//    string baseEncodeStr = base64Str;
//    unsigned char DecodeStringTemp[MSG_LEN]={0};
//    int decodelen  = 1024;
//    int retSucc = base64_decode(base64Str.c_str(),base64Str.length(),DecodeStringTemp,&decodelen);
 

    printf("enc %d:", strlen((char*)dstStringTemp));
 
    memset((char*)sourceStringTemp, 0, MSG_LEN);
    if (!aes_decrypt((const unsigned char*)dehex, (const unsigned char*)key, sourceStringTemp,keylen))
    {
        LOGD("decrypt error\n");
        return -1;
    }
    printf("\n");
    int len = strlen((char*)sourceStringTemp);
 

    char des[MSG_LEN] ={0};
    char soure[MSG_LEN] ={0};
    memcpy(soure,sourceStringTemp,380);
    memset(dstStringTemp,0,MSG_LEN);

    /*对比解密后与原数据是否一致*/
    if(!memcmp(paint, sourceStringTemp, keylen)) {
        LOGD("test success\n");
    } else {
        LOGD("test failed\n");
    }
 
    return 0;
}

 

关于输出数据的长度
AES_cbc_encrypt 这个方法并没有返回加密后长度,根据源码可知:输出数据缓冲区的长度必须是16字节的倍数,加密完成后,比输入长度多出来的输出数据是不可以丢弃的。

如果直接用 strlen 取会有错误,所以可以用 :如果原长度 int len =3333;

新的长度

int nlen = len + 16 - len%16;

其实就是如果不是 16倍数,要补全最后的16;

注意:如果输入非 16倍数 windows 32,64 平台 会得出不同的结果,建议输入如果不是 16倍数,自己补全;

例:

	char sid[128]="addfdfdafddfadfdsafadf";
        int slen = strlen(sid);
	#if defined(WIN32) || defined(_WIN32) || defined(WINDOWS)
	// 变成 16 倍数。否则windows aes 加密后,32,64 值不同;
	int mlen = slen % 16;
	if (0 != mlen)
	{
		strncat((char*)sid, "0000000000000000", 16 - mlen);
	}
         slen = strlen(sid);

 

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: OpenSSL是一个开源的密库,支持多种密算法,其中包括AES CBC模式加解密AES CBC模式是一种对称密算法,它将明文分成固定长度的块,每个块都使用相同的密钥进行密,同时使用前一个块的密文作为下一个块的输入,以此来增密的安全性。 在OpenSSL中,可以使用以下函数进行AES CBC模式加解密: 1. EVP_CIPHER_CTX_init():初始化密上下文结构体。 2. EVP_EncryptInit_ex():初始化密算法,设置密钥和IV(初始化向量)。 3. EVP_EncryptUpdate():密数据。 4. EVP_EncryptFinal_ex():完成密操作。 5. EVP_DecryptInit_ex():初始化解密算法,设置密钥和IV。 6. EVP_DecryptUpdate():解密数据。 7. EVP_DecryptFinal_ex():完成解密操作。 使用这些函数可以轻松实现AES CBC模式加解密操作。 ### 回答2: OpenSSL是功能强大而广泛使用的密库,支持很多对称密算法,其中包括AES (Advanced Encryption Standard)算法,而CBC (Cipher Block Chaining)模式是一种常用的密模式。 CBC模式是一种分组密码模式,对明文进行分组后,每个分组通过密算法与前一个分组的密文异或运算得到密文,以此实现密。CBC模式的安全性来源于密文与前一个密文有关,因此需要一个随机的初始化向量(IV)来使第一个明文分组与IV异或运算得到第一个密文分组。 在OpenSSL libcrypto库中,通过调用EVP_aes_256_cbc、EVP_EncryptInit_ex、EVP_EncryptUpdate、EVP_EncryptFinal_ex来进行AES 256位密,调用EVP_DecryptInit_ex、EVP_DecryptUpdate、EVP_DecryptFinal_ex来进行解密。其中,EVP_EncryptInit_ex和EVP_DecryptInit_ex需要设置密算法、key、IV。EVP_EncryptUpdate和EVP_DecryptUpdate用于密或解密数据,EVP_EncryptFinal_ex和EVP_DecryptFinal_ex用于确定最后一个分组的密文或者最后一个分组的解密结果。 在CBC模式中,由于每个分组的密需要使用前一个密文,因此需要对首个分组进行处理。通常的处理方式是在首个明文分组与IV异或运算得到首个密文分组。CBC模式的安全性依赖于IV的随机性,如果使用相同的IV多次使用相同的密钥进行密,则会产生接近明文的密文,因此密时应该每次使用不同的IV。 在实际的使用中,我们可以使用OpenSSL的命令行工具进行加解密操作,如"openssl enc -aes-256-cbc -in plaintext.txt -out ciphertext.bin"即使用AES 256位CBC模式密plaintext.txt,并将密结果保存到ciphertext.bin中。同样地,使用命令"openssl enc -d -aes-256-cbc -in ciphertext.bin -out plaintext.txt",可以对密文进行解密。这些命令使用了默认的IV,实际使用中应该通过代码生成一个随机的IV,每次密时都使用不同的随机IV。 ### 回答3: OpenSSL AES CBC模式加解密是一种对称密的方法,适用于保证数据传输的机密性和完整性的场合。AES(Advanced Encryption Standard)是一种对称密算法,CBC(Cipher Block Chaining)模式是其一种密模式,使用到了密钥和IV(Initialization Vector)。 其中,CBC模式的工作方式是将明文分块进行密,每个密文块与上一个密文块的密文块进行异或运算,然后再密密钥进行密。IV是一种随机数,用于增安全性。CBC模式的解密过程是将密文块逆向解密,再与上一个密文块进行异或运算,最后再进行解密。 使用OpenSSL AES CBC模式密时,需要指定密密钥key和IV。可以使用openssl命令进行加解密操作,也可以使用编程语言库进行操作。使用OpenSSL进行密的命令为: openssl enc -aes-256-cbc -in plaintext.txt -out ciphertext.bin -K xxxxxxxxxxxxxxxxxxxxxx -iv xxxxxxxxxxxxxxxxxxxxxx 其中,-in参数指定要密的明文文件,-out参数指定要输出的密文文件,-K参数指定密密钥,-iv参数指定IV值。 使用OpenSSL进行解密的命令为: openssl enc -d -aes-256-cbc -in ciphertext.bin -out plaintext.txt -K xxxxxxxxxxxxxxxxxxxxxx -iv xxxxxxxxxxxxxxxxxxxxxx 其中,-d参数表示进行解密操作,其他参数与密时相同。 总的来说,OpenSSL AES CBC模式加解密是一种非常实用的对称密方式,可以用于保证数据传输的安全和机密性,通过设置密密钥和IV,可以有效地增数据的安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

恋恋西风

up up up

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值