加密算法之對(duì)稱加密

加密算法簡(jiǎn)介

加密算法就是加密的方法敬尺,在密碼學(xué)中肢执,加密是將明文信息隱藏起來(lái)练慕,使之缺少特殊信息時(shí)不可讀惰匙。加密算法可以分為兩類:對(duì)稱加密和非對(duì)稱加密。

1. 對(duì)稱加密
將信息使用一個(gè)密鑰進(jìn)行加密铃将,解密時(shí)使用同樣的密鑰项鬼,同樣的算法進(jìn)行解密。

2. 非對(duì)稱加密
非對(duì)稱加密又稱公開(kāi)密鑰加密劲阎,密鑰分為私密密鑰和公開(kāi)密鑰绘盟,通過(guò)公鑰加密,私鑰解密的過(guò)程悯仙,并且加密和解密算法不同龄毡。

關(guān)于對(duì)稱加密

對(duì)稱加密是加密和解密雙方持有相同的私鑰,即加密方通過(guò)密鑰執(zhí)行加密過(guò)程锡垄,解密方通過(guò)相同的密鑰執(zhí)行解密過(guò)程沦零,因?yàn)殡p方持有相同的密鑰,所以叫做對(duì)稱加密货岭。同時(shí)路操,因?yàn)槊荑€理論上只有加解密雙方持有,所以也叫做私鑰加密千贯。常見(jiàn)的對(duì)稱加密算法有:DES屯仗,3DES,AES以及RC4等丈牢。

對(duì)稱加密分為序列密碼和分組密碼兩類祭钉,如下圖:

1. 序列密碼
序列密碼單獨(dú)加密每個(gè)位,它是通過(guò)將密鑰序列中的每個(gè)位 與每個(gè)明文位相加實(shí)現(xiàn)的己沛。同步序列密碼的密碼序列僅僅取決于密鑰慌核,而異步序列密碼序列則取決于密鑰和密文,如RC4申尼。

2. 分組密碼
分組密碼每次使用相同的密鑰加密整個(gè)明文位分組垮卓。這意味著對(duì)給定分組內(nèi)任何明文位的加密都依賴于與它同在一個(gè)分組內(nèi)的其他所有明文位。絕大多數(shù)分組密碼的分組長(zhǎng)度要么是128位(16字節(jié))师幕,比如AES粟按,要么是64位(8字節(jié))诬滩,比如DES和3DES。

對(duì)稱加密特點(diǎn)

  1. 算法可逆灭将,即加密后可以通過(guò)解密還原數(shù)據(jù)疼鸟。
  2. 加密效率高,加密速度快
  3. 安全性沒(méi)有非對(duì)稱加密高庙曙,因?yàn)槊荑€分發(fā)時(shí)存在安全隱患

對(duì)稱加密算法

在寫對(duì)稱加密算法之前空镜,有必要先提一下分組加密的操作模式有哪些,因?yàn)榉纸M加密是對(duì)稱加密中應(yīng)用最多的加密方式捌朴,并且可以有不同的操作模式吴攒。

分組加密模式

1. 電子密碼本模式(ECB)
ECB模式要求明文長(zhǎng)度必須是所使用密碼的分組大小的整數(shù)倍,比如在AES(后面會(huì)提到)中砂蔽,明文長(zhǎng)度應(yīng)該是16字節(jié)的整數(shù)倍洼怔,如果不滿足此長(zhǎng)度要求,則必須對(duì)其進(jìn)行填充左驾,填充的方式有很多種镣隶,比如:在明文后附加單個(gè)"1",然后再根據(jù)需要附加足夠多的"0"位什荣,直到明文的長(zhǎng)度達(dá)到分組長(zhǎng)度的整數(shù)倍矾缓,如果明文的長(zhǎng)度剛好是分組長(zhǎng)度的整數(shù)倍,則填充的所有位剛好形成了一個(gè)單獨(dú)的額外分組稻爬。ECB加密解密如下圖:

其中x_i表示明文分組嗜闻,e表示加密方法,k為密鑰桅锄,y_i表示密文分組琉雳,e^{-1}表示解密方法。假設(shè)分組密碼加密(解密)的分組大小為b位友瘤,長(zhǎng)度超過(guò)b位的消息將被分割為大小為b位的分組翠肘,如果消息長(zhǎng)度不是b位的整數(shù)倍,則在加密前必須將其填充位b位的整數(shù)倍辫秧。ECB模式中的每個(gè)分組都是單獨(dú)加密的束倍,
ECB優(yōu)缺點(diǎn):

  1. 加密和解密之間的分組同步不是必須的,即如果數(shù)據(jù)丟失盟戏,接收方還是可能解密已收到的分組绪妹。
  2. 加密高度確定,即只要密鑰不變柿究,相同的明文分組總是產(chǎn)生相同的密文分組邮旷。
  3. 明文分組的加密是完全獨(dú)立的,與前面的分組沒(méi)有任何關(guān)系蝇摸。如果攻擊者將密文分組重新排序婶肩,有可能會(huì)得到有效的明文办陷。
  4. 密碼分組鏈接模式(CBC)

