(加密基礎)base64篇

base64篇

base64嚴格意義說並不是一種加密方式,而是一種編碼方式,標準的base64有很多的特徵例如字符串中常常會看到"+“和”",在末尾也時常看到兩個連續的"="

1、原理:

base64將每三個字節分成一組(24bit),再將這一組數據數據按照每6個bit進行切割,這樣就切割出了4個小組,在將每個小組高位補0,湊齊8bit,在對應base64轉化表,將其轉化爲新的編碼。

這裏需要注意的是當字符串不是3的倍數時,需要用0對字符串進行補齊,將其轉化爲3的倍數,然而最後必然會產生全0值,而base64編碼表的0對應的通常是’A’,這樣在解碼時會造成極大的麻煩,因此引入了’='字符串,對末尾的0進行編碼,由於base64的特性可能會導致其末尾出現一個或者最多兩個0的情況

示例(1):當字符串爲三的倍數時:

字符 6 6 6 6 6 6 * *
16進製表示 0x36 0x36 0x36 0x36
2進製表示 00110110 00110110 00110110 00110110 00110110 00110110
每6位切割處理後 001101 100011 011000 110110 001101 100011 011000 110110
對比base64編碼表後 0xD 0x23 0x18 0x36 0xD 0x23 0x18 0x36
對應的base64字符 N j Y 2 N j Y 2

示例(2):當字符串不爲三的倍數時:
這個時候就需要用0將不足三個補齊三個

字符 6 6 * *
16進製表示 0x36 0x36 0x0(補齊)
2進製表示 00110110 00110110 00000000
每6位切割處理後 001101 100011 011000 00000
對比base64編碼表後 0xD 0x23 0x18 0x0(末尾0)
對應的base64字符 N j Y =

2.1、C語言實現(加密):

1.對輸入的字符串進行判斷並補成3的倍數

unsigned int			SixBitGroupSize;		//明文6Bit組大小
unsigned char*			BitPlainText;			//明文Bit組	
if (strlen(PlainText) % 3)	//不是3的倍數
	{
		BitPlainSize		= (strlen(PlainText) / 3 + 1) * 3;
		SixBitGroupSize		= (strlen(PlainText) / 3 + 1) * 4;
	}
	else	//是3的倍數
	{
		BitPlainSize = strlen(PlainText);
		SixBitGroupSize = strlen(PlainText) / 3 * 4;
	}

這很簡單根據實際情況對明文bit組的大小和6bit組的大小進行修正就可以了

2.將已經爲3的倍數的字符串(3x8bit)轉化成(4x6bit)

int TransitionSixBitGroup(unsigned char *BitPlainText, unsigned char* SixBitGroup, unsigned int SixBitGroupSize)
{
    int ret = 0;
 
    //1、每4個6Bit組一個循環
    for (int i = 0, j = 0; i < SixBitGroupSize; i += 4, j += 3)
    {
        SixBitGroup[i]        = ((BitPlainText[j] & 0xFC) >> 2);
        SixBitGroup[i + 1]    = ((BitPlainText[j] & 0x03) << 4) + ((BitPlainText[j + 1] & 0xF0) >> 4);
        SixBitGroup[i + 2]    = ((BitPlainText[j + 1] & 0x0F) << 2) + ((BitPlainText[j + 2] & 0xC0) >> 6);
        SixBitGroup[i + 3]    = (BitPlainText[j + 2] & 0x3F);
    }
 
    return ret;
}

for循環代碼分析:

(1)SixBitGroup[i] = ((BitPlainText[j] & 0xFC) >> 2);

根據&操作符的特性,將8位二進制數據保留前6位,在將前6位數據右移2位實現補零操作

在這裏插入圖片描述

(2)SixBitGroup[i + 1] = ((BitPlainText[j] & 0x03) << 4) + ((BitPlainText[j + 1] & 0xF0) >> 4);

將第一個8位的後兩位提出來,左移4位作爲第二個6bit的高位和第二個8位的前4位進行相加

在這裏插入圖片描述

(3)SixBitGroup[i + 2] = ((BitPlainText[j + 1] & 0x0F) << 2) + ((BitPlainText[j + 2] & 0xC0) >> 6);

