Featured image of post base64加解密原理及base64变种

base64加解密原理及base64变种

前言

今天整理电脑资料,无意间翻出来一道CTF题。考题内容是变种base64加解密,解题程序是当时做题是从互联网收集,个博客做个记录,顺便回顾下base64加解密原理。

base64加解密原理

  1. base64字符的组成部分 A-Z、a-z、0-9、+、/
    26 + 26 + 10 + 2 = 64
  2. Base64表
    base64码表
  3. 加密原理 先将每三个字符分离,最后有可能剩0个或者1个或者2个字符。
  • 整三个:将三个字符转换为ascii二进制码,得到24bit(3*8bit),然后再按顺序分为4份(每6bit为一份)。最后,将这四份二进制转换为4份十进制,再按照Base64字符表转为4个字符。
  • 分离后剩1个字符:将这一个字符转换为ascii二进制码,先切一个6bit还剩2bit,再将这2bit后面补4个0。最后,将这两份二进制转换为2份十进制,再按照Base64字符表转为2个字符,后面再补两个等于号(这里两个等号打不出来)。
  • 分离后剩2个字符:将这一个字符转换为ascii二进制码,先切两个6bit还剩4bit,再将这2bit后面补2个0。最后,将这三份二进制转换为3份十进制,再按照Base64字符表转为3个字符,后面再补一个等于号(=)。
  • Base64对于中文的不同编码可能会出现不同的结果,具体要看中文用的是什么编码。
  1. 以字符串"php"为例 对应ASCII: 01110000 01101000 01110000
    每6位分割: 011100 000110 100001 110000
    对应10进制值: 28 6 33 48
    Base64对应的字符:c G h w
    结果: php = cGhw(base64)
  2. 解密 看懂加密,解密就是加密的逆向,这里要强调的是:Base64解密也是靠着Base64表解密的,如果碰到不在Base64表的字符(空格,<,>,等等),将会跳过这些字符,仅将在表内的字符组成一个新的字符串进行解码。

base64变种

base64变种主要是围绕base64码表,比如对码表做凯撒加密处理,或是题目给一段自定义64码表

base64加解密程序

# python版本
# coding:utf-8

#s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
s = "uL9BG2i1po7z6MnCQf8rvDxJt5Ahw3kjlKWPesqy+EdZbc/aS0HOVXYmNgIRTFU4"

def My_base64_encode(inputs):
        # 将字符串转化为2进制
        bin_str = []
        for i in inputs:
                x = str(bin(ord(i))).replace('0b', '')
                bin_str.append('{:0>8}'.format(x))
        #print(bin_str)
        # 输出的字符串
        outputs = ""
        # 不够三倍数,需补齐的次数
        nums = 0
        while bin_str:
                #每次取三个字符的二进制
                temp_list = bin_str[:3]
                if(len(temp_list) != 3):
                        nums = 3 - len(temp_list)
                        while len(temp_list) < 3:
                                temp_list += ['0' * 8]
                temp_str = "".join(temp_list)
                #print(temp_str)
                # 将三个8字节的二进制转换为4个十进制
                temp_str_list = []
                for i in range(0,4):
                        temp_str_list.append(int(temp_str[i*6:(i+1)*6],2))
                #print(temp_str_list)
                if nums:
                        temp_str_list = temp_str_list[0:4 - nums]

                for i in temp_str_list:
                        outputs += s[i]
                bin_str = bin_str[3:]
        outputs += nums * '='
        print("Encrypted String:\n%s "%outputs)

def My_base64_decode(inputs):
        # 将字符串转化为2进制
        bin_str = []
        for i in inputs:
                if i != '=':
                        x = str(bin(s.index(i))).replace('0b', '')
                        bin_str.append('{:0>6}'.format(x))
        #print(bin_str)
        # 输出的字符串
        outputs = ""
        nums = inputs.count('=')
        while bin_str:
                temp_list = bin_str[:4]
                temp_str = "".join(temp_list)
                #print(temp_str)
                # 补足8位字节
                if(len(temp_str) % 8 != 0):
                        temp_str = temp_str[0:-1 * nums * 2]
                # 将四个6字节的二进制转换为三个字符
                for i in range(0,int(len(temp_str) / 8)):
                        outputs += chr(int(temp_str[i*8:(i+1)*8],2))
                bin_str = bin_str[4:]
        print("Decrypted String:\n%s "%outputs)