2. 密碼分組鏈接模式(CBC)

CBC模式主要基于兩種思想。第一律歼,所有分組的加密都鏈接在一起民镜,是得密文y_i不僅依賴x_i,而且還依賴前面所有的明文分組苗膝。第二殃恒,加密過(guò)程使用的初始向量(IV)進(jìn)行了隨機(jī)化。

密文y_i是明文x_i加密后的結(jié)果辱揭,它將反饋為密碼輸入,并與后續(xù)明文分組x_{i+1}進(jìn)行異或操作病附,然后將得到的異或和進(jìn)行加密问窃,得到下一個(gè)密文y_{i+1},而這個(gè)密文將被用來(lái)加密x_{i+2}完沪,以此類推域庇。整個(gè)過(guò)程如下圖所示。

由于第一個(gè)明文分組x_1沒(méi)有前向密文覆积,所以將IV與第一個(gè)明文相加會(huì)使每輪的CBC加密變得不確定听皿。

注意:第一個(gè)密文y_1取決于明文x_1(和IV);第二個(gè)密文y_2則取決于IV宽档、x_1x_2尉姨;第三個(gè)明文取決于IV、x_1吗冤、x_2x_3又厉,以此類推。最后一個(gè)密文則是所有明文分組和IV的函數(shù)椎瘟。

3. 輸出反饋模式(OFB)

OFB模式使用分組密碼來(lái)構(gòu)建一個(gè)序列密鑰加密方案覆致。注意,在OFB模式中肺蔚,密鑰序列不是按位產(chǎn)生煌妈,而是以分組方式產(chǎn)生。密碼的輸出是b個(gè)密鑰序列位宣羊,其中b為所使用的分組密碼的寬度璧诵;將b為的明文與該b位的密鑰序列進(jìn)行異或操作即可實(shí)現(xiàn)對(duì)明文的加密。如下圖:

OFB模式首先使用分組密碼加密IV段只,得到的密鑰輸出為b位密鑰序列的第一個(gè)集合腮猖;將前一個(gè)密鑰輸出反饋給分組密碼進(jìn)行加密,即可計(jì)算出密鑰序列位的下一個(gè)分組赞枕;不斷重復(fù)此過(guò)程澈缺。
因?yàn)槭褂玫氖峭叫蛄忻艽a坪创,所以加密與解密操作完全相同,且加密解密位異或操作姐赡。OFB的一個(gè)優(yōu)點(diǎn)就是分組密碼的計(jì)算與明文無(wú)關(guān)莱预。因此,可以預(yù)計(jì)算密鑰序列材料的一個(gè)或多個(gè)分組S_i项滑。

4. 密碼反饋模式(CFB)

CFB模式也使用分組密碼作為構(gòu)建序列密碼的基本元件依沮,與OFB模式相同的是,CFB也使用了反饋枪狂;而不同的是危喉,OFB反饋的是分組密碼的輸出,而CFB反饋的是密文州疾。OFB的基本思想是:要生成第一個(gè)密鑰序列分組S_1辜限,必須先加密IV;而所有后續(xù)密鑰序列分組S2严蓖,S_3薄嫡,...都是通過(guò)加密前一個(gè)密文得到的。如下圖所示:

根據(jù)序列密碼加密颗胡,CFB加密解密操作也完全相同毫深,但CFB模式是一個(gè)異步序列密鑰加密

5. 計(jì)數(shù)器模式(CTR)

與OFB和CFB模式一樣,密鑰序列也是以分組方式計(jì)算的毒姨。分組密碼的輸入為一個(gè)計(jì)數(shù)器哑蔫,每當(dāng)分組密碼計(jì)算一個(gè)新密鑰序列分組時(shí),該計(jì)數(shù)器都會(huì)產(chǎn)生一個(gè)不同的值手素,如下圖所示:

