base64编解码(openssl和c语言2种实现方式)

1.base16引申

#include <iostream>
typedef unsigned char  uchar;
//用表来映射的话可以达到O1的复杂度
static const char base16EncodeTable[] = "0123456789ABCDEF";
//'0'-'9' == 48 - 57    'A' - 'F' == 65 -70  
static const char base16DecTable[] =
{
	-1,//0
	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  //1-10
	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  //11-20
	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  //21-30
	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  //31-40
	-1,-1,-1,-1,-1,-1,-1, 0, 1, 2,  //41-50
	 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,  //51-60
	-1,-1,-1,-1,10,11,12,13,14,15,  //61-70
};
int base16_encode(const uchar* in, int size, uchar* out)
{
	for (int i = 0; i < size; ++i)
	{
		char h = in[i] >> 4;  //拿到高位
		char l = in[i] & 0x0F;//拿到低位

	/*此时得到的h 和 l只是ascii表中的0~15的值,
	需要经过base16EncodeTable表映射为可以打印的字符*/
		out[i * 2] = base16EncodeTable[h];
		out[i * 2 + 1] = base16EncodeTable[l];
	}
	return size * 2; //转码后空间扩大一倍,4位转成一个字符即,一个字节转成2个字节
}

int base16_decode(const uchar* in, int size, uchar* out)
{
	for (int i = 0; i < size; i += 2)
	{
		uchar ch = in[i];//拿到高位型字符
		uchar cl = in[i + 1]; //拿到低位型字符
		uchar h = base16DecTable[ch];
		uchar l = base16DecTable[cl];
		out[i / 2] = h << 4 | l;
	}
	return size / 2;
}


int main()
{
	std::cout << "base 16" << std::endl;
	const uchar data[] = "测试base16";
	int len = sizeof(data);
	uchar out[1024] = { 0 };
	int ret = base16_encode(data, len, out);
	std::cout << "encode ret = " << ret << " data = " << out << std::endl;

	memset((char*)data, 0, sizeof(data));

	ret = base16_decode(out, ret, (uchar*)data);

	std::cout << "decode ret = " << ret << " data = " << data << std::endl;

	return 0;
}

2.base64

需注意 openssl的base64会默认加换行,我们需要手动调用API将其去掉,带_c的即为手动实现的c语言base64编解码

代码实现(看详细注释即可)

#include <iostream>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/buffer.h>


//typedef struct bio_st BIO;
//
//struct bio_st
//{
//	BIO_METHOD* method;    //BIO方法结构,是决定BIO类型和行为的重要参数,各种BIO的不同之处主要也正在于此项。
//
//	long (*callback)(struct bio_st*, int, const char*, int, long, long);     //BIO回调函数
//	char* cb_arg;                                                          //回调函数的第一个参量
//
//	int init;           //初始化标志,初始化了为1,否则为0。比如文件BIO 中,通过BIO_set_fp
//						//关联一个文件指针时,该标记则置1。
//	int shutdown;       //BIO开关标志,如果为BIO_CLOSE,则释放BIO时自动释放持有的资源,否则不自动释放持有资源
//	int flags;          //有些BIO 实现需要它来控制各个函数的行为。比如文件BIO 默认该值为BIO_FLAGS_UPLINK,
//						//这时文件读操作调用UP_fread 函数而不是调用fread 函数。
//	int retry_reason;  //重试原因,主要用在socket 和ssl BIO 的异步阻塞。比如socketbio 中,遇到 
//					   //WSAEWOULDBLOCK 错误时,openssl 告诉用户的操作需要重试
//	int num;           //该值因具体BIO 而异,比如socket BIO 中num 用来存放链接字。
//	void* ptr;         //ptr:指针,具体bio 有不同含义。比如文件BIO中它用来存放文件句柄;mem bio 中它用来存放
//					   //内存地址;connect bio 中它用来存放BIO_CONNECT 数据,acceptbio 中它
//					   //用来存放BIO_ACCEPT数据。
//
//	struct bio_st* next_bio;    //BIO链中下一个BIO 地址,BIO 数据可以从一个BIO 传送到另一个BIO。
//	struct bio_st* prev_bio;    //BIO链中上一个BIO 地址,
//
//	int references;                     //引用计数
//	unsigned long num_read;             //已读出的数据长度
//	unsigned long num_write;            //已写入的数据长度
//
//	CRYPTO_EX_DATA ex_data;             //额外数据
//};

