天天看點

密碼算法原理與實作:Base64編碼文章概述:Base64簡介:Base64的編碼原理:Base64的編碼圖解:Base64核心代碼講解(C語言):本篇總結:代碼實作

本文轉自網絡文章,内容均為非盈利,版權歸原作者所有。

轉載此文章僅為個人收藏,分享知識,如有侵權,馬上删除。

原文作者:QiuJYu

原文位址:密碼學基礎:Base64編碼

目錄

文章概述:

Base64簡介:

Base64的編碼原理:

Base64的編碼圖解:

Base64核心代碼講解(C語言):

Base64加密部分:

Base64解密部分:

本篇總結:

代碼實作

文章概述:

  • 本文目的:寫這篇文章的目的主要是整理下密碼學中Base64的知識點,并把它們分享出來。并且幫助初探密碼學的壇友們一步一步的用C語言将Base64的編碼實作出來。
  • 閱讀方法:希望大家在浏覽完本片文章後可以自己去實作一下,相信一定會對你的程式設計技術有所提高。(附件中提供參考代碼)
  • 具備基礎:

    (1)熟練掌握C語言

  • 學習環境:任意C語言開發環境, Base64加解密工具

Base64簡介:

  雖然這篇文章釋出在密碼算法區,但希望大家不要誤解,Base64并不是一種加密的方法,而是一種編碼的方式。雖然用Base64加密(暫且說是加密)的字元串看起來有一種被加密的感覺,但是這隻是感覺。因為如果用标準的Base64進行加密會發現很多Base64的特征,比如在Base64字元串中會出現'+'和'\'兩種字元,在字元串的末尾經常會有一個到兩個連續的'='。隻要發現了這些特征,就可以肯定這個字元串被Base64加密過,隻要通過相應的解密小程式就可以輕松得到加密前的樣子(非标準的除外)。

  那麼有為什麼說Base64是一中編碼方式呢?這是因為Base64可以把所有的二進制資料都轉換成ASCII碼可列印字元串的形式。以便在隻支援文本的環境中也能夠順利地傳輸二進制資料。當然有時在CTF的題目中摻雜上非标準的Base64編碼表也會有加密的效果,但是如果找到這個表那就程式設計明文了,是以在CTF題目中隻會起到輔助的作用。

Base64的編碼原理:

  Base64編碼的核心原理是将二進制資料進行分組,每24Bit(3位元組)為一個大組,再把一個大組的資料分成4個6Bit的小分組。由于6Bit資料隻能表示64個不同的字元(2^6=64),是以這也是Base64的名字由來。這64個字元分别對應ASCII碼表中的'A'-'Z','a'-'z','0''9','+'和'/'。他們的對應關系是由Base64字元集決定的。因為小分組中的6Bit資料表示起來并不友善,是以要把每個小分組進行高位補零操作,這樣每個小分組就構成了一個8Bit(位元組)的資料。在補零操作完成後接下來的工作就簡單多了,那就是将小分組的内容作為Base64字元集的下标,然後一一替換成對應的ASCII字元。加密工作完成。

  Base64解密的工作原理也非常的簡單,隻要操作方式和加密步驟相反即可。首先将Base64編碼根據其對應的字元集轉換成下标,這就是補完零後的8Bit(一位元組)資料。既然有補零操作那自然會有去零操作了,我們要将這些8Bit資料的最高位上的兩個0抹去形成6Bit資料,這也就是前面我們提到過的小分組。最後就是将每4個6Bit資料進行合并形成24Bit的大分組,然後将這些大分組按照每組8Bit進行拆分就會得到3個8Bit的資料,這寫8Bit資料就是加密前的資料了。解密工作完成。

  重點:别看前面說的Base64工作流程這麼簡單,實際上裡面還是有很多坑的,那在我們了解了編碼原理後現在就來填坑了:

  我們在Base64編碼前是無法保證準備編碼的字元串長度是3的倍數,是以為了讓編碼能夠順利進行就必須在擷取編碼字元串的同時判斷字元串的長度是否是3的倍數,如果是3的倍數編碼就可以正常進行,如果不是那麼就要進行額外的操作——補零,就是要在不足3的倍數的字元串末尾用0x00進行填充。

  這樣就是解決了字元串長度不足的問題了,但是同時也引進了另一個新的問題,那就是末尾補充上的0在進行Base64字元集替換的時候會與字元集中的'A'字元發生沖突。因為字元集中的下标0對應的字元是'A',而末尾填充上的0x00在分組補零後同樣是下标0x00,這樣就無法分辨出到底是末尾填充的0x00還是二進制資料中的0x00。為了解決這個問題我們就必須引入Base64字元集外的新字元來區分末尾補充上的0x00,這就是'='字元不在Base64字元集中,但是也出現在Base64編碼的原因了,'='字元在一個Base64編碼的末尾中最多會出現兩個,如果不符合這以規則那麼這個Base64就可能被人做了手腳。