初始化分組密碼的輸入時(shí)必須避免兩次使用相同過(guò)的輸入值鸳址,如果攻擊者知道了使用相同輸入加密的明文中的任何一個(gè),就可以計(jì)算出密鑰序列分組泉懦,從而可以解密其他明文稿黍。計(jì)數(shù)器模式最大的特點(diǎn)就是并行化,因?yàn)橛?jì)數(shù)器模式不需要任何反饋崩哩。加入有兩個(gè)分組加密引擎巡球,即可以讓兩個(gè)引擎同時(shí)使用第一個(gè)分組密碼加密計(jì)數(shù)器值TRC_1CTR_2,這兩個(gè)分組密碼引擎完成后邓嘹,一個(gè)繼續(xù)加密CTR_3酣栈,而另一個(gè)則加密CTR_4

6. 伽羅瓦計(jì)數(shù)器模式(GCM)

GCM是一種計(jì)算消息驗(yàn)證碼的加密模式汹押。MAC(消息驗(yàn)證碼)由發(fā)送者計(jì)算密碼校驗(yàn)和矿筝,并附加在消息后面,接收方也會(huì)計(jì)算此消息的密碼校驗(yàn)和棚贾,并校驗(yàn)與發(fā)送者發(fā)送過(guò)來(lái)的是否相同窖维,這樣便可以確認(rèn)消失是否是發(fā)送者發(fā)送過(guò)來(lái)的榆综,且密文是否有被修改過(guò)。

主流對(duì)稱加密算法實(shí)現(xiàn)(Go語(yǔ)言)

下面將逐一介紹上面提到的對(duì)稱加密的算法實(shí)現(xiàn)铸史。

1. RC4

RC4為流加密算法鼻疮,即前面提到的序列加密,由偽隨機(jī)數(shù)生成器和異或運(yùn)算組成琳轿,密鑰長(zhǎng)度可變判沟,范圍在[1,255]。RC4一個(gè)字節(jié)一個(gè)字節(jié)地加解密崭篡,由于采用的是異或運(yùn)算挪哄,使用的是同一套算法。

func Encrypt(bytes []byte, key []byte) ([]byte, error) {
    c, err := rc4.NewCipher(key)
    if err != nil {
        return nil, err
    }
    var dst = make([]byte, len(bytes))
    c.XORKeyStream(dst, bytes)
    return dst, nil
}

//RC4為序列密碼加密琉闪,采用異或運(yùn)算中燥,所以此處直接調(diào)用解密算法
func Decrypt(encryptData, key []byte) ([]byte, error) {
    return Encrypt(encryptData, key)
}

2. DES(3DES)

DES是一種使用56位(7字節(jié))(注:其實(shí)DES的輸入密鑰是64位(8字節(jié)),但是每個(gè)字節(jié)的第8位都作為前面7位的一個(gè)奇校驗(yàn)位塘偎,所以實(shí)際密鑰有效位為56位。)密鑰對(duì)64位(8字節(jié))長(zhǎng)分組進(jìn)行加密的算法拿霉,加吟秩、解密過(guò)程使用相同對(duì)密鑰。

DES算法機(jī)制為迭代绽淘,一共16輪涵防,每輪操作完全相同,但使用不同的子密鑰沪铭,子密鑰都是由主密鑰推導(dǎo)而來(lái)的壮池,都是從輸入密鑰中選擇48個(gè)置換位。DES加密流程如下:

3DES即為三重DES加密杀怠,3DES加密密鑰長(zhǎng)度為192位(24字節(jié))椰憋。

解密過(guò)程主要為密鑰編排逆轉(zhuǎn),即解密的第一輪需要子密鑰16赔退;第二輪需要子密鑰15橙依;以此類推。

func Encrypt(plainText []byte, key []byte) ([]byte, error) {
    //block, err := des.NewTripleDESCipher(key)為三重DES加密
    block, err := des.NewCipher(key)
    if err != nil {
        return nil, err
    }

    blockSize := block.BlockSize()                     //分組大小
    plainText = paddingWithPKCS5(plainText, blockSize) //填充

    var cipherText = make([]byte, len(plainText))

    //ECB每個(gè)分組單獨(dú)加密
    var temp = cipherText
    for len(plainText) > 0 {
        block.Encrypt(temp, plainText[:blockSize])
        plainText = plainText[blockSize:]
        temp = temp[blockSize:]
    }
    return cipherText, nil
}