將第二個8位的後四位提取出來,向左移2位作爲高位和第三個8位的前兩位右移6位到最低位,後相加

在這裏插入圖片描述

(3)SixBitGroup[i + 3] = (BitPlainText[j + 2] & 0x3F)

將第3個8位的後6位直接提取出來

在這裏插入圖片描述

3.獲取6bit轉換成功後的字符串

unsigned char Base64Table[64] =
{
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
    'I', 'G', 'K', 'L', 'M', 'N', 'O', 'P',
    'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
    'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
    'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
    'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
    'w', 'x', 'y', 'z', '0', '1', '2', '3',
    '4', '5', '6', '7', '8', '9', '+', '/'
};
 
int GetBase64String(unsigned char *CipherGroup, unsigned char *SixBitGroup, unsigned int SixBitGroupSize)
{
    int ret = 0;
 
    for (int i = 0; i < SixBitGroupSize; i++)
    {
        CipherGroup[i] = Base64Table[SixBitGroup[i]];
    }
 
    return ret;
}

4.獲取6bit轉換成功後的字符串最後兩位,若爲’A’則將其轉化爲’=’

for (int i = SixBitGroupSize - 1; i > SixBitGroupSize - 3; i--)
{
    if (CipherGroup[i] == 'A')
    {
        CipherGroup[i] = '=';
    }
}

2。2、C語言實現(解碼):

1.首先將編碼的字符串轉化爲對應的值

int GetBase64Index(unsigned char *CipherText, unsigned char *Base64Index, unsigned int Base64IndexSize)
{
    int ret = 0;
 
    for (int i = 0; i < Base64IndexSize; i++)
    {
        //計算下標
        if (CipherText[i] >= 'A' && CipherText[i] <= 'Z')    //'A'-'Z'
        {
            Base64Index[i] = CipherText[i] - 'A';
        }
        else if (CipherText[i] >= 'a' && CipherText[i] <= 'z')    //'a'-'z'
        {
            Base64Index[i] = CipherText[i] - 'a' + 26;
        }
        else if (CipherText[i] >= '0' && CipherText[i] <= '9')    //'0'-'9'
        {
            Base64Index[i] = CipherText[i] - '0' + 52;
        }
        else if (CipherText[i] == '+')
        {
            Base64Index[i] = 62;
        }
        else if (CipherText[i] == '/')
        {
            Base64Index[i] = 63;
        }
        else    //處理字符串末尾是'='的情況
        {
            Base64Index[i] = 0;
        }
    }
 
    return ret;
}

其實也可以通過索引Base64Table[64]數組,但是這樣做會極大增加時間複雜度,因此在C語言中沒有這麼做

2.將4X6Bit組轉換爲3X8Bit組形式

int TransitionEightBitGroup(unsigned char *BitPlainText, unsigned char *Base64Index, unsigned int Base64IndexSize)
{
    int ret = 0;
 
    for (int i = 0, j = 0; j < Base64IndexSize; i += 3, j += 4)
    {
        BitPlainText[i]        = (Base64Index[j] << 2) + ((Base64Index[j + 1] & 0xF0) >> 4);
        BitPlainText[i + 1]    = ((Base64Index[j + 1] & 0x0F) << 4) + ((Base64Index[j + 2] & 0xFC) >> 2);
        BitPlainText[i + 2]    = ((Base64Index[j + 2] & 0x03) << 6) + Base64Index[j + 3];
    }
F
    return ret;
}

這個跟前面一樣也是相關的位移、取出指定位的操作

3、python:

import base64
#加密
s = '66'
a = base64.b64encode(s.encode('utf-8'))
print(a)
#解密
print (base64.b64decode(a))

補充:
ctf題可能出現base64變碼的情況這個時候就需要進行一些轉化:

import base64
table_tmp = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'N', 'M','O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b','c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p','q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '9', '1', '2', '3','4', '5', '6', '7', '8', '0', '+', '/']
table_original = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
table_tmp_str = ''
str1 = ''  
for i in table_tmp:
	table_tmp_str += i
print(table_tmp_str)
print(base64.b64decode(str1.translate(str.maketrans(table_tmp_str,table_original))))

