OpenSSL算法学习

base16

#include<iostream>
using namespace std;
static const char BASE16_ENC_TAB[] = "0123456789ABCDEF";
static const char BASE16_DEC_TAB[] = {
	-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	'A'~'F'
};

int Base16Encode(const unsigned char* in,int size,char* out)
{
	for (int i = 0; i < size; i++)
	{
		//一个字节取出高4位和低4位 1000 0001   0000 1000
		char high = in[i] >> 4;		//移位丢弃低位 (0~15)
		char low = in[i] & 0x0F;	//0000 1111 去掉高位(0~15)
		out[i * 2] = BASE16_ENC_TAB[high];//(0~15)映射到对应字符
		out[i * 2 + 1] = BASE16_ENC_TAB[low];
	}
	//base16 转码后空间扩大一倍,4位转成一个字符,一个字节转成两个字符
	return size * 2;
}
int Base16Decode(const string& in, unsigned char* out)
{
	for (int i = 0; i < in.size(); i += 2)
	{
		unsigned char ch = (int)in[i];
		unsigned char cl = (int)in[i + 1];
		unsigned h = BASE16_DEC_TAB[ch];
		unsigned l = BASE16_DEC_TAB[cl];

		out[i / 2] = (int)(h << 4 | l);
	}
	return in.size() / 2;
}

int main(int argc, char* argv[])
{
	cout << "test base16" << endl;
	const unsigned char data[] = "测试base16";
	int len = sizeof(data);
	char out1[1024] = { 0 };
	unsigned char out2[1024] = { 0 };
	cout << data << endl;
	int re = Base16Encode(data, len, out1);
	cout << re << ":" << out1 << endl;
	re = Base16Decode(out1, out2);
	cout << re << ":" << out2 << endl;
	return 0;
}

base64

base64编码要求把3个8位字节(3*8=24)转化为4个6位的字节(4*9=24),之后在6位的前面补两个0,形成8位一个字节的形式。如果剩下的字节不足3个字节,则用0填充,输出字符使用‘=’因此编码后输出的文本末尾可能会出现1或2个‘=’。

BIO接口

BIO包含了多种接口,用于控制在BIO_METHOD中的不同实现函数,包含6中filter型和8中source/sink型。应用场景:

BIO_new创建一个BIO对象

数据源:source/sink类型的BIO是数据源BIO_new(BIO_s_mem())

过滤:filter BIO就是把数据从一个BIO转换到另一个BIO或应用接口

        BIO_new(BIO_f_base64());

BIO链:一个BIO链通常包括一个source BIO和一个或多个filter BIO

        BIO_push(b64_bio,mem_bio);

写编码,读编码BIO_write   BIO_read_ex

加码

int Base64Encode(const unsigned char* in, int len, char* out_base64)
{
	if (!in || len <= 0 || !out_base64)
		return 0;
	//内存源 source
	auto mem_bio = BIO_new(BIO_s_mem());
	if (!mem_bio)return 0;

	//base64 filter
	auto b64_bio = BIO_new(BIO_f_base64());
	if (!b64_bio)
	{
		BIO_free(mem_bio);
		return 0;
	}

	//形成BIO链
	//b64_mem
	BIO_push(b64_bio, mem_bio);
	//超过64字节不添加换行符(\n),编码的数据在一行中
	// 默认结尾有换行符\n 超过64字节再添加\n
	BIO_set_flags(b64_bio, BIO_FLAGS_BASE64_NO_NL);

	//写入到base64 filter 进行编码,结果会传递到链表的下一个节点,到mem中读取结果
	// (从链表头部链表头部代表了整个链表)
	//BIO_write编码 3字节->4字节 不足三字节 补充 0 和 =
	//编码数据每64字节(不确定)会加\n换行符
	int re = BIO_write(b64_bio, in, len);
	if (re <= 0)
	{
		//清空整个链表节点
		BIO_free_all(b64_bio);
		return 0;
	}
	//刷新一下缓存,写入链表的mem
	BIO_flush(b64_bio);
	int outsize = 0;
	//从链表源内存读取
	BUF_MEM* p_data = 0;
	BIO_get_mem_ptr(b64_bio, &p_data);
	if (p_data)
	{
		memcpy(out_base64, p_data->data,p_data->length);
		outsize = p_data->length;
	}
	BIO_free_all(b64_bio);
	return outsize;
}

解码

int Base64Decode(const char* in, int len, unsigned char* out_data)
{
	if (!in || len <= 0 || !out_data)
		return 0;
	//内存源(密文)
	auto mem_bio = BIO_new_mem_buf(in, len);
	if (!mem_bio) return 0;
	//base64 过滤器
	auto b64_bio = BIO_new(BIO_f_base64());
	if (!b64_bio)
	{
		BIO_free(mem_bio);
		return 0;
	}
	//形成BIO链
	BIO_push(b64_bio, mem_bio);

	//读取 解码
	// 默认读取换行符做结束
	//设置后编码中如果有\n会失败
	BIO_set_flags(b64_bio, BIO_FLAGS_BASE64_NO_NL);

	//四字节转三字节
	size_t size = 0;
	BIO_read_ex(b64_bio, out_data, len, &size);
	BIO_free(b64_bio);
	return size;
}

