base64加密原理及python、C语言代码实现

base64算法

base64加密原理

关于base64,百度百科给出的解释是:

Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。可查看RFC2045~RFC2049,上面有MIME的详细规范。
Base64编码是从二进制到字符的过程,可用于在HTTP环境下传递较长的标识信息。采用Base64编码具有不可读性,需要解码后才能阅读。
Base64由于以上优点被广泛应用于计算机的各个领域,然而由于输出内容中包括两个以上“符号类”字符(+, /, =),不同的应用场景又分别研制了Base64的各种“变种”。为统一和规范化Base64的输出,Base62x被视为无符号化的改进版本。

base64中的这64个可打印字符包括小写的 a − z a-z az和大写的 A − Z A-Z AZ,依旧数字 0 − 9 0-9 09以及两个符号 “ + " 和 “ / " “+"和“/" +"/"。选择64这个数字是因为64是2的6次方,正好可以用6位二进制编号,所以这64个字符在这里的编号不同于在ASCII中的编号了,应该为:
在这里插入图片描述
要先明确,base64的加密对象是二进制串

加密过程是:将三个字节 (共3*8=24位) 的二进制转换为四个字符

例如:
原来的二进制数是:1111 1111, 1111 1111, 1111 1111 (二进制)
转换后 0011 1111, 0011 1111, 0011 1111, 0011 1111 (二进制)
十进制为:63,63,63,63
对应上面码表的字符为 / / / / ////
所以上面的24位编码,编码后的Base64值为 / / / / ////

再来一个例子:
原来的二进制数是:1010 1101,1011 1010,0111 0110(二进制)
转换后 0010 1011, 0001 1011 ,0010 1001 ,0011 0110(二进制)
十进制为:43 27 41 54
对应上面码表的字符为 r b p 2 rbp2 rbp2
所以上面的24位编码,编码后的Base64值为 r b p 2 rbp2 rbp2
解码同理,把 r b q 2 rbq2 rbq2的二进制位连接上再重组得到三个8位值,得出原码。

base加密在python中可以直接调用库:base64,例如:
(知道Base是对二进制数进行加密的,所以在对字母进行加密是就需要先将字母转化为数字)

import base64

s = 'a'
s1 = base64.b64encode(s.encode())
print(s1)
# b'YQ=='

s = 'ab'
s1 = base64.b64encode(s.encode())
print(s1)
# b'YWI='

C 语言实现

// base64.cpp
#include <iostream>
#include <windows.h>
#include "Base64.h"

using namespace std;


char *base64_encode(const char* data, int data_len) 
{ 
    //int data_len = strlen(data); 
    int prepare = 0; 
    int ret_len; 
    int temp = 0; 
    char *ret = NULL; 
    char *f = NULL; 
    int tmp = 0; 
    char changed[4]; 
    int i = 0; 
    ret_len = data_len / 3; 
    temp = data_len % 3; 
    if (temp > 0) 
    { 
        ret_len += 1; 
    } 
    ret_len = ret_len*4 + 1; 
    ret = (char *)malloc(ret_len); 
      
    if ( ret == NULL) 
    { 
        printf("No enough memory.\n"); 
        exit(0); 
    } 
    memset(ret, 0, ret_len); 
    f = ret; 
    while (tmp < data_len) 
    { 
        temp = 0; 
        prepare = 0; 
        memset(changed, '\0', 4); 
        while (temp < 3) 
        { 
            //printf("tmp = %d\n", tmp); 
            if (tmp >= data_len) 
            { 
                break; 
            } 
            prepare = ((prepare << 8) | (data[tmp] & 0xFF)); 
            tmp++; 
            temp++; 
        } 
        prepare = (prepare<<((3-temp)*8)); 
        //printf("before for : temp = %d, prepare = %d\n", temp, prepare); 
        for (i = 0; i < 4 ;i++ ) 
        { 
            if (temp < i) 
            { 
                changed[i] = 0x40;          // 瀵瑰簲鐮佽〃涓殑 '=' 
            } 
            else 
            { 
                changed[i] = (prepare>>((3-i)*6)) & 0x3F; 
            } 
            *f = base[changed[i]]; 
            //printf("%.2X", changed[i]); 
            f++; 
        } 
    } 
    *f = '\0'; 
      
    return ret; 
      
} 


static char find_pos(char ch)   
{ 
    char *ptr = (char*)strrchr(base, ch);//the last position (the only) in base[] 
    return (ptr - base); 
} 


char *base64_decode(const char *data, int data_len) 
{ 
    int ret_len = (data_len / 4) * 3; 
    int equal_count = 0; 
    char *ret = NULL; 
    char *f = NULL; 
    int tmp = 0; 
    int temp = 0;
    int prepare = 0; 
    int i = 0; 
    if (*(data + data_len - 1) == '=') 
    { 
        equal_count += 1; 
    } 
    if (*(data + data_len - 2) == '=') 
    { 
        equal_count += 1; 
    } 
    if (*(data + data_len - 3) == '=') 
    {//seems impossible 
        equal_count += 1; 
    } 
    switch (equal_count) 
    { 
    case 0: 
        ret_len += 4;//3 + 1 [1 for NULL] 
        break; 
    case 1: 
        ret_len += 4;//Ceil((6*3)/8)+1 
        break; 
    case 2: 
        ret_len += 3;//Ceil((6*2)/8)+1 
        break; 
    case 3: 
        ret_len += 2;//Ceil((6*1)/8)+1 
        break; 
    } 
    ret = (char *)malloc(ret_len); 
    if (ret == NULL) 
    { 
        printf("No enough memory.\n"); 
        exit(0); 
    } 
    memset(ret, 0, ret_len); 
    f = ret; 
    while (tmp < (data_len - equal_count)) 
    { 
        temp = 0; 
        prepare = 0; 
        while (temp < 4) 
        { 
            if (tmp >= (data_len - equal_count)) 
            { 
                break; 
            } 
            prepare = (prepare << 6) | (find_pos(data[tmp])); 
            temp++; 
            tmp++; 
        } 
        prepare = prepare << ((4-temp) * 6); 
        for (i=0; i<3 ;i++ ) 
        { 
            if (i == temp) 
            { 
                break; 
            } 
            *f = (char)((prepare>>((2-i)*8)) & 0xFF); 
            f++; 
        } 
    } 
    *f = '\0'; 
    return ret; 
}