typedef unsigned char uchar;
int base64_encode(const uchar* in, int size, uchar* out)
{
	int outsize = 0;
	if (!in || size <= 0)
	{
		return false;
	}
	//内存源 source 封装了对内存操作的bio接口,包括了对内存的读写操作
	BIO* mem_bio = BIO_new(BIO_s_mem());    
	//base64 filter 过滤器
	BIO* base64_bio = BIO_new(BIO_f_base64()); //封装了对base64编码方法的bio,写的时候进行编码,读的时候进行解码
	if (!base64_bio)
	{
		BIO_free(mem_bio);
		return false;
	}

	//bio结构是一个链式结构,单个的bio是一个只有一个环节的bio的特例,在一个bio链中增加另一个bio
	//使用的bio_push   删除的话是bio_pop 
	BIO_push(base64_bio, mem_bio); //mem_bio附加到base_64bio的bio上,并返回base_64bio  其实就是mem_bio前插一个base64_bio
	//写入到base64 filter 进行编码,结果会传递到链表的下一个节点,即mem中读取数据
	//链表头部代表整个链表  write进行编码 编码数据每64字节(不同平台不确定)加一个\n,最后一位也有换行符

	BIO_set_flags(base64_bio, BIO_FLAGS_BASE64_NO_NL);//解决上述换行问题,会去掉所有换行符  不过解码也需要进行修改,因为最后一位也没有换行符了
	int ret = BIO_write(base64_bio, in, size);
	if (ret <= 0)
	{
		BIO_free_all(base64_bio);
		return false;
	}
	//刷新缓存,写入链表的mem
	BIO_flush(base64_bio);
	BUF_MEM* p_data = nullptr;
	//从链表源内存读取
	BIO_get_mem_ptr(base64_bio, &p_data);
	if (p_data)
	{
		memcpy(out, p_data->data, p_data->length);
		outsize = p_data->length;
	}
	BIO_free_all(base64_bio);
	return outsize;
}

int base64_decode(const uchar* in, int size, uchar* out)
{
	size_t len = 0;
	if (!in || size <= 0)
	{
		return false;
	}
	BIO* mem_bio = BIO_new_mem_buf(in, size);
	BIO* base64_bio = BIO_new(BIO_f_base64());
	if (!base64_bio)
	{
		BIO_free(mem_bio);
		return false;
	}
	BIO_push(base64_bio, mem_bio);
	BIO_set_flags(base64_bio, BIO_FLAGS_BASE64_NO_NL);//与解码进行对应,要保持一致,不然会失败  表示不会加换行
	//读解码
	BIO_read_ex(base64_bio, out,size, &len);

	BIO_free_all(base64_bio);
	return len;
}

static const  char* base64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char base64_detable[] = {
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 255,
	255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 253, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,
	52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255,
	255, 254, 255, 255, 255,   0,   1,   2,   3,   4,   5,   6,
	7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,
	19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,
	255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,
	37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
	49,  50,  51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255 };

