OpenSSL AES 加解密 及 aes 加密码后长度 及要注意的问题
openssl
传输层安全性/安全套接层及其加密库
项目地址:https://gitcode.com/gh_mirrors/ope/openssl
免费下载资源
·
Openssl是很常用的第三方库,因为要用全平台的,所以选择了此库,以跨平台方便。 AES是常用对称加密算法,主要是速度快方便。
-
以下是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 个月前
更多推荐
已为社区贡献4条内容
所有评论(0)