4.java

思路和C語言基本相同

public class Base64Realize {
    //進行base64映射的字符數組
    private final static char[] str = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
                                   'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
                                   '0','1','2','3','4','5','6','7','8','9','+','/'};

    /**
     * 獲取解碼器
     * @return
     */
    public static Base64Realize getDecoder(){
        return new Base64Realize();
    }

    /**
     * 解碼
     * @param code
     * @return
     */
    public String decode(String code){
        //對字符串的長度進行計算
        int length = code.length();
        //判斷長度的合法性
        if(length == 0 || length % 4 != 0)
            return null;
        //獲取字符串末尾的'='號數目
        int endEqualNum = 0;
        if(code.endsWith("=="))
            endEqualNum = 2;
        else if(code.endsWith("="))
            endEqualNum = 1;
        //對末尾的=號進行替換
        code.replace('=','0');
        StringBuilder sb = new StringBuilder(length);
        //解碼
        int blockNum = length / 4;
        String afterDecode = "";
        for(int i = 0;i < blockNum;i++){
            afterDecode = decodeDetail(code.substring(i * 4,i * 4 + 4));
            sb.append(afterDecode);
        }
        //返回字符串
        String result = sb.toString();
        return result.substring(0,result.length() - endEqualNum);
    }

    /**
     * 編碼
     * @param code
     * @return
     */
    public String encode(String code){
        //初始化判斷
        if (code == null || code.equals(""))
            return null;
        //獲取需編碼字符串的長度
        int length = code.length();
        StringBuilder sb = new StringBuilder(length * 2);
        //轉化爲char型數組
        char[] code1 = code.toCharArray();
        //獲取長度對3的取餘
        int mod = length % 3;
        //獲取長度對3的倍數的
        int div = length / 3;
        //編碼
        for(int i = 0;i < div;i++){
            int temp = i * 3;
            sb.append(encodeDetail(code1[temp],code1[temp + 1],code1[temp + 2]));
        }
        //對超出的進行額外的編碼
        if (mod == 1) {
            String str = encodeDetail(code1[length - 1], '\0', '\0');
            sb.append(str.substring(0,str.length() - 2) + "==");
        }
        if(mod == 2) {
            String str = encodeDetail(code1[length - 2], code1[length - 1], '\0');
            sb.append(str.substring(0,str.length() - 1) + "=");
        }
        return sb.toString();
    }

    /**
     * 編碼的詳細步驟
     * @param a1
     * @param a2
     * @param a3
     * @return
     */
    private String encodeDetail(char a1,char a2,char a3){
        char[] b = new char[4];
        b[0] = str[((a1 & 0xFC) >> 2)];
        b[1] = str[(a1 & 0x03) << 4 | (a2 & 0xF0) >> 4];
        b[2] = str[(a2 & 0x0F) << 2 | (a3 & 0xC0) >> 6];
        b[3] = str[(a3 & 0x3F)];
        return String.copyValueOf(b);
    }


    /**
     * 解碼的詳細步驟
     * @param str
     * @return
     */
    private String decodeDetail(String str){
        int len = str.length();
        if(len != 4)
            return null;
        char[] b = new char[3];
        int a1 = getIndex(str.charAt(0));
        int a2 = getIndex(str.charAt(1));
        int a3 = getIndex(str.charAt(2));
        int a4 = getIndex(str.charAt(3));
        b[0] = (char) (a1 << 2 | (a2 & 0x30) >> 4);
        b[1] = (char) ((a2 & 0x0F) << 4 | (a3 & 0x3C) >> 2);
        b[2] = (char) ((a3 & 0x03) << 6 | a4);
        return String.copyValueOf(b);
    }

    /**
     * 獲取字節的映射位置
     * @param c
     * @return
     */
    private int getIndex(char c){
        for(int i = 0;i < str.length;i++){
            if(str[i] == c)
                return i;
        }
        return -1;
    }

    /**
     * 獲取編碼器
     * @return
     */
    public static Base64Realize getEncoder(){
        return new Base64Realize();
    }
}

參考鏈接:https://bbs.pediy.com/thread-253433.htm

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章