func Decrypt(cipherText []byte, key []byte) ([]byte, error) {
    //block, err := des.NewTripleDESCipher(key)為三重DES加密
    block, err := des.NewCipher(key)
    if err != nil {
        return nil, err
    }

    blockSize := block.BlockSize() //分組大小

    var plainText = make([]byte, len(cipherText))

    //ECB每個(gè)分組單獨(dú)加密
    var temp = plainText
    for len(cipherText) > 0 {
        block.Decrypt(temp, cipherText[:blockSize])
        cipherText = cipherText[blockSize:]
        temp = temp[blockSize:]
    }
    plainText = unPaddingWithPKCS5(plainText)
    return plainText, nil
}

func paddingWithPKCS5(data []byte, blockSize int) []byte {
    //需要填充的值以及數(shù)量
    padding := blockSize - len(data)%blockSize
    //組裝填充值([]byte)
    var paddingData = []byte{byte(padding)}
    paddingData = bytes.Repeat(paddingData, padding)
    //append填充
    data = append(data, paddingData...)
    return data
}

func unPaddingWithPKCS5(data []byte) []byte {
    padding := int(data[len(data)-1])
    return data[:len(data)-padding]
}

3. AES

AES擁有三種不同的密鑰長(zhǎng)度抵抗蠻力攻擊硕旗,分別為128位窗骑,192位和256位,分組大小為128位漆枚。

func Encrypt(plainText []byte, key []byte) ([]byte, error) {
    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, err
    }

    blockSize := block.BlockSize()                     //分組大小
    plainText = paddingWithPKCS5(plainText, blockSize) //填充

    var cipherText = make([]byte, len(plainText))

    //CBC模式
    blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
    blockMode.CryptBlocks(cipherText,plainText)
    return cipherText, nil
}

func Decrypt(cipherText []byte, key []byte) ([]byte, error) {
    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, err
    }

    blockSize := block.BlockSize() //分組大小

    var plainText = make([]byte, len(cipherText))

    //CBC模式
    blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
    blockMode.CryptBlocks(plainText, cipherText)

    plainText = unPaddingWithPKCS5(plainText)

    return plainText, nil
}

引用資料

《維基百科》
《深入淺出密碼學(xué)——常用加密技術(shù)原理與應(yīng)用》

最后

原文鏈接
如有錯(cuò)誤创译,請(qǐng)不吝賜教!
Thanks!
附上代碼鏈接[github.com/pyihe/secret]

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末墙基,一起剝皮案震驚了整個(gè)濱河市软族,隨后出現(xiàn)的幾起案子刷喜,更是在濱河造成了極大的恐慌,老刑警劉巖互订,帶你破解...
    沈念sama閱讀 218,640評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吱肌,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡仰禽,警方通過(guò)查閱死者的電腦和手機(jī)氮墨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)吐葵,“玉大人规揪,你說(shuō)我怎么就攤上這事∥虑停” “怎么了猛铅?”我有些...
    開(kāi)封第一講書人閱讀 165,011評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)凤藏。 經(jīng)常有香客問(wèn)我奸忽,道長(zhǎng),這世上最難降的妖魔是什么揖庄? 我笑而不...
    開(kāi)封第一講書人閱讀 58,755評(píng)論 1 294
  • 正文 為了忘掉前任栗菜,我火速辦了婚禮,結(jié)果婚禮上蹄梢,老公的妹妹穿的比我還像新娘疙筹。我一直安慰自己,他們只是感情好禁炒,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布而咆。 她就那樣靜靜地躺著,像睡著了一般幕袱。 火紅的嫁衣襯著肌膚如雪暴备。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,610評(píng)論 1 305
  • 那天凹蜂,我揣著相機(jī)與錄音馍驯,去河邊找鬼。 笑死玛痊,一個(gè)胖子當(dāng)著我的面吹牛汰瘫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播擂煞,決...
    沈念sama閱讀 40,352評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼混弥,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起蝗拿,我...
    開(kāi)封第一講書人閱讀 39,257評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤晾捏,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后哀托,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體惦辛,經(jīng)...
    沈念sama閱讀 45,717評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評(píng)論 3 336
  • 正文 我和宋清朗相戀三年仓手,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了胖齐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,021評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嗽冒,死狀恐怖呀伙,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情添坊,我是刑警寧澤剿另,帶...
    沈念sama閱讀 35,735評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站贬蛙,受9級(jí)特大地震影響雨女,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜阳准,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評(píng)論 3 330
  • 文/蒙蒙 一戚篙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧溺职,春花似錦、人聲如沸位喂。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,936評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)塑崖。三九已至七冲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間规婆,已是汗流浹背澜躺。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,054評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留抒蚜,地道東北人掘鄙。 一個(gè)月前我還...
    沈念sama閱讀 48,224評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像嗡髓,于是被迫代替她去往敵國(guó)和親操漠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評(píng)論 2 355