Base64字元集:

密碼算法原理與實作:Base64編碼文章概述:Base64簡介:Base64的編碼原理:Base64的編碼圖解:Base64核心代碼講解(C語言):本篇總結:代碼實作

Base64的編碼圖解:

我們以輸入字元串"6666"為例:  

1、判斷字元串長度,不足3的倍數用0x00填充:

密碼算法原理與實作:Base64編碼文章概述:Base64簡介:Base64的編碼原理:Base64的編碼圖解:Base64核心代碼講解(C語言):本篇總結:代碼實作

2、将補零後的字元串進行8Bit分組:

密碼算法原理與實作:Base64編碼文章概述:Base64簡介:Base64的編碼原理:Base64的編碼圖解:Base64核心代碼講解(C語言):本篇總結:代碼實作

3、把每個大分組進行6Bit分組:

密碼算法原理與實作:Base64編碼文章概述:Base64簡介:Base64的編碼原理:Base64的編碼圖解:Base64核心代碼講解(C語言):本篇總結:代碼實作

4、将6Bit組轉換成Base64字元集的下标:

(注:由于是進行圖檔解說,是以省區了6Bit組高位補零操作!)

密碼算法原理與實作:Base64編碼文章概述:Base64簡介:Base64的編碼原理:Base64的編碼圖解:Base64核心代碼講解(C語言):本篇總結:代碼實作

5、把字元集的下标替換成Base64字元:

密碼算法原理與實作:Base64編碼文章概述:Base64簡介:Base64的編碼原理:Base64的編碼圖解:Base64核心代碼講解(C語言):本篇總結:代碼實作

6、修正末尾的符号,得到Base64編碼結果

密碼算法原理與實作:Base64編碼文章概述:Base64簡介:Base64的編碼原理:Base64的編碼圖解:Base64核心代碼講解(C語言):本篇總結:代碼實作

解密操作和加密操作相反!

Base64核心代碼講解(C語言):

Base64加密部分:

1、将長度補全後的字元串轉換成6Bit分組:

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;
}
           

  這一段代碼的功能是将已經補足長度的16進制資料轉變成6Bit分組,每一個分組用8Bit(一個位元組)表示,是以也就自動完成了6Bit組的高位補零操作。這裡用到了一個for循環,其目的是為了達到前面所說的分組,這裡分了兩個部分,一部分是将16進制資料分成一個3*8Bit的大分組,另一部分是将大分組中的資料分割成4*6Bit的小分組,分割的過程用到了很多位操作,大大降低了分組的複雜性,隻不過需要注意運算法的優先級。

  語句剖析:

  SixBitGroup[i] = ((BitPlainText[j] & 0xFC) >> 2); //在3*8Bit資料中的第一個資料取6Bit内容右移兩位得到第一個6Bit資料。

密碼算法原理與實作:Base64編碼文章概述:Base64簡介:Base64的編碼原理:Base64的編碼圖解:Base64核心代碼講解(C語言):本篇總結:代碼實作

  SixBitGroup[i + 1] = ((BitPlainText[j] & 0x03) << 4) + ((BitPlainText[j + 1] & 0xF0) >> 4);//在3*8Bit資料中的第一個資料取2Bit内容後左移4位,加上3*8Bit資料中的第二個資料取4Bit資料構成第二個6Bit資料。

密碼算法原理與實作:Base64編碼文章概述:Base64簡介:Base64的編碼原理:Base64的編碼圖解:Base64核心代碼講解(C語言):本篇總結:代碼實作

  SixBitGroup[i + 2] = ((BitPlainText[j + 1] & 0x0F) << 2) + ((BitPlainText[j + 2] & 0xC0) >> 6);//在3*8Bit資料中的第二個資料取4Bit内容後左移2位,加上3*8Bit資料中的第三個資料取2Bit資料右移6位構成第三個6Bit資料。

密碼算法原理與實作:Base64編碼文章概述:Base64簡介:Base64的編碼原理:Base64的編碼圖解:Base64核心代碼講解(C語言):本篇總結:代碼實作

  SixBitGroup[i + 3] = (BitPlainText[j + 2] & 0x3F);//在3*8Bit資料中的第三個資料取6Bit資料得到最後一個6Bit資料。