print()
print("     *************************************")
print("     *    (1)encode         (2)decode    *")
print("     *************************************")
print()

num = input("Please select the operation you want to perform:\n")
if(num == "1"):
        input_str = input("Please enter a string that needs to be encrypted: \n")
        My_base64_encode(input_str)
else:
        input_str = input("Please enter a string that needs to be decrypted: \n")
        My_base64_decode(input_str)
/*C语言版本*/
#include <stdio.h>
#include <string.h>

// 全局常量定义
// const char * base64char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const char * base64char = "uL9BG2i1po7z6MnCQf8rvDxJt5Ahw3kjlKWPesqy+EdZbc/aS0HOVXYmNgIRTFU4";
const char padding_char = '=';

/*编码代码
* const unsigned char * sourcedata, 源数组
* char * base64 ,码字保存
*/
int base64_encode(const unsigned char * sourcedata, char * base64)
{
    int i = 0, j = 0;
    unsigned char trans_index = 0;    // 索引是8位,但是高两位都为0
    const int datalength = strlen((const char*)sourcedata);
    for (; i < datalength; i += 3){
        // 每三个一组,进行编码
        // 要编码的数字的第一个
        trans_index = ((sourcedata[i] >> 2) & 0x3f);
        base64[j++] = base64char[(int)trans_index];
        // 第二个
        trans_index = ((sourcedata[i] << 4) & 0x30);
        if (i + 1 < datalength){
            trans_index |= ((sourcedata[i + 1] >> 4) & 0x0f);
            base64[j++] = base64char[(int)trans_index];
        }
        else{
            base64[j++] = base64char[(int)trans_index];
            base64[j++] = padding_char;
            base64[j++] = padding_char;
            break;   // 超出总长度,可以直接break
        }
        // 第三个
        trans_index = ((sourcedata[i + 1] << 2) & 0x3c);
        if (i + 2 < datalength){ // 有的话需要编码2个
            trans_index |= ((sourcedata[i + 2] >> 6) & 0x03);
            base64[j++] = base64char[(int)trans_index];
            trans_index = sourcedata[i + 2] & 0x3f;
            base64[j++] = base64char[(int)trans_index];
        }
        else{
            base64[j++] = base64char[(int)trans_index];
            base64[j++] = padding_char;
            break;
        }
    }

    base64[j] = '\0';
    return 0;
}

/** 在字符串中查询特定字符位置索引
* const char *str ,字符串
* char c,要查找的字符
*/
int num_strchr(const char *str, char c) // 
{
    const char *pindex = strchr(str, c);
    if (NULL == pindex){
        return -1;
    }
    return pindex - str;
}
/* 解码
* const char * base64 码字
* unsigned char * dedata, 解码恢复的数据
*/
int base64_decode(const char * base64, unsigned char * dedata)
{
    int i = 0, j = 0;
    int trans[4] = { 0, 0, 0, 0 };
    for (; base64[i] != '\0'; i += 4){
        // 每四个一组,译码成三个字符
        trans[0] = num_strchr(base64char, base64[i]);
        trans[1] = num_strchr(base64char, base64[i + 1]);
        // 1/3
        dedata[j++] = ((trans[0] << 2) & 0xfc) | ((trans[1] >> 4) & 0x03);
        if (base64[i + 2] == '='){
            continue;
        }
        else{
            trans[2] = num_strchr(base64char, base64[i + 2]);
        }
        // 2/3
        dedata[j++] = ((trans[1] << 4) & 0xf0) | ((trans[2] >> 2) & 0x0f);
        if (base64[i + 3] == '='){
            continue;
        }
        else{
            trans[3] = num_strchr(base64char, base64[i + 3]);
        }

        // 3/3
        dedata[j++] = ((trans[2] << 6) & 0xc0) | (trans[3] & 0x3f);
    }
    dedata[j] = '\0';
    return 0;
}

// 测试
int main()
{
    const unsigned char str[] = "a45rbcd";
    const unsigned char *sourcedata = str;
    char base64[512];

    base64_encode(str, base64);
    printf("编码:%s\n", base64);
    char dedata[128];
    base64_decode(base64, (unsigned char*)dedata);
    printf("译码:%s", dedata);
    getchar(); 
    return 0;
}

参考

Base64加密解密原理