C语言 openssl库 AES对称加解密 CBC模式 PKCS7Padding填充 256秘钥 带16偏移 base64编解码_openssl pkcs7padding_一个菜鸡的学习记录的博客-程序员秘密

技术标签: PKCS7Padding  CBC  openssl  AES加密  C语言学习  base64编码  

最近学习对接平台 需要用到 AES BASE64 加密对接接口
非常少的资料
而且满足不了需要或者有bug,譬如无偏移,base解码超位数输出不正常等
最后整理出如标题所示的结果
希望能帮助到有需要的朋友 也给自己往后回顾用

使用前需要安装openssl库

使用方法:
<./aes 数据> <例子:./aes test> <注意:有空格会被当成多个参数>

功能介绍:
1.对数据进行PKCS7Padding填充
2.进行AES CBC 加密 数据块128bit 秘钥32位(256bit)
3.对加密数据进行base4编码

关于openssl:
编译命令:gcc aes.c -o aes -lssl -lcrypto

自行搜索安装openssl库的方法

测试验证网站:
http://tool.chacuo.net/cryptaes
CBC pkcs7padding 128 E10ADC3949BA59ABBE56E056F20F883E E10ADC3949BA59AB base64 utf-8

#include <stdio.h>
#include <string.h>
#include <unistd.h>
 
#include "openssl/pem.h"
#include "openssl/aes.h"
// #include "openssl/bio.h"
// #include "openssl/evp.h"

#define KEY_BLOCK_BIT 33
#define IV_BLOCK_BIT 17
/*
这个是你自己写的一个十六字节的秘钥,aes加密解密都用这同一个
命令:find /usr/include/ -name *.h | xargs grep 'AES_BLOCK_SIZE'
结果:/usr/include/openssl/aes.h:# define AES_BLOCK_SIZE 16
//256下 key为秘钥32 iv为偏移16
*/

unsigned char key[KEY_BLOCK_BIT] = "E10ADC3949BA59ABBE56E056F20F883E"; ///usr/include/openssl/aes.h:# define AES_BLOCK_SIZE 16 
unsigned char iv[IV_BLOCK_BIT] = "E10ADC3949BA59AB";

#define AES_BITS 10240
#define MSG_LEN 10240
 
/**********************************************************
函数名:getlen           
参数:char *str        --字符串地址
返回值:int            --字符串长度
说明:输入字符串地址获取字符串长度
***********************************************************/
int getlen(char *str) {
    int i = 0;
    while (str[i] != '\0') {
        i++;
    }
    return i;
}
/**********************************************************
函数名:PKCS7Padding          
参数:unsigned char *str      --字符串地址
返回值:int                   --正向测试填充后的字符串长度
说明:对初始数据进行PKCS7Padding填充
***********************************************************/
int PKCS7Padding(unsigned char *str)
{
    int remain, i;
    int len=getlen(str);
    remain = 16 - len%16;
    //printf("remain = %d\n",remain);
    for(i=0; i<remain; i++)
    {
        str[len+i] = remain;
        //printf("str[len+i]= %d\n",str[len+i]);
    }
   	str[len+i] = '\0';
    
    return len + remain;
}
/**********************************************************
函数名:DePKCS7Padding         
参数:unsigned char *p    --字符串地址
返回值:int               --反填充个数
说明:对明文进行PKCS7Padding填充反填充(去除后面的填充乱码)
***********************************************************/
int DePKCS7Padding(unsigned char *str)
{
 	 int remain,i;

 	 while (*str != '\0'){str++;}  //定位到\0
 	 str--;
 	 remain = *str;//读取填充的个数
 	 //printf("remain = %d\n",remain); 
 	 //定位到最前面的填充数
 	 for(i=0;i<remain;i++){str--;}
 	 str++;
 	 *str = '\0';//截断
 	 return remain;
}
/**********************************************************
函数名:aes_encrypt
参数:char* str_in     --输入字符串地址
参数:char* out        --输出字符串地址
参数:char* key        --秘钥key 32位
参数:char* iv         --偏移key 16位
返回值:int             --0失败  1成功
说明:输入"明文"字符串地址  输出ase加密后的"密文"的字符串(乱码不可读)到地址 
***********************************************************/
int aes_encrypt(char* str_in, char* str_out,char *key, char *iv)
{
  	//检测是否有 输入 KEY 输入  有其1为NULL则退出
    if (!str_in || !key || !str_out) return 0;
    
    //抽取数据
    char aes_encode_temp[1024]; 
    strcpy(aes_encode_temp,str_in);

    //加密的初始化向量 (偏移量)
    unsigned char iv_temp[IV_BLOCK_BIT];
    strcpy(iv_temp,iv);

    //进行PCK7填充 获取填充后长度
    int len = PKCS7Padding((unsigned char*)aes_encode_temp);
    //printf("PKCS7Padding str : %s\n",aes_encode_temp); //打印填充后的数据
 	
    //通过自己的秘钥获得一个aes秘钥以供下面加密使用
    AES_KEY aes;
	
    if (AES_set_encrypt_key((unsigned char*)key, 256, &aes) < 0)//256表示32位字符秘钥
    {
        return 0;
    }
 
    //加密接口,使用之前获得的aes秘钥
    AES_cbc_encrypt((unsigned char*)aes_encode_temp, (unsigned char*)str_out, len, &aes, iv_temp, AES_ENCRYPT);
    return 1;
}
 
