單向散列函數(shù)(go語(yǔ)言實(shí)踐)

1. 單向散列函數(shù)的含義

單向散列函數(shù)(one-wayfunction)有一個(gè)輸入和一個(gè)輸出,其中輸入稱為消息(message),輸出稱為散列值 (hashvalue)。單向散列函數(shù)可以根據(jù)消息的內(nèi)容計(jì)算出散列值,而散列值就可以被用來(lái)檢查消息的完整性。

這里的消息不一定是人類能夠讀懂的文字,也可以是圖像文件或者聲音文件。單向散列函數(shù)不需要知道消息實(shí)
際代表的含義。無(wú)論任何消息,單向散列函數(shù)都會(huì)將它作為單純的比特序列來(lái)處理,即根據(jù)比特序列計(jì)算出散
列值。

散列值的長(zhǎng)度和消息的長(zhǎng)度無(wú)關(guān)。無(wú)論消息是1比特,還是100MB,甚至是IOOGB,單向散列函數(shù)都會(huì)計(jì)算出固 定長(zhǎng)度的散列值。以SHA-I單向散列函數(shù)為例,它所計(jì)算出的散列值的長(zhǎng)度永遠(yuǎn)是160比特(20字節(jié))。

單向散列函數(shù)的相關(guān)術(shù)語(yǔ)有很多變體,不同參考資料中所使用的術(shù)語(yǔ)也不同,下面我們就介紹其中的兒個(gè)。 單向散列函數(shù)也稱為消息摘要函數(shù)(message digest function)哈希函數(shù)或者雜湊函數(shù)。 輸入單向散列函數(shù)的消息也稱為 原像 (pre-image)

單向散列函數(shù)輸出的散列值也稱為消息摘要(message digest)或者指紋(fingerprint)。 完整性 也稱為一致性。

2. 單向散列函數(shù)的性質(zhì)

  • 根據(jù)任意長(zhǎng)度的消息計(jì)算出固定長(zhǎng)度的散列值
  • 能夠快速計(jì)算出散列值
  • 消息不同散列值也不同
  • 難以發(fā)現(xiàn)碰撞,稱為抗碰撞性
  • 備單向性,無(wú)法通過散列值反算出消息

3. 單向散列函數(shù)的實(shí)際應(yīng)用

  • 檢測(cè)軟件是否被篡改

  • 消息認(rèn)證碼
    消息認(rèn)證碼是將“發(fā)送者和接收者之間的共享密鑰”和“消息,進(jìn)行混合后計(jì)算出的散列值。使用消息認(rèn)證碼可以 檢測(cè)并防止通信過程中的錯(cuò)誤、篡改以及偽裝。
    消息認(rèn)證碼在SSL/TLS中也得到了運(yùn)用。

  • 數(shù)字簽名
    數(shù)字簽名是現(xiàn)實(shí)社會(huì)中的簽名(sign)和蓋章這樣的行為在數(shù)字世界中的實(shí)現(xiàn)。數(shù)字簽名的處理過程非常耗時(shí), 因此一般不會(huì)對(duì)整個(gè)消息內(nèi)容直接施加數(shù)字簽名,而是先通過單向散列函數(shù)計(jì)算出消息的散列值,然后再對(duì)這 個(gè)散列值施加數(shù)字簽名。

  • 偽隨機(jī)數(shù)生成器
    密碼技術(shù)中所使用的隨機(jī)數(shù)需要具備“事實(shí)上不可能根據(jù)過去的隨機(jī)數(shù)列預(yù)測(cè)未來(lái)的隨機(jī)數(shù)列”這樣的性質(zhì)。為 了保證不可預(yù)測(cè)性,可以利用單向散列函數(shù)的單向性。

  • 一次性口令
    一次性口令經(jīng)常被用于服務(wù)器對(duì)客戶端的合法性認(rèn)證。在這種方式中,通過使用單向散列函數(shù)可以保證口令只 在通信鏈路上傳送一次(one-time),因此即使竊聽者竊取了口令,也無(wú)法使用。

4. 常用的單向散列函數(shù)

4.1. MD4、MD5