密碼算法原理與實作:Base64編碼文章概述:Base64簡介:Base64的編碼原理:Base64的編碼圖解:Base64核心代碼講解(C語言):本篇總結:代碼實作

2、根據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;
}
           

  通過第一步的處理,我們得到了Base64的高位補零後的6Bit分組也就是Base64字元集的下标。通過下标擷取Base64字元集中的内容也就非常簡單了,利用for循環進行查表指派操作就可以初步得到Base64的編碼值了。

3、将初步得到Base64的編碼值末尾補充的字元轉換成'=':

unsigned int            NumberOfEqual;          //填充後等号最大個數  
 
//填充一個位元組的最多會産生一個 '=', 填充兩個位元組的最多會産生兩個 '='
if (strlen(PlainText) % 3)    //不是3的倍數
{
    NumberOfEqual       = 3 - (strlen(PlainText) % 3); 
}
else    //是3的倍數
{
    NumberOfEqual       = 0;
}
 
for (int i = SixBitGroupSize - 1; i >= SixBitGroupSize - NumberOfEqual; i--)
{
    if (CipherGroup[i] == 'A')
    {
        CipherGroup[i] = '=';
    }
}
           

  因為填充一個位元組的最多會産生一個 '=', 填充兩個位元組的最多會産生兩個 '=',是以判斷條件為i > SixBitGroupSize-NumberOfEqual,并且在循環中判斷末尾是否是補充字元。經過這一過程,也就擷取了Base64加密後的結果。加密完成!

Base64解密部分:

1、将Base64密文轉換成Base64下标:

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;
}
           

  由于Base64字元串是用ASCII碼表示的,是以要想擷取其對應的索引号就需要減去每一段ASCII第一個字元後加上相應的偏移,最後應該注意的是不要忘記還有一個不在Base64字元集的字元。

2、将Base64下标(6Bit組)轉換為明文字元串的8Bit組形式

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;
}
           

  這裡進行的位操作有點不容易了解,但是它的作用就是把4*6Bit組中高位填充的0x00去掉後合并成3*8Bit的明文資料。需要留心下位操作的運算符優先級和處理的資料位。最後得到的結果就是16進制資料了。解密完成!

  語句剖析:

  BitPlainText[i] = (Base64Index[j] << 2) + ((Base64Index[j + 1] & 0xF0) >> 4);//将第一個4*6Bit組資料左移2位去除高位補的0x00得到6個有效Bit位,從第二個4*6Bit組取得4Bit資料右移4位(包含兩個有效位),兩個部分相加得到第一個3*8Bit組資料。

密碼算法原理與實作:Base64編碼文章概述:Base64簡介:Base64的編碼原理:Base64的編碼圖解:Base64核心代碼講解(C語言):本篇總結:代碼實作

  BitPlainText[i + 1] = ((Base64Index[j + 1] & 0x0F) << 4) + ((Base64Index[j + 2] & 0x3C) >> 2);//從第二個4*6Bit組取得4Bit資料左移4位得到4個有效Bit位,從第三個4*6Bit組取得6Bit資料右移2位得到4個有效Bit位,兩個部分相加得到第二個3*8Bit組資料。

密碼算法原理與實作:Base64編碼文章概述:Base64簡介:Base64的編碼原理:Base64的編碼圖解:Base64核心代碼講解(C語言):本篇總結:代碼實作

  BitPlainText[i + 2] = ((Base64Index[j + 2] & 0x03) << 6) + Base64Index[j + 3];//從第三個4*6Bit組取得2Bit資料左移6位得到2個有效Bit位,從第四個4*6Bit組取得8Bit資料得到6個有效Bit位,兩個部分相加得到第三個3*8Bit組資料。

密碼算法原理與實作:Base64編碼文章概述:Base64簡介:Base64的編碼原理:Base64的編碼圖解:Base64核心代碼講解(C語言):本篇總結:代碼實作

本篇總結:

  寫到這裡,我對Base64算法的了解也就分享完了。其實Base64的原理非常簡單,但是實作它的過程卻十分的有意思,它展現了C語言中位操作的魅力。我感覺隻有對位操作有着深入的了解,才能更好的進行密碼學的學習。

代碼實作

實作代碼,請檢視

不知道是為什麼在核心代碼講解部分,完全不知道要寫些什麼。。。。

繼續閱讀