G8.3 實(shí)現(xiàn)不可逆加密 - 用Go語(yǔ)言 Golang實(shí)現(xiàn)

前兩節(jié)介紹的加密方法都屬于“可逆”的加密算法,因?yàn)榧用芎蟮拿芪慕?jīng)過(guò)解密的過(guò)程就可以還原出原文。還有一類加密算法屬于“不可逆”的加密算法,是指一般無(wú)法進(jìn)行正常解密還原出原文的加密算法。


不可逆加密算法的應(yīng)用場(chǎng)景也有很多,最典型的是服務(wù)端保存用戶登錄密碼的方式。從保護(hù)用戶隱私角度考慮,服務(wù)器端不應(yīng)該存儲(chǔ)用戶的登錄密碼原文,也不應(yīng)該保存可逆加密后的密文(因?yàn)橐部梢员唤饷苓€原),這時(shí)候?qū)嵺`中常用的方法是在服務(wù)器保存密碼時(shí)將其用不可逆的算法轉(zhuǎn)換成密文存儲(chǔ),下次用戶登錄時(shí)服務(wù)器將發(fā)來(lái)的用戶密碼以同樣的不可逆算法加密后再與保存的密碼密文做比對(duì)來(lái)判斷是否相同。


從這個(gè)例子也可以看出,不可逆加密算法一般要滿足這個(gè)要求:同樣的明文用同樣的方式加密后,得到的密文必須是一樣,否則就無(wú)法用于比對(duì)了。


最簡(jiǎn)單的不可逆加密算法可能就是取模算法了,例如18 % 5 的結(jié)果是3,而23 % 5的結(jié)果也是3,如果18和23代表明文,“% 5”這個(gè)取模操作(也就是求對(duì)于5的余數(shù))代表加密算法,3代表加密后的密文,那么顯然這個(gè)加密算法是不可逆的,因?yàn)閺拿芪摹?”無(wú)法確定原文是18還是23(甚至還可能是其他更多的數(shù)字),而任何數(shù)字對(duì)5取模的結(jié)果都是不變的。那么該算法如果用于對(duì)密碼加密,可以將密碼轉(zhuǎn)換后的字節(jié)切片中的每個(gè)字節(jié)數(shù)值對(duì)5取模后形成新的密文字節(jié)切片,服務(wù)器端保存這個(gè)密文就可以了,以后用戶登錄時(shí)傳上來(lái)的密碼做同樣的加密操作,得到的結(jié)果與保存的密文應(yīng)該是一致的。


當(dāng)然,取模操作作為加密方法來(lái)說(shuō)加密強(qiáng)度太低,實(shí)際應(yīng)用中用的最多的不可逆加密算法是MD5算法,該算法應(yīng)用了散列函數(shù)的原理,可以將任何數(shù)據(jù)轉(zhuǎn)換成固定長(zhǎng)度的字節(jié)序列(一般是16個(gè)字節(jié)),并且與取模操作一樣具有原文對(duì)應(yīng)到密文的唯一性。


取模操作也可以看做散列函數(shù)的一種,可以將任何數(shù)據(jù)散列到[0, n)的范圍內(nèi)(n是取模的模數(shù))。散列函數(shù)一般都具備這樣的特性:原始數(shù)據(jù)與散列后的數(shù)據(jù)是多對(duì)一的關(guān)系,即同樣的原始數(shù)據(jù)用同樣的散列函數(shù)處理后必然得到同樣的結(jié)果,但同樣的結(jié)果不一定對(duì)應(yīng)同一個(gè)原始數(shù)據(jù)。這也是為什么大多數(shù)不可逆算法使用散列函數(shù)作為核心方法的原因。


下面的代碼演示了如何使用Go語(yǔ)言中的crypto/md5等包來(lái)實(shí)現(xiàn)MD5加密算法。


package main


import (

? "crypto/md5"

? "encoding/hex"

? "io"

? "log"

? "os"

? "strings"

? t "github.com/topxeq/goexamples/tools"

)


func main() {


? //原始字符串

? originalTextT := "測(cè)試字符串"


? //對(duì)原始字符串生成md5碼,md5BytesArrayT是[16]byte類型的數(shù)組

? md5BytesArrayT :=md5.Sum([]byte(originalTextT))


? //將數(shù)組轉(zhuǎn)換為切片

? md5BytesT := md5BytesArrayT[:]


? t.Printfln("md5字節(jié)切片(16個(gè)字節(jié)): %#v", md5BytesT)


? //將md5字節(jié)切片轉(zhuǎn)換為16進(jìn)制的文本,將有32個(gè)字符

? //并轉(zhuǎn)換為全大寫字母

? md5TextT := strings.ToUpper(hex.EncodeToString(md5BytesT))


? t.Printfln("md5文本(32位): %#v", md5TextT)


? //用流式方法對(duì)字符串進(jìn)行md5編碼

? md5Encoder := md5.New()


? //向md5Encoder中寫入字符串

? io.WriteString(md5Encoder, originalTextT)


? //調(diào)用Sum函數(shù)進(jìn)行md5編碼,并轉(zhuǎn)換為十六進(jìn)制字符串

? md5TextT = hex.EncodeToString(md5Encoder.Sum(nil))


? t.Printfln("流式編碼的md5文本(小寫): %#v", md5TextT)


? //直接用流式方法對(duì)一個(gè)文件進(jìn)行md5編碼

? fileT, errT := os.Open(`c:\test\long.txt`)


? if errT != nil {

?????? log.Fatal(errT)

? }


? defer fileT.Close()


? md5Encoder = md5.New()


? //帶有初始化語(yǔ)句的條件判斷

? if _, errT = io.Copy(md5Encoder, fileT); errT!= nil {

?????? log.Fatal(errT)

? }


? t.Printfln("文件的md5碼:%x", md5Encoder.Sum(nil))

}

代碼 14?3 MD5加密示例


代碼14?3中已經(jīng)有詳盡的解釋,再附加幾點(diǎn)解釋如下:


-> 代碼中用到的md5包中的函數(shù)最主要的是md5.Sum函數(shù),該函數(shù)實(shí)現(xiàn)了將任意一個(gè)字節(jié)切片編碼為MD5,編碼結(jié)果的數(shù)據(jù)類型是[16]byte,即16個(gè)字節(jié)的字節(jié)數(shù)組;

->?由于字節(jié)數(shù)組與字節(jié)切片并不是同一個(gè)類型,所以還需要進(jìn)行轉(zhuǎn)換,將[16]byte類型的數(shù)據(jù)轉(zhuǎn)換為[]byte類型才能符合后面hex.EncodeToString等函數(shù)的傳入?yún)?shù)類型要求;

->?目前一般使用時(shí)都是用MD碼的十六進(jìn)制文本形式,這會(huì)有32個(gè)字符長(zhǎng)度;

->?代碼后面也演示了如何用流式方法來(lái)直接編碼一個(gè)字符串為MD碼以及直接編碼一個(gè)文件;md5.New函數(shù)將新建一個(gè)MD5的編碼器(hash.Hash類型),該編碼器支持流式寫入,寫入完所有內(nèi)容后,調(diào)用該編碼器的Sum函數(shù)就會(huì)進(jìn)行MD5編碼;


代碼14?3的運(yùn)行結(jié)果是:


md5字節(jié)切片(16個(gè)字節(jié)): []byte{0x1f, 0x3c, 0xa0, 0x51, 0x2, 0x8d, 0x1d, 0x1e, 0x95, 0xa6, 0xf4, 0xe2, 0x69, 0xd7, 0x27, 0xab}

md5文本(32位): "1F3CA051028D1D1E95A6F4E269D727AB"

流式編碼的md5文本(小寫): "1f3ca051028d1d1e95a6f4e269d727ab"

文件的md5碼:9da81dede7a381a6d9fecc0cd69a81a9


可以看出,無(wú)論使用普通方式還是流式方式進(jìn)行MD5編碼,對(duì)同樣的輸入字符串的結(jié)果都是一樣的(注意,十六進(jìn)制文本的大小寫一般在各個(gè)系統(tǒng)中都可以識(shí)別,目前的趨勢(shì)更多的是使用小寫形式)。


類似MD5這樣的不可逆加密,也不需要使用密碼就可以直接進(jìn)行加密。


最后順便提一下,任何加密理論上都可以被破解,即使是不可逆的加密算法也是有辦法破解的。MD5的破解方法已經(jīng)在網(wǎng)絡(luò)上有所流傳,實(shí)質(zhì)上是窮舉法的破解方式,就是不停地收集和計(jì)算各種明文的MD5編碼并將這兩者的成對(duì)保存起來(lái),然后根據(jù)保存的海量數(shù)據(jù),對(duì)MD5密文進(jìn)行反查,這需要大量的積累,消耗的資源也較大,查出來(lái)的結(jié)果也可能是多個(gè)(MD5的密文與明文是一對(duì)多的關(guān)系),但確實(shí)也算是一種方法,在此說(shuō)明一下供大家了解。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容