整体代码

#include<iostream>
using namespace std;
#include<openssl/bio.h>
#include <openssl/evp.h>
#include<openssl/buffer.h>

int Base64Encode(const unsigned char* in, int len, char* out_base64)
{
    ......
}
int Base64Decode(const char* in, int len, unsigned char* out_data)
{
    ......
}

int main(int argc, char* argv[])
{
	cout << "first openssl code" << endl;
	unsigned char data[] = "测试base64数据";
	int len = sizeof(data);
	char out[1024] = { 0 };
	unsigned char out2[1024] = { 0 };
	cout << "source:" << data << endl;
	int re = Base64Encode(data, len, out);
	if (re > 0)
	{
		out[re] = '\0';
		cout <<"encode:" << out << endl;
	}
	int res = Base64Decode(out, re, out2);
	cout << "decode:" << out2 << endl;
	getchar();
	return 0;
}

base58

Base58 是一种用于编码数字的编码表,它主要用于加密货币地址中,如比特币等。与其他常见的编码表,如 Base64 不同,Base58 编码表不包含数字 0、大写字母 O、大写字母 I、小写字母 l 等易混淆的字符,可以避免在传输过程中的误解和错误。

Base58 编码表的原理是将数字转换为一组基于 58 个字符的字符串,每个字符对应于一个特定的值,从而实现对数字的编码。以下是 Base58 编码表的字符集:

123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz

其中,数字 0、大写字母 O、大写字母 I、小写字母 l 被排除在外,共计 58 个字符。

编码

//编码表
static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";

//编码函数:
std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
{
    // Skip & count leading zeroes.
    int zeroes = 0;
    int length = 0;
    while (pbegin != pend && *pbegin == 0) {
        pbegin++;
        zeroes++;
    }
    // Allocate enough space in big-endian base58 representation.
    int size = (pend - pbegin) * 138 / 100 + 1; // log(256) / log(58), rounded up.
    std::vector<unsigned char> b58(size);
    while (pbegin != pend) {
        int carry = *pbegin;
        int i = 0;
        // Apply "b58 = b58 * 256 + ch".
        for (auto it = b58.rbegin();
            (carry != 0 || i < length) && (it != b58.rend());
            it++, i++) {
            carry += 256 * (*it);
            *it = carry % 58;
            carry /= 58;
        }

        assert(carry == 0);
        length = i;
        pbegin++;
    }
    // Skip leading zeroes in base58 result.
    std::vector<unsigned char>::iterator it = b58.begin() + (size - length);
    while (it != b58.end() && *it == 0)
        it++;
    // Translate the result into a string.
    std::string str;
    str.reserve(zeroes + (b58.end() - it));
    str.assign(zeroes, '1');
    while (it != b58.end())
        str += pszBase58[*(it++)];
    return str;
}

解码

// 解码表需要自建
static const int8_t mapBase58[256] = {
    -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
    -1, 0, 1, 2, 3, 4, 5, 6,  7, 8,-1,-1,-1,-1,-1,-1,
    -1, 9,10,11,12,13,14,15, 16,-1,17,18,19,20,21,-1,
    22,23,24,25,26,27,28,29, 30,31,32,-1,-1,-1,-1,-1,
    -1,33,34,35,36,37,38,39, 40,41,42,43,-1,44,45,46,
    47,48,49,50,51,52,53,54, 55,56,57,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
};

//解码
bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch, int max_ret_len)
{
    // Skip leading spaces.
    while (*psz && IsSpace(*psz))
        psz++;
    // Skip and count leading '1's.
    int zeroes = 0;
    int length = 0;
    while (*psz == '1') {
        zeroes++;
        if (zeroes > max_ret_len) return false;
        psz++;
    }
    // Allocate enough space in big-endian base256 representation.
    int size = strlen(psz) * 733 / 1000 + 1; // log(58) / log(256), rounded up.
    std::vector<unsigned char> b256(size);
    // Process the characters.
    static_assert(sizeof(mapBase58) / sizeof(mapBase58[0]) == 256, "mapBase58.size() should be 256"); // guarantee not out of range
    while (*psz && !IsSpace(*psz)) {
        // Decode base58 character
        int carry = mapBase58[(uint8_t)*psz];
        if (carry == -1)  // Invalid b58 character
            return false;
        int i = 0;
        for (std::vector<unsigned char>::reverse_iterator it = b256.rbegin(); (carry != 0 || i < length) && (it != b256.rend()); ++it, ++i) {
            carry += 58 * (*it);
            *it = carry % 256;
            carry /= 256;
        }
        assert(carry == 0);
        length = i;
        if (length + zeroes > max_ret_len) return false;
        psz++;
    }
    // Skip trailing spaces.
    while (IsSpace(*psz))
        psz++;
    if (*psz != 0)
        return false;
    // Skip leading zeroes in b256.
    std::vector<unsigned char>::iterator it = b256.begin() + (size - length);
    // Copy result into output vector.
    vch.reserve(zeroes + (b256.end() - it));
    vch.assign(zeroes, 0x00);
    while (it != b256.end())
        vch.push_back(*(it++));
    return true;
}

 

  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值