/**********************************************************
函数名:aes_decrypt
参数:char* str_in     --输入字符串地址
参数:char* str_out    --输出字符串地址
参数:char* key        --秘钥key 32位
参数:char* iv         --偏移key 16位
返回值:int             --0失败  1成功
说明:输入"密文"字符串地址  输出ase解密后的"明文"后的字符串(乱码不可读)到地址 
***********************************************************/
int aes_decrypt(char* str_in, char* str_out,char* key,char* iv)
{
    if (!str_in || !key || ! str_out)    return 0; 
 
    //这个也是加密解密同一个确保十六字节里面的内容加密解密一样
    unsigned char iv_temp[IV_BLOCK_BIT];
    strcpy(iv_temp,iv);
   
    //通过自己的秘钥获得一个aes秘钥以供下面解密使用,128表示16字节
    AES_KEY aes; 

    if (AES_set_decrypt_key((unsigned char*)key, 256, &aes) < 0)//成功返回0
    {
        return 0;
    }
    
    char aes_encode_temp[1024]; 
    strcpy(aes_encode_temp,str_in);
  
    int len = getlen(aes_encode_temp);
    
    //这边是解密接口,使用之前获得的aes秘钥
    AES_cbc_encrypt((unsigned char*)aes_encode_temp, (unsigned char*) str_out, len, &aes, iv_temp, AES_DECRYPT);
    DePKCS7Padding(str_out);

    return 1;
}
 
 /**********************************************************
函数名:base64_encode
参数:char* in_str    --输入字符串地址
参数:char* out_str    --输出字符串地址
返回值:int             --0失败  成功返回编号的字节数
说明:对in_str进行base64编码 输出到out_str
***********************************************************/
int base64_encode(char *in_str, char *out_str)
{   
  	int in_len = getlen(in_str);
    BIO *b64 = NULL, *bio = NULL;
    BUF_MEM *bptr = NULL;
    size_t size = 0;
 
    if (in_str == NULL || out_str == NULL)
        return 0;
 
    b64 = BIO_new(BIO_f_base64());
    bio = BIO_new(BIO_s_mem());
    bio = BIO_push(b64, bio);
 
    BIO_write(bio, in_str, in_len);
    BIO_flush(bio);
 
    BIO_get_mem_ptr(bio, &bptr);
    memcpy(out_str, bptr->data, bptr->length);
    out_str[bptr->length] = '\0';
    size = bptr->length;
 
    BIO_free_all(bio);
   
    return size;
}
 /**********************************************************
函数名:base64Decode
参数:char* in_str     --输入字符串地址
参数:char* out_str    --输出字符串地址
返回值:int             --0
说明:对str_in进行base64编码 输出到out_str
***********************************************************/
int base64Decode(char *in_str, char *out_str)
{
    int length =getlen(in_str);

    BIO *b64 = NULL;
    BIO *bmem = NULL;
   /* char *buffer = (char *)malloc(length);
    memset(buffer, 0, length);*/
    b64 = BIO_new(BIO_f_base64());
	/* if (!newLine) {
       BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
    }*/
    bmem = BIO_new_mem_buf(in_str, length);
    bmem = BIO_push(b64, bmem);
    BIO_read(bmem, out_str, length);
    BIO_free_all(bmem);

    //strcpy(out_str,buffer);
    return 0;
}

