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);

 

GitHub 加速计划 / ope / openssl
25.13 K
9.99 K
下载
传输层安全性/安全套接层及其加密库
最近提交(Master分支:1 个月前 )
fd39d1c8 Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Shane Lontis <shane.lontis@oracle.com> (Merged from https://github.com/openssl/openssl/pull/25095) 3 个月前
ae87c488 Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Shane Lontis <shane.lontis@oracle.com> (Merged from https://github.com/openssl/openssl/pull/25095) 3 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