MD4是由Rivest于1990年設(shè)計(jì)的單向散列函數(shù),能夠產(chǎn)生128比特的散列值(RFC1186,修訂版RFC1320)。不 過,隨著Dobbertin提出尋找MD4散列碰撞的方法,因此現(xiàn)在它已經(jīng)不安全了。

MD5是由Rwest于1991年設(shè)計(jì)的單項(xiàng)散列函數(shù),能夠產(chǎn)生128比特的散列值(RFC1321)。

MD5的強(qiáng)抗碰撞性已經(jīng)被攻破,也就是說(shuō),現(xiàn)在已經(jīng)能夠產(chǎn)生具備相同散列值的兩條不同的消息,因此它也已
經(jīng)不安全了。

MD4和MD5中的MD是消息摘要(Message Digest)的縮寫。

4.1.1 Go中使用MD5
func GetMD5ToHexStr(src []byte) string {
    result := md5.Sum(src)
    return hex.EncodeToString(result[:])
}

4.2. SHA-1、SHA-224、SHA-256、SHA-384、SHA-512

SHA-1是由NIST(NationalInstituteOfStandardsandTechnology,美國(guó)國(guó)家標(biāo)準(zhǔn)技術(shù)研究所)設(shè)計(jì)的一種能夠產(chǎn)生 160比特的散列值的單向散列函數(shù)。1993年被作為美國(guó)聯(lián)邦信息處理標(biāo)準(zhǔn)規(guī)格(FIPS PUB 180)發(fā)布的是 SHA,1995年發(fā)布的修訂版FIPS PUB 180-1稱為SHA-1。

SHA-1的消息長(zhǎng)度存在上限,但這個(gè)值接近于2^64比特,是個(gè)非常巨大的數(shù)值,因此在實(shí)際應(yīng)用中沒有問題。

SHA-256、SHA-384和SHA-512都是由NIST設(shè)計(jì)的單向散列函數(shù),它們的散列值長(zhǎng)度分別為256比特、384比特和
512比特。這些單向散列函數(shù)合起來(lái)統(tǒng)稱SHA-2,它們的消息長(zhǎng)度也存在上限(SHA-256的上限接近于 2^64 比特,
SHA-384 和 SHA-512的上限接近于 2^128 比特)。這些單向散列函數(shù)是于2002年和 SHA-1 一起作為 FIPS PUB 180-2 發(fā)布的 SHA-1 的強(qiáng)抗碰撞性已于2005年被攻破, 也就是說(shuō),現(xiàn)在已經(jīng)能夠產(chǎn)生具備相同散列值的兩條不同的消 息。不過,SHA-2還尚未被攻破。

4.2.1 Go中對(duì)SHA-1、SHA-2的使用
func GetHashFromBytes(src []byte, kHashType KHashType) (string, error) {
    result := []byte("")
    switch kHashType {
        case KHashTypeMd5:
            temp := md5.Sum(src)
            result = temp[:]
        case KHashTypeSha1:
            temp := sha1.Sum(src)
            result = temp[:]
        case KHashTypeSha256:
            temp := sha256.Sum256(src)
            result = temp[:]
        case KHashTypeSha512:
            temp := sha512.Sum512(src)
            result = temp[:]
    }
    if result == nil{
        return "", errors.New("ERROR:WRONG kHashType")
    }
    return hex.EncodeToString(result),nil
}

func GetHashFromFile(filename string, kHashType KHashType) (string, error) {
    // 打開文件
    file, err := os.Open(filename)
    if err != nil {
        return "", err
    }
    defer file.Close()

    hash := func() hash.Hash {
        switch kHashType {
        case KHashTypeMd5:
            return md5.New()
        case KHashTypeSha1:
            return sha1.New()
        case KHashTypeSha256:
            return sha256.New()
        case KHashTypeSha512:
            return sha512.New()
        default:
            return nil
        }
    }()

    if hash == nil {
        return "", errors.New("ERROR:WRONG kHashType")
    }

    // 將文件數(shù)據(jù)拷貝給哈希對(duì)象
    num, err := io.Copy(hash, file)
    if err != nil {
        return "", err
    }
    fmt.Println(num)

    return hex.EncodeToString(hash.Sum(nil)), nil

}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容