/**********************************************************
函数名:main
使用方法:
./aes 数据 例子:./aes test
***********************************************************/
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        printf("<./aes 数据> <例子:./aes test> <注意:有空格会被当成多个参数>\n");
        return 0;
    } else
    {
        printf("-------------------------------------------------------\n");
        printf("原始数据:\n%s\n", argv[1]);
        printf("秘钥:\n%s\n",key);
        printf("偏移量:\n%s\n",iv);
    }
 	
 	printf("------------------------正向测试-----------------------------\n");
    //aes加密
    printf("-------------------------------------------------------\n");
    char aes_encode_out[1024];  
    bzero(aes_encode_out, 1024);
    aes_encrypt(argv[1], aes_encode_out,key, iv);
    printf("加密-密文:\n%s\n", aes_encode_out); //打印密文
    printf("-------------------------------------------------------\n");
    //base64加密
    char base64_encode_out[1024] = {0};
    bzero(base64_encode_out, 1024);
    base64_encode(aes_encode_out, base64_encode_out);
    printf("编码-64:\n%s\n", base64_encode_out);
    printf("-------------------------------------------------------\n");

    printf("------------------------逆向测试-----------------------------\n");
    //base64解密
    char base64_decode_out[1024] = {0};
    bzero(base64_decode_out, 1024);
    base64Decode(base64_encode_out, base64_decode_out);


    printf("解码-64:\n%s\n", base64_decode_out);
    printf("-------------------------------------------------------\n");


    //aes解密
    char aes_decode_out[1024] = {0};
    bzero(aes_decode_out, 1024);

    aes_decrypt(base64_decode_out, aes_decode_out,key,iv);

    printf("解密-明文:\n%s\n", aes_decode_out);
    printf("-------------------------------------------------------\n");
    return 0;
}

在这里插入图片描述在这里插入图片描述网站对比通过测试。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_38916259/article/details/101123192

智能推荐

FutureTask学习笔记_0oo踏雪无痕oo0的博客-程序员秘密

目录Future 接口介绍RunnableFutureFutureTask介绍原理代码详情Future 接口介绍Future 表示一个异步计算,提供了用于检查异步计算是否完成,等待异步计算结果,取消异步计算任务等方法。等待获取异步计算结果会阻塞当前线程,直到超时或者获取到异步计算的结果。如果异步计算已经完成,取消计算任务的方法将不会生效。如果希望利用 Futur...

Angular 5 子组件与父组件实现数据双向绑定_WXF_Angular的博客-程序员秘密

1. 实现父组件和子组件间 数据的双向绑定2. 描述:子组件和父组件间,各有一个&amp;lt;input&amp;gt;标签,在父组件input 内容,子组件的input 标签上同步 ,在子组件的input 上输入内容,父组件input 标签页同步3. 具体实现:    在父组件html中写如下代码子组件input标签&amp;lt;home-input #homeinput&amp;gt;&amp;lt;/home-input&amp;gt...

从0开始搭建自己的个人博客hexo(一)_从0开始单间hexo博客_fmk1023的博客-程序员秘密

从0开始搭建自己的个人博客hexo手把手教你从0开始搭建自己的个人博客 |无坑版视频教程| hexo本篇所包含的内容如下:安装NodeJs安装 Git安装hexo运行测试1.安装NodeJs Hexo是基于nodeJS环境的静态博客。作为服务端运行javascript的平台的NodeJs,把前台javascript移到了服务器端,Google V8引擎使其运行效率非常...

我才接触到的深度学习的一系列不那么相关的概念weight decay ,crop等等概念_qq_27292549的博客-程序员秘密

一、weight decay(权值衰减)的使用既不是为了提高你所说的收敛精确度也不是为了提高收敛速度,其最终目的是防止过拟合。在损失函数中,weight decay是放在正则项(regularization)前面的一个系数,正则项一般指示模型的复杂度,所以weight decay的作用是调节模型复杂度对损失函数的影响,若weight decay很大,则复杂的模型损失函数的值也就大。二、