int main() {
    char text[200];
	printf("请输入待加密字符:");
	int i=0;
	do
    {
        scanf("%s",&text[i]); 
        i++;
    }while(getchar()!='\n');
    printf("%s\n", base64_encode(text, strlen(text)));

    return 0;
}
// base64.h

#ifndef BASE64_H
#define BASE64_H

const char base[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; 


char* base64_encode(const char* data, int data_len); 


char *base64_decode(const char* data, int data_len); 

#endif

代码参考

python实现

利用库

import base64
s = input()
a = base64.b64encode(s.decode())
print(a)

原理实现

class MyBase64():
    base64_dict = {}
    string_temp = ('ABCDEFGHIJKLMNOPQRSTUVWXYZ'
                   'abcdefghijklmnopqrstuvwxyz'
                   '0123456789+/')
    ascii_string = ''.join([chr(i) for i in range(4, 2 ** 7 - 1)])

    def __init__(self, string):
        # 初始化,创建 base64 编码字典
        self.string = string
        for i in range(2 ** 6):
            self.base64_dict[i] = self.string_temp[i]

    def convert(self):
        # base64 编码过程

        # 编码
        string_encode_byte = self.string.encode('utf-8')
        # 十进制化
        string_digit_list = list(string_encode_byte)

        # 二进制化 + 0 填充
        string_bin_list = []
        for item in string_digit_list:
            string_bin_list.append(str(bin(item))[2:].zfill(8))

        # 字符串合并
        string_sum = ''.join(string_bin_list)

        # 6 的倍数,不足 0 填充
        string_fill = self.fillIt(string_sum, factor=6, item='0')

        # 切片,6位一个单位
        string_bin_list2 = self.splitIt(string_fill, bits=6)

        # 十进制化
        string_digit_list2 = []
        for item in string_bin_list2:
            string_digit_list2.append(int(item, 2))

        # 查表
        string_base64_list = []
        for item in string_digit_list2:
            string_base64_list.append(self.base64_dict[item])

        # 拼接
        string_sum2 = ''.join(string_base64_list)
        # 4 的倍数,不足填充 =
        string_convert = self.fillIt(string_sum2, factor=4, item='=')

        return string_convert

    def fillIt(self, string, factor, item):
        """
        指定倍数填充指定字符
        string:原字符串
        factor:倍数
        item:填充字符
        """
        length = len(string)
        remainder = length % factor
        if remainder:
            times = factor - remainder
            string = string + times * item
        return string

    def splitIt(self, string, bits):
        """
        指定位数切片
        string:原字符串
        bits:每次切片数量
        """
        length = len(string)
        new_list = []
        for i in range(bits, length + 1, bits):
            new_list.append(string[i - bits:i])
            remain = length % bits
        if remain != 0:
            new_list.append(string[-remain:])
        return new_list


if __name__ == '__main__':
    string = input()
    myBase64 = MyBase64(string)
    enc_string = myBase64.convert()
    print("测试字符串:{}".format(string))
    print("base64:{}".format(enc_string))

代码参考

拓展:base隐写

base64之所以可以隐藏信息,便是在于在解密过程中,在解码的第3步中,会有部分数据被丢弃(即不会影响解码结果),这些数据正是在编码过程中补的0。也就是说,如果在编码过程中不全用0填充,而是用其他的数据填充,仍然可以正常编码解码,因此这些位置可以用于隐写。

解开隐写的方法就是将这些不影响解码结果的位提取出来组成二进制串(一行 base64 最多有 2 个等号, 也就是有 22 位的可隐写位.),然后转换成ASCII字符串。这就是为什么出base64隐写时会有很多大段 base64 的原因

原理及代码参考

def get_base64_diff_value(s1, s2):
    base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
    res = 0
    for i in xrange(len(s2)):
        if s1[i] != s2[i]:
            return abs(base64chars.index(s1[i]) - base64chars.index(s2[i]))
    return res


def solve_stego():
    with open('shy.txt', 'rb') as f:
        file_lines = f.readlines()
        bin_str = ''
        for line in file_lines:
            steg_line = line.replace('\n', '')
            norm_line = line.replace('\n', '').decode('base64').encode('base64').replace('\n', '')
            diff = get_base64_diff_value(steg_line, norm_line)
            print diff
            pads_num = steg_line.count('=')
            if diff:
                bin_str += bin(diff)[2:].zfill(pads_num * 2)
            else:
                bin_str += '0' * pads_num * 2
            print goflag(bin_str)


def goflag(bin_str):
    res_str = ''
    for i in xrange(0, len(bin_str), 8):
        res_str += chr(int(bin_str[i:i + 8], 2))
    return res_str


if __name__ == '__main__':
    solve_stego()

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值