int base64_encode_c(const uchar* in, int size, uchar* out)
{
	uchar c1, c2, c3;
	int i = 0, index = 0;
	if (!in || !out)
	{
		return -1;
	}
	while (i < size)
	{
		c1 = in[i++]; //取本次循环的第一个字节
		if (i == size)  //如果本次循环第一个字节为总字节的最后一个字节
		{
			out[index++] = base64_table[c1 >> 2]; //取高位6个bit
			out[index++] = base64_table[(c1 & 0x3)<<4];//取低位2个bit 后移拼接第二个字节的后4(0)
			out[index++] = '='; //后面补 =
			out[index++] = '=';
			break;
		}
		c2 = in[i++];//取本次循环的第二个字节
		if (i == size)//如果本次循环第二个字节为总字节的最后一个字节
		{
			out[index++] = base64_table[c1 >> 2];
			out[index++] = base64_table[((c1 & 0x03) << 4) | ((c2&0xF0) >> 4)];
			out[index++] = base64_table[((c2 & 0xF0) << 2)];
			out[index++] = '=';
			break;
		}
		c3 = in[i++];
		out[index++] = base64_table[c1 >> 2];  //取高6位
		out[index++] = base64_table[((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4)]; //第一个字节低2位左移4位 +第二个字节 高4位 右移4位
		out[index++] = base64_table[((c2 & 0x0F) << 2)|((c3&0xC0)>>6)];//第二个字节低4位左移2位+ 第三个字节的高2位 右移6位 
		out[index++] = base64_table[c3 & 0x3F];//第三个字节的低6位
	}
	return index;
}


int base64_decode_c(const uchar* in, int size, uchar* out)
{
	char c1, c2, c3, c4;
	int i = 0, index = 0;
	while (i < size)
	{
		do   //读第一个字节并进行转换为真实数字
		{
			c1 = base64_detable[(int)in[i++]];
		} while ((i < size) && (c1 == 255));
		if (c1 == 255)
		{
			break;
		}

		do   //读第二个字节并进行转换为真实数字
		{
			c2 = base64_detable[(int)in[i++]];
		} while ((i < size) && (c2 == 255));
		if (c2 == 255)
		{
			break;
		}

		out[index++] = (char)((c1 << 2) | (c2 & 0x30) >> 4);

		do   //读第三个字节并进行转换为真实数字
		{
			c3 = in[i++];
			if (c3 == '=')
			{
				return index;
			}
			c3 = base64_detable[(int)c3];
		} while ((i < size) && (c3 == 255));
		if (c3 == 255)
		{
			break;
		}

		out[index++] = (char)((c2 & 0x0F) << 4 | (c3 & 0x3C) >> 2);

		do   //读第4个字节并进行转换为真实数字
		{
			c4 = in[i++];
			if (c4 == '=')
			{
				return index;
			}
			c4 = base64_detable[(int)c4];
		} while ((i < size) && (c4 == 255));
		if (c4 == 255)
		{
			break;
		}
		out[index++] = (char)((c3 & 0x03) << 6 | (c4 & 0x3F));
	}
	return index;
}



int main()
{
	std::cout << "oepnssl BIO base64" << std::endl;
	unsigned char data[] = "测试base64001测试base64001测试base64001测试base64001测试base64001测试base64001测试base64001";
	uchar out[4096] = { 0 };
	int len = sizeof(data);
	int ret = base64_encode(data, len, out);
	if (ret > 0)
	{
		out[ret] = '\0';
		std::cout <<"ret = " << ret<<" "<< out << std::endl;
	}
	memset((char*)data, 0, sizeof(data));
	ret = base64_decode_c(out, ret, data);
	if (ret > 0)
	{
		out[ret] = '\0';
		std::cout << data << std::endl;
	}
	return 0;
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 C 语言中,您可以使用 OpenSSL 库来实现 Base64 解码。以下是一个示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <openssl/bio.h> #include <openssl/evp.h> int base64_decode(const unsigned char* encoded_data, size_t encoded_length, unsigned char* decoded_data, size_t* decoded_length) { BIO *bio, *b64; size_t length = 0; // 创建 Base64 解码的 BIO b64 = BIO_new(BIO_f_base64()); bio = BIO_new_mem_buf(encoded_data, encoded_length); bio = BIO_push(b64, bio); // 解码 BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); length = BIO_read(bio, decoded_data, encoded_length); // 清理并设置解码后的长度 BIO_free_all(bio); *decoded_length = length; return 0; } int main() { const char* encoded_text = "SGVsbG8gd29ybGQh"; // 输入要解码Base64 码字符串 size_t encoded_length = strlen(encoded_text); size_t decoded_length = ((encoded_length + 3) / 4) * 3; unsigned char* decoded_text = (unsigned char*)malloc(decoded_length + 1); if (decoded_text == NULL) { printf("内存分配失败!\n"); return 1; } int result = base64_decode((const unsigned char*)encoded_text, encoded_length, decoded_text, &decoded_length); if (result != 0) { printf("解码失败:%d\n", result); free(decoded_text); return 1; } decoded_text[decoded_length] = '\0'; printf("解码结果:%s\n", decoded_text); free(decoded_text); return 0; } ``` 在上述示例代码中,我们使用了 OpenSSL 的 `BIO`(I/O 抽象)和 `EVP`(加密算法)来实现 Base64 解码。需要注意的是,您需要先安装 OpenSSL 库并确保译时链接了正确的库文件。 译和运行上述代码后,将输出解码结果:"Hello world!"。 请注意,此示例仅演示了如何使用 OpenSSL 库来进行 Base64 解码。如果您需要进行更复杂的加密/解密操作,可以参考 OpenSSL 的官方文档或其他资源获取更多信息。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值