第3章 基本概念(2)数据类型:typeof操作符 Undefined类型 Null类型 Boolean类型_ZHOU_VIP的博客-程序员秘密

4. 数据类型ECMAScript 中有5 种简单数据类型(也称为基本数据类型):Undefined、Null、Boolean、Number和String。还有1 种复杂数据类型——Object,Object 本质上是由一组无序的名值对组成的。4.1 typeof操作符:检测给定变量的数据类型对一个值使用typeof 操作符可能返回下列某个字符串:"undefi

log4j.xml配置_谋问题的博客-程序员秘密

配置一、 [xhtml] view plain copyxml version="1.0" encoding="UTF-8" ?>     >          log4j:configuration>           appender name="CONSOLE" class="org.apache.log4

随便推点

RecyclerView的滚动事件OnScrollListener_daimengs的博客-程序员秘密

RecyclerView的滚动事件OnScrollListener(1)滚动事件分类列表的滚动一般分为两种: 1.手指按下 -&amp;gt; 手指拖拽列表移动 -&amp;gt; 手指停止拖拽 -&amp;gt; 抬起手指 2.手指按下 -&amp;gt; 手指快速拖拽后抬起手指 -&amp;gt; 列表继续滚动 -&amp;gt; 停止滚动上面的过程的状态变化如下:1.静止 -&amp;gt; 被迫拖拽移动 -&amp;gt; 静止2.静止 -&amp;gt;...

解决QT+VS中无法打开ui_xxx.h文件_无法打开ui_widget.h_/哈哈的博客-程序员秘密

在VS中添加插件Qt VS Tools,就可以在VS中写QT项目了,但是VS中写QT项目和在QT Creater中并不完全一样,VS中的项目文件结构是:但是如图中的widget.h文件中包含了ui_widget.h文件,但提示无法打开ui_widget.h文件,双击ui_widget.h也无法打开此文件。解决办法如图依次点击,然后等待几秒就可以打开该文件。选中ui_widget.h文件...

HttpOnly作用_Better-衡的博客-程序员秘密

防止通过脚本读取setCookie中的内容,进而防止XXS攻击

codeforces 629D-Babaei and Birthday Cake(dp && 线段树或树状数组离散优化)_babaei and birthday cake 树状数组_JW_7066的博客-程序员秘密

题目链接:【codeforces 629D】  HDU1087的升级版有n个圆柱形的蛋糕,已知每个蛋糕的半径r和高h,将这n个蛋糕叠起来,第i个蛋糕能放在第j个蛋糕的上面(1第j个蛋糕的体积,问最终叠成的蛋糕的最大体积dp[i] = max(dp[j], 1用线段树记录第i个蛋糕之前满足条件的的最大dp值将从小到大排序后的体积的序号作为线段树的下标,没访问一次vol[i],就把

出生时辰转天干地支 c语言算法,生辰八字天干地支转换_weixin_39918928的博客-程序员秘密

我们当前通用的公元年,也叫做西历年、纪年,源自西方社会的纪年法,是从耶稣诞生的那一年开始计算。是从辛亥后,也就是年开始采用公元纪年法,在这之前,我们采用的都是干支年法。干支,也就是天干和地支,传说出自于黄帝时代,实际是萌芽于西汉初,始行于王莽,通行于东汉以后。有人认为在汉武帝以前用干支纪年。天干地支纪年法是我国的古老传统文化之一,并由此催生了众多的灿烂中华文明。天干,也就是十天干,即:甲、乙、丙、...

Zookeeper基础知识和Linux环境下搭建_txxs的博客-程序员秘密

最近要实现一个基于zookeeper的分布式锁,但是一些知识一无所知,找了一些,汇总在这里,下边的大部分来自这个博客一、ZooKeeper的背景1.1 认识ZooKeeperZooKeeper---译名为“动物园管理员”。动物园里当然有好多的动物,游客可以根据动物园提供的向导图到不同的场馆观赏各种类型的动物,而不是像走在原始丛林里,心惊胆颤的被动 物所观赏。为了让各种不