雜湊函式(Hash Functions - 雜湊函式)的基本介紹(SHA-2,SHA-256,MD-5,Scrypt,BCrypt等)

rtoax發表於2020-10-11

Table of Contents

雜湊函式的基本介紹(SHA-256,MD-5等)

為什麼要使用雜湊函式?

確定性地加擾資料

輸入無關緊要,輸出大小相同

它們如何工作?

免責宣告

什麼是MD5雜湊?

SHA-2的工作原理(SHA-256)

什麼是雜湊函式?

SHA-2和SHA-256

SHA-256“ hello world”;步驟1 –預處理

步驟2 –初始化雜湊值(h)

步驟3 –初始化舍入常數(k)

步驟4 –區塊迴圈

步驟5 –建立郵件時間表(w)

步驟6 –壓縮

步驟7 –修改最終值

第8步-連線最終雜湊

偽碼

Scrypt雜湊的基本介紹

什麼是Scrypt?

為什麼不使用密碼直接加密?

加密屬性

什麼是BCrypt?

OWASP - 開放式Web應用程式安全專案

相關文章


 

Hash,一般翻譯做雜湊、雜湊,或音譯為雜湊,是把任意長度的輸入(又叫做預對映pre-image)通過雜湊演算法變換成固定長度的輸出,該輸出就是雜湊值。這種轉換是一種壓縮對映,也就是,雜湊值的空間通常遠小於輸入的空間,不同的輸入可能會雜湊成相同的輸出,所以不可能從雜湊值來確定唯一的輸入值。簡單的說就是一種將任意長度的訊息壓縮到某一固定長度的訊息摘要的函式。

雜湊函式根據選擇的演算法返回輸入資料的128位,160位,256位或512位雜湊。

表示要雜湊的字串值的表示式。該表示式可以返回任何內建或不同的資料型別。唯一型別被視為其源資料型別。如果值為數字或日期時間,則在評估函式之前,將其隱式轉換為VARCHAR。如果值為XML,則在對函式求值之前執行隱式的XMLSERIALIZE到CLOB(2G)CCSID 1208。

表1.雜湊演算法
功能名稱演算法結果大小返回值數結果長度HASH函式中使用的對應演算法值
HASH_MD5MD5128位2^128160
HASH_SHA1SHA1160位2^160201
HASH_SHA256SHA-256256位2^256322
HASH_SHA512SHA-512512位2^512643

空格會影響雜湊;帶有尾隨空格的固定長度字串將產生與沒有尾隨空格的可變長度字串不同的結果。表示式的CCSID 可以使比較相等的字串生成不同的結果值。

SHA1和MD5演算法均已發現安全漏洞。您可以在適用的法規遵從性文件中找到可接受的雜湊演算法,例如美國國家標準技術研究院(NIST)特殊出版物800-131A。

語法替代:具有單個引數的HASH函式類似於HASH_MD5。可以為HASH指定第二個引數,以指示要使用的演算法。演算法值顯示在表1中。第二個引數可以是一個表示式,該表示式必須返回任何內建數字,字串或圖形字串資料型別的值。在評估函式之前,將字串引數轉換為整數。HASH的結果資料型別為VARBINARY。如果只有一個引數,則結果的length屬性為16。如果第二個引數由整數常量指定,則結果的length屬性為表1中所示的結果長度。。否則,結果的length屬性為64。如果任一引數可以為null,則結果可以為null。如果任何一個引數為null,則結果為null值。

例子

使用MD5演算法生成雜湊資料。

VALUES HEX(HASH_MD5('ABCDEFGHIJKLMNOPQRSTUVWXYZ'))

返回以下值:

5156BECBC019E3F0F9520B143435427E

使用SHA1演算法生成雜湊資料。

VALUES HEX(HASH_SHA1('ABCDEFGHIJKLMNOPQRSTUVWXYZ'))

返回以下值:

55324E3DD1FA95040F65709D193E82575237EF86

使用SHA-256演算法生成雜湊資料。

VALUES HEX(HASH_SHA256('ABCDEFGHIJKLMNOPQRSTUVWXYZ'))

返回以下值:

011F7AD1ECD8E5A4CC8533D1ECD497DC5D95E848B14F8BCFD56A73D7F41843E2

使用SHA-512演算法生成雜湊資料。

VALUES HEX(HASH_SHA512('ABCDEFGHIJKLMNOPQRSTUVWXYZ'))

返回以下值:

D8AC4B838921A83C4207B62B8B63628F8FBE836EB012167310331FFC070FC977D224F39148
  8806CB1FE2AA9C8C739E5104CAD1C4C6E97967DA6223D657CD9295

 

雜湊函式的基本介紹(SHA-256,MD-5等)

https://dev.to/wagslane/very-basic-intro-to-hash-functions-sha-256-md-5-etc-399j


這將是雜湊函式的基本介紹。我將假定我的大多數讀者都在這裡,以瞭解為什麼使用雜湊函式以及它們為什麼起作用的基本概念。我的目標是從一般意義上解釋它,我將省略證明和實現細節,而將重點放在高階原則上。

為什麼要使用雜湊函式?

雜湊函式在整個Internet上使用,以安全地儲存密碼,查詢重複記錄,快速儲存和檢索資料等等。例如,Qvault使用雜湊將主密碼擴充套件為專用加密金鑰。

  1.  https://en.wikipedia.org/wiki/Hash\_function#Uses
  2. https://en.wikipedia.org/wiki/Hash_function#Uses

我想關注雜湊函式的幾個重要功能,可以說是最重要的功能。

  • 雜湊函式確定性地加擾資料
  • 無論輸入如何,雜湊函式的輸出始終具有相同的大小
  • 無法從加擾資料中檢索原始資料(單向功能)

確定性地加擾資料

想想一個魔方。

我從無雜亂無章的多維資料集開始。如果我開始隨機扭曲,到最後,我將得到的東西與我剛開始的東西幾乎沒有任何相似之處。另外,如果我要重新開始並做完全相同的一系列動作,我將能夠反覆獲得完全相同的結果。即使結果may_出現_random,也完全不是。這就是確定性*的意思。

確定性對於安全儲存密碼很重要。例如,假設我的密碼是“ iLoveBitcoin”

我可以使用雜湊函式對其進行加擾:

iLoveBitcoin→“ 2f5sfsdfs5s1fsfsdf98ss4f84sfs6d5fs2d1fdf15”

現在,如果有人要檢視加密版本,他們將不知道我的原始密碼!這很重要,因為這意味著作為網站開發人員,我只需要儲存使用者密碼的雜湊(加密資料)即可進行驗證。當使用者註冊時,我對密碼進行雜湊處理並將其儲存在資料庫中。當使用者登入時,我只是對他們鍵入的內容進行雜湊處理,然後比較兩個雜湊值。由於給定的輸入始終會產生相同的雜湊,因此每次都有效。

如果網站以純文字形式(而不是雜湊的形式)儲存密碼,則將嚴重違反安全性。如果有人要入侵該站點的資料庫並找到所有使用純文字密碼儲存的電子郵件,則他們可以使用這些組合並在其他網站上嘗試使用。

輸入無關緊要,輸出大小相同

如果我對單個單詞進行雜湊處理,則輸出將具有一定的大小(對於SHA-256,則為特定的雜湊函式,大小為256位)。如果我對一本書進行雜湊處理,輸出將是相同大小

這是另一個重要功能,因為它可以節省我們的計算時間。一個經典的例子是使用雜湊作為資料對映中的鍵。資料對映是電腦科學中用於儲存資料的簡單結構。

當程式將資料儲存在對映中時,鍵和值將被賦予對映。當程式要訪問該值時,它可以將適當的鍵提供給對映並接收相應的值。資料對映之所以不錯,是因為它們可以立即找到資料。_鍵用作計算機可以立即找到的地址,而不是花費數小時來搜尋數百萬條記錄。

因為鍵就像地址,所以不能太大。如果我想將書籍儲存在資料對映中,則可以對書籍的內容進行雜湊處理並將雜湊值用作鍵。作為程式設計師,我可以簡單地使用雜湊來查詢書中的內容,而不必嘗試按標題,作者等對數千條記錄進行排序。

它們如何工作?

這是撰寫本文的真正挑戰。我將使其保持極其簡單,並省略實際的實現細節,同時讓您基本瞭解計算機在處理某些資料時的實際工作。

讓我們來看一下我正在為這個演示動態編寫的示例演算法 LANEHASH:

  • 我們從一些要雜湊的資料開始

iLove比特幣

  • 我將字母和數字轉換為1和0(計算機中的所有資料都儲存在1和0中,不同的1和0表示不同的字母)

iLoveBitcoin→100010100000101111

  • 在這一點上,我們經歷了各種預定步驟來轉換我們的資料。這些步驟可以是任何步驟,重要的是,每當我們使用LANEHASH時,我們都需要使用相同的步驟,以便我們的演算法具有確定性。
  • 我們將前四位從左側移到右側

1000 10100000101111→10100000101111 1000

  • 我們隔著一點

1 0 1 0 0 0 0 0 1 0 1 1 1 1 1 0 0 0→110011110&000001100

  • 我們將這兩部分轉換為以10為底的數字。以10為基數是我們在學校都學過的“正常”數字系統。(所有二進位制資料實際上只是數字,您可以在其他地方線上查詢如何將二進位制輕鬆轉換為以10為基數)

110011110→414

000001100→12

  • 我們將兩個數字相乘

414 * 12 = 4968

  • 我們對該數字求平方

4968 ^ 2 = 24681024

  • 我們將該數字轉換回二進位制

24681024→1011110001001101001000000

  • 我們從右側切掉9位以得到16位

1011110001001101 001000000 →1011110001001101

  • 我們將二進位制資料轉換回英語

1011110001001101→“ 8sj209dsns02k2”

如您所見,如果在開頭以相同的單詞開頭,那麼在結尾始終將得到相同的輸出。但是,即使您只更改一個字母,結果也將發生巨大變化。

免責宣告

在我從英語轉換為二進位制,以及從二進位制轉換為英語的步驟中,我沒有遵循任何模式。不要讓那讓您感到困惑。有很多不同的方法可以將二進位制資料轉換為英語,然後再轉換回英語,我只是不想在本文中對此感到困惑。以下是有關該主題的一些參考資料:

https://zh.wikipedia.org/wiki/ASCII

https://zh.wikipedia.org/wiki/Unicode

 

什麼是MD5雜湊?

https://www.md5hashgenerator.com/


通過採用任意長度的字串並將其編碼為128位指紋來建立MD5雜湊。使用MD5演算法編碼相同的字串將始終導致相同的128位雜湊輸出。當在資料庫(例如流行的MySQL)中儲存密碼,信用卡號或其他敏感資料時,MD5雜湊通常與較小的字串一起使用。該工具提供了一種快速簡便的方法,可以從長度最多為256個字元的簡單字串中編碼MD5雜湊。

MD5雜湊還用於確保檔案的資料完整性。由於MD5雜湊演算法始終為相同的給定輸入產生相同的輸出,因此使用者可以將原始檔的雜湊值與目標檔案的新建立的雜湊值進行比較,以檢查其是否完整且未修改。

MD5雜湊不是加密的。它只是給定輸入的指紋。但是,這是單向事務,因此幾乎不可能對MD5雜湊進行反向工程以檢索原始字串。

 

 

SHA-2的工作原理(SHA-256)

https://dev.to/wagslane/how-sha-2-works-step-by-step-sha-256-11ci

https://qvault.io/2020/07/08/how-sha-2-works-step-by-step-sha-256/


 

SHA-2(安全雜湊演算法2)是SHA-256的一部分,是其中最流行的雜湊演算法之一。在本文中,我們將盡可能簡單地分解演算法的每個步驟,並手工完成一個真實的示例。

SHA-2以其安全性(它沒有像SHA-1一樣崩潰)和速度而聞名。在未生成金鑰的情況下(例如挖礦比特幣),像SHA-2這樣的快速雜湊演算法通常佔據上風。

什麼是雜湊函式?

如果您想全面瞭解雜湊函式,請在此處閱讀。也就是說,為了前進,讓我們回顧一下雜湊函式的三個主要目的:

  • 確定性地加擾資料
  • 接受任意長度的輸入並輸出固定長度的結果
  • 不可逆地操縱資料。輸入不能從輸出派生

SHA-2和SHA-256

SHA-2是一種演算法,是有關如何對資料進行雜湊處理的通用思想。SHA-256設定其他常量,這些常量定義SHA-2演算法的行為。這樣的常數之一就是輸出大小。“ 256”和“ 512”以位元為單位表示它們各自的輸出摘要大小。

讓我們逐步介紹一下SHA-256的示例。

SHA-256“ hello world”;步驟1 –預處理

將“ hello world”轉換為二進位制:

01101000 01100101 01101100 01101100 01101111 00100000 01110111 01101111
01110010 01101100 01100100

附加一個1:

01101000 01100101 01101100 01101100 01101111 00100000 01110111 01101111
01110010 01101100 01100100 1

用0填充,直到資料為512的整數倍,然後減去64位(本例中為448位):

01101000 01100101 01101100 01101100 01101111 00100000 01110111 01101111
01110010 01101100 01100100 10000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

在末尾附加64位,其中64位是big-endian整數,表示二進位制原始輸入的長度。在我們的例子中,為88,或二進位制為“ 1011000”。

01101000 01100101 01101100 01101100 01101111 00100000 01110111 01101111
01110010 01101100 01100100 10000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 01011000

現在我們有了輸入,它將始終被512平均整除。

步驟2 –初始化雜湊值(h)

現在,我們建立8個雜湊值。這些是硬編碼的常數,代表前8個素數的平方根的小數部分的前32位:2、3、5、7、11、13、17、19

h0 := 0x6a09e667
h1 := 0xbb67ae85
h2 := 0x3c6ef372
h3 := 0xa54ff53a
h4 := 0x510e527f
h5 := 0x9b05688c
h6 := 0x1f83d9ab
h7 := 0x5be0cd19

步驟3 –初始化舍入常數(k)

與第2步類似,我們正在建立一些常量(在此處瞭解有關常量以及何時使用它們的更多資訊)。這次有64個。每個值(0-63)是前64個素數(2 – 311)的立方根的小數部分的前32位。

0x428a2f98 0x71374491 0xb5c0fbcf 0xe9b5dba5 0x3956c25b 0x59f111f1 0x923f82a4 0xab1c5ed5
0xd807aa98 0x12835b01 0x243185be 0x550c7dc3 0x72be5d74 0x80deb1fe 0x9bdc06a7 0xc19bf174
0xe49b69c1 0xefbe4786 0x0fc19dc6 0x240ca1cc 0x2de92c6f 0x4a7484aa 0x5cb0a9dc 0x76f988da
0x983e5152 0xa831c66d 0xb00327c8 0xbf597fc7 0xc6e00bf3 0xd5a79147 0x06ca6351 0x14292967
0x27b70a85 0x2e1b2138 0x4d2c6dfc 0x53380d13 0x650a7354 0x766a0abb 0x81c2c92e 0x92722c85
0xa2bfe8a1 0xa81a664b 0xc24b8b70 0xc76c51a3 0xd192e819 0xd6990624 0xf40e3585 0x106aa070
0x19a4c116 0x1e376c08 0x2748774c 0x34b0bcb5 0x391c0cb3 0x4ed8aa4a 0x5b9cca4f 0x682e6ff3
0x748f82ee 0x78a5636f 0x84c87814 0x8cc70208 0x90befffa 0xa4506ceb 0xbef9a3f7 0xc67178f2

步驟4 –區塊迴圈

對於來自我們輸入的每個512位“塊”資料,將執行以下步驟。在我們的案例中,由於“ hello world”非常短,因此我們只有一個塊。在迴圈的每次迭代中,我們將使雜湊值h0-h7突變,這將是最終輸出。

步驟5 –建立郵件時間表(w)

將步驟1中的輸入資料複製到一個新陣列中,其中每個條目都是一個32位字:

01101000011001010110110001101100 01101111001000000111011101101111
01110010011011000110010010000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000001011000

再新增48個初始化為零的單詞,這樣我們就有了一個陣列w [0…63]

01101000011001010110110001101100 01101111001000000111011101101111
01110010011011000110010010000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000001011000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
...
...
00000000000000000000000000000000 00000000000000000000000000000000

使用以下演算法在陣列末尾修改零位索引:

對於從W [16 ... 63]:

s0 =(w [i-15]右旋7)xor(w [i-15]右旋18)xor(w [i-15]右移3)

s1 =(w [i-2]右旋17)xor(w [i-2]右旋19)xor(w [i-2]右移10)

w [i] = w [i-16] + s0 + w [i-7] + s1

s0 = (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift 3)
s1 = (w[i- 2] rightrotate 17) xor (w[i- 2] rightrotate 19) xor (w[i- 2] rightshift 10)
w[i] = w[i-16] + s0 + w[i-7] + s1

讓我們做w [16]以便我們看一下它是如何工作的:

w[1] rightrotate 7:
  01101111001000000111011101101111 -> 11011110110111100100000011101110
w[1] rightrotate 18:
  01101111001000000111011101101111 -> 00011101110110111101101111001000
w[1] rightshift 3:
  01101111001000000111011101101111 -> 00001101111001000000111011101101

s0 = 11011110110111100100000011101110 XOR 00011101110110111101101111001000 XOR 00001101111001000000111011101101

s0 = 11001110111000011001010111001011

w[14] rightrotate 17:
  00000000000000000000000000000000 -> 00000000000000000000000000000000
w[14] rightrotate19:
  00000000000000000000000000000000 -> 00000000000000000000000000000000
w[14] rightshift 10:
  00000000000000000000000000000000 -> 00000000000000000000000000000000

s1 = 00000000000000000000000000000000 XOR 00000000000000000000000000000000 XOR 00000000000000000000000000000000

s1 = 00000000000000000000000000000000

w[16] = w[0] + s0 + w[9] + s1

w[16] = 01101000011001010110110001101100 + 11001110111000011001010111001011 + 00000000000000000000000000000000 + 00000000000000000000000000000000

// addition is calculated modulo 2^32

w[16] = 00110111010001110000001000110111

這使我們在訊息時間表(w)中留下了64個單詞:

01101000011001010110110001101100 01101111001000000111011101101111
01110010011011000110010010000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000001011000
00110111010001110000001000110111 10000110110100001100000000110001
11010011101111010001000100001011 01111000001111110100011110000010
00101010100100000111110011101101 01001011001011110111110011001001
00110001111000011001010001011101 10001001001101100100100101100100
01111111011110100000011011011010 11000001011110011010100100111010
10111011111010001111011001010101 00001100000110101110001111100110
10110000111111100000110101111101 01011111011011100101010110010011
00000000100010011001101101010010 00000111111100011100101010010100
00111011010111111110010111010110 01101000011001010110001011100110
11001000010011100000101010011110 00000110101011111001101100100101
10010010111011110110010011010111 01100011111110010101111001011010
11100011000101100110011111010111 10000100001110111101111000010110
11101110111011001010100001011011 10100000010011111111001000100001
11111001000110001010110110111000 00010100101010001001001000011001
00010000100001000101001100011101 01100000100100111110000011001101
10000011000000110101111111101001 11010101101011100111100100111000
00111001001111110000010110101101 11111011010010110001101111101111
11101011011101011111111100101001 01101010001101101001010100110100
00100010111111001001110011011000 10101001011101000000110100101011
01100000110011110011100010000101 11000100101011001001100000111010
00010001010000101111110110101101 10110000101100000001110111011001
10011000111100001100001101101111 01110010000101111011100000011110
10100010110101000110011110011010 00000001000011111001100101111011
11111100000101110100111100001010 11000010110000101110101100010110

步驟6 –壓縮

初始化變數a,b,c,d,e,f,g,h,並將它們分別設定為等於當前的雜湊值。h0,h1,h2,h3,h4,h5,h6,h7

執行壓縮迴圈。壓縮迴圈將使a…h的值發生變化。壓縮迴圈如下:

我從0到63

S1 =(e右旋轉6)xor(e右旋轉11)xor(e右旋轉25)

ch =(e和f)xor((not e)和g)

temp1 = h + S1 + ch + k [i] + w [i]

S0 =(右旋轉2)xor(右旋轉13)xor(右旋轉22)

maj =(a和b)xor(a和c)xor(b和c)

temp2:= S0 + maj

h =克

g = f

e = d +溫度1

d = c

c = b

b = a

a = temp1 + temp2

S1 = (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25)
ch = (e and f) xor ((not e) and g)
temp1 = h + S1 + ch + k[i] + w[i]
S0 = (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22)
maj = (a and b) xor (a and c) xor (b and c)
temp2 := S0 + maj
h = g
g = f
e = d + temp1
d = c
c = b
b = a
a = temp1 + temp2

讓我們進行第一次迭代,所有加法都是以2 ^ 32模的

a = 0x6a09e667 = 01101010000010011110011001100111
b = 0xbb67ae85 = 10111011011001111010111010000101
c = 0x3c6ef372 = 00111100011011101111001101110010
d = 0xa54ff53a = 10100101010011111111010100111010
e = 0x510e527f = 01010001000011100101001001111111
f = 0x9b05688c = 10011011000001010110100010001100
g = 0x1f83d9ab = 00011111100000111101100110101011
h = 0x5be0cd19 = 01011011111000001100110100011001

e rightrotate 6:
  01010001000011100101001001111111 -> 11111101010001000011100101001001
e rightrotate 11:
  01010001000011100101001001111111 -> 01001111111010100010000111001010
e rightrotate 25:
  01010001000011100101001001111111 -> 10000111001010010011111110101000
S1 = 11111101010001000011100101001001 XOR 01001111111010100010000111001010 XOR 10000111001010010011111110101000
S1 = 00110101100001110010011100101011

e and f:
    01010001000011100101001001111111
  & 10011011000001010110100010001100 =
    00010001000001000100000000001100
not e:
  01010001000011100101001001111111 -> 10101110111100011010110110000000
(not e) and g:
    10101110111100011010110110000000
  & 00011111100000111101100110101011 =
    00001110100000011000100110000000
ch = (e and f) xor ((not e) and g)
   = 00010001000001000100000000001100 xor 00001110100000011000100110000000
   = 00011111100001011100100110001100

// k[i] is the round constant
// w[i] is the batch
temp1 = h + S1 + ch + k[i] + w[i]
temp1 = 01011011111000001100110100011001 + 00110101100001110010011100101011 + 00011111100001011100100110001100 + 1000010100010100010111110011000 + 01101000011001010110110001101100
temp1 = 01011011110111010101100111010100

a rightrotate 2:
  01101010000010011110011001100111 -> 11011010100000100111100110011001
a rightrotate 13:
  01101010000010011110011001100111 -> 00110011001110110101000001001111
a rightrotate 22:
  01101010000010011110011001100111 -> 00100111100110011001110110101000
S0 = 11011010100000100111100110011001 XOR 00110011001110110101000001001111 XOR 00100111100110011001110110101000
S0 = 11001110001000001011010001111110

a and b:
    01101010000010011110011001100111
  & 10111011011001111010111010000101 =
    00101010000000011010011000000101
a and c:
    01101010000010011110011001100111
  & 00111100011011101111001101110010 =
    00101000000010001110001001100010
b and c:
    10111011011001111010111010000101
  & 00111100011011101111001101110010 =
    00111000011001101010001000000000
maj = (a and b) xor (a and c) xor (b and c)
    = 00101010000000011010011000000101 xor 00101000000010001110001001100010 xor 00111000011001101010001000000000 
    = 00111010011011111110011001100111

temp2 = S0 + maj
      = 11001110001000001011010001111110 + 00111010011011111110011001100111
      = 00001000100100001001101011100101

h = 00011111100000111101100110101011
g = 10011011000001010110100010001100
f = 01010001000011100101001001111111
e = 10100101010011111111010100111010 + 01011011110111010101100111010100
  = 00000001001011010100111100001110
d = 00111100011011101111001101110010
c = 10111011011001111010111010000101
b = 01101010000010011110011001100111
a = 01011011110111010101100111010100 + 00001000100100001001101011100101
  = 01100100011011011111010010111001

整個計算又進行了63次,從而始終修改了變數ah。我們不會手工完成,但是我們將提供ender:

h0 = 6A09E667 = 01101010000010011110011001100111
h1 = BB67AE85 = 10111011011001111010111010000101
h2 = 3C6EF372 = 00111100011011101111001101110010
h3 = A54FF53A = 10100101010011111111010100111010
h4 = 510E527F = 01010001000011100101001001111111
h5 = 9B05688C = 10011011000001010110100010001100
h6 = 1F83D9AB = 00011111100000111101100110101011
h7 = 5BE0CD19 = 01011011111000001100110100011001

a = 4F434152 = 001001111010000110100000101010010
b = D7E58F83 = 011010111111001011000111110000011
c = 68BF5F65 = 001101000101111110101111101100101
d = 352DB6C0 = 000110101001011011011011011000000
e = 73769D64 = 001110011011101101001110101100100
f = DF4E1862 = 011011111010011100001100001100010
g = 71051E01 = 001110001000001010001111000000001
h = 870F00D0 = 010000111000011110000000011010000

步驟7 –修改最終值

在壓縮迴圈之後,但仍然在迴圈中,我們通過將雜湊值新增到變數ah中來修改雜湊值。像往常一樣,所有加法都是模2 ^ 32

h0 = h0 + a = 10111001010011010010011110111001
h1 = h1 + b = 10010011010011010011111000001000
h2 = h2 + c = 10100101001011100101001011010111
h3 = h3 + d = 11011010011111011010101111111010
h4 = h4 + e = 11000100100001001110111111100011
h5 = h5 + f = 01111010010100111000000011101110
h6 = h6 + g = 10010000100010001111011110101100
h7 = h7 + h = 11100010111011111100110111101001

第8步-連線最終雜湊

最後但並非最不重要的一點是,將它們全部拍打!

digest = h0 append h1 append h2 append h3 append h4 append h5 append h6 append h7
       = B94D27B9934D3E08A52E52D7DA7DABFAC484EFE37A5380EE9088F7ACE2EFCDE9

做完了!我們已經仔細研究了SHA-256的每個步驟(沒有重複),?

 

偽碼

如果您想以虛擬碼形式檢視上面剛剛完成的所有步驟,那麼直接來自WikiPedia

Note 1: All variables are 32 bit unsigned integers and addition is calculated modulo 232
Note 2: For each round, there is one round constant k[i] and one entry in the message schedule array w[i], 0 ≤ i ≤ 63
Note 3: The compression function uses 8 working variables, a through h
Note 4: Big-endian convention is used when expressing the constants in this pseudocode,
    and when parsing message block data from bytes to words, for example,
    the first word of the input message "abc" after padding is 0x61626380

Initialize hash values:
(first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
h0 := 0x6a09e667
h1 := 0xbb67ae85
h2 := 0x3c6ef372
h3 := 0xa54ff53a
h4 := 0x510e527f
h5 := 0x9b05688c
h6 := 0x1f83d9ab
h7 := 0x5be0cd19

Initialize array of round constants:
(first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311):
k[0..63] :=
   0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
   0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
   0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
   0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
   0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
   0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
   0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
   0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2

Pre-processing (Padding):
begin with the original message of length L bits
append a single '1' bit
append K '0' bits, where K is the minimum number >= 0 such that L + 1 + K + 64 is a multiple of 512
append L as a 64-bit big-endian integer, making the total post-processed length a multiple of 512 bits

Process the message in successive 512-bit chunks:
break message into 512-bit chunks
for each chunk
    create a 64-entry message schedule array w[0..63] of 32-bit words
    (The initial values in w[0..63] don't matter, so many implementations zero them here)
    copy chunk into first 16 words w[0..15] of the message schedule array

    Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array:
    for i from 16 to 63
        s0 := (w[i-15] rightrotate  7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift  3)
        s1 := (w[i- 2] rightrotate 17) xor (w[i- 2] rightrotate 19) xor (w[i- 2] rightshift 10)
        w[i] := w[i-16] + s0 + w[i-7] + s1

    Initialize working variables to current hash value:
    a := h0
    b := h1
    c := h2
    d := h3
    e := h4
    f := h5
    g := h6
    h := h7

    Compression function main loop:
    for i from 0 to 63
        S1 := (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25)
        ch := (e and f) xor ((not e) and g)
        temp1 := h + S1 + ch + k[i] + w[i]
        S0 := (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22)
        maj := (a and b) xor (a and c) xor (b and c)
        temp2 := S0 + maj
 
        h := g
        g := f
        f := e
        e := d + temp1
        d := c
        c := b
        b := a
        a := temp1 + temp2

    Add the compressed chunk to the current hash value:
    h0 := h0 + a
    h1 := h1 + b
    h2 := h2 + c
    h3 := h3 + d
    h4 := h4 + e
    h5 := h5 + f
    h6 := h6 + g
    h7 := h7 + h

Produce the final hash value (big-endian):
digest := hash := h0 append h1 append h2 append h3 append h4 append h5 append h6 append h7

 

Scrypt雜湊的基本介紹

https://dev.to/wagslane/very-basic-intro-to-the-scrypt-hash-7l5


這將是Scrypt雜湊函式或更準確地說是KDF函式的基本介紹。我將假定我的大多數觀眾都在這裡,以瞭解使用Scrypt原因以及其工作原理基礎。我的目標是從一般意義上解釋它,我將省略證明和實現細節,而將重點放在高階原則上。

密碼學中scrypt(發音為“ ess crypt” [1])是由Colin Percival建立的基於密碼的金鑰派生功能,最初用於Tarsnap線上備份服務。[2] 該演算法經過專門設計,使其需要大量記憶體,因此執行大規模自定義硬體攻擊的成本很高。IETF在2016年將scrypt演算法釋出為RFC 7914。scrypt的簡化版本被許多加密貨幣用作工作量證明方案,首先由位於Tenebrix的名為ArtForz的匿名程式設計師實現,隨後不久又由Fairbrix和Litecoin實現[3] -- https://en.wikipedia.org/wiki/Scrypt

什麼是Scrypt?

Scrypt是一種設計緩慢的 雜湊函式。其目的是獲取一些輸入資料,併為該資料建立指紋,但是要非常緩慢地進行。Qvault如何使用其真實案例的最佳示例之一。即,使用密碼並建立256位私有金鑰

例如,假設您的密碼為password1234。通過使用scrypt,我們可以確定性地將其擴充套件為256位金鑰:

password1234- >
AwEEDA4HCwQFAA8D
AwwHDQwPDwUOBwoO
CQACAgUJBQ0JAAYN
BAMCDQ4JCQgLDwcG
DQMDDgMKAQsNBAkL
AwsACA ==

現在可以將該長256位金鑰用作私有金鑰,以使用AES-256密碼對資料進行加密和解密。

為什麼不使用密碼直接加密?

大多數加密演算法,包括AES-256,都要求使用足夠長的金鑰。通過對密碼進行雜湊處理,我們得到了更長且固定大小的金鑰。

此外,出於兩個原因,我們選擇使用scrypt演算法,而不是使用SHA-256之類的更快的雜湊值:

  • 慢一點
  • 它使用記憶體以及CPU資源

我們想要慢速雜湊的原因是,攻擊者很難猜測使用者的密碼。如果攻擊者試圖強行闖入金庫,則意味著他們只是反覆猜測密碼以進行破解。AES-256速度非常快,因此,攻擊者將能夠嘗試許多密碼在現代計算機上每秒傳輸一次。

由於攻擊者必須先對每個密碼執行一個scrypt雜湊,然後才能嘗試對庫進行解密,因此攻擊變得如此緩慢,幾乎不可能猜出密碼。在功能相對強大的臺式計算機上,雜湊Qvault密碼大約需要1.5秒,因為我們將記憶體和計算要求設定得很高。

加密屬性

像所有雜湊函式一樣,scrypt具有以下屬性:

  • 確定性的(每次相同的輸入都會產生相同的輸出)
  • 固定尺寸的輸出
  • 不可逆的(通過使用輸出,攻擊者無法找到輸入)

此外,Scrypt具有以下屬性:

  • 計算昂貴且速度慢(計算機執行雜湊需要很長時間)
  • 記憶體密集型(可能使用數GB的RAM來執行雜湊)

 

什麼是BCrypt?

https://dev.to/sylviapap/bcrypt-explained-4k5c


BCrypt是由OpenBSD專案的Niels Provos和DavidMazières在1999年設計的一種雜湊演算法。B代表...

如果您是初學者密碼學的專家,那麼您來對地方了。也許您只是進入Rails並想新增使用者登入/登出功能。也許您真的很喜歡加密雜湊演算法。我肯定是!如果您真的是一個初學者,那麼一個名為Khan Academy的小型網站上有一些關於加密的特別出色的視訊

這並不是真正的教程,但是在使用BCrypt時,請始終記住取消註釋Rails Gemfile中的gem。

source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.6.1'

...

# Use Active Model has_secure_password
# gem 'bcrypt', '~> 3.1.7'
gem 'bcrypt', '~> 3.1.7'

...

 

現在,您可以做一些很酷的事情:

# Encrypts password
my_password = BCrypt::Password.create('iLOVEdogs123')
 => "$2a$10$kypbnGGCpJ7UQlysnqzJG.6H.dUewn7UPVWA3Ip.E.8U4jlVnFNnu"

# Tests if input matches
my_password == 'iLOVEdogs123'
 => true 

my_password == 'ilovedogs12'
 => false

# Not super important for this post, but this is why the above crypt begins with "$2a$"
my_password.version
 => "2a" 

# "Cost" factor - how quickly the password is encrypted
my_password.cost
 => 10 

現在,您可以使用BCrypt對應用程式執行很多操作-身份驗證,授權,登入,登出等!但是,已經有很多部落格文章和有關如何編寫程式碼的有用文件。我對幕後動作更感興趣。

Bcrypt是怎麼加密的?

Bcrypt有四個變數:

  1. saltRounds: 正數,代表hash雜湊次數,數值越高越安全,預設10次。
  2. myPassword: 明文密碼字串。
  3. salt: 鹽,一個128bits隨機字串,22字元
  4. myHash: 經過明文密碼password和鹽salt進行hash,個人的理解是預設10次下 ,迴圈加鹽hash10次,得到myHash

每次明文字串myPassword過來,就通過10次迴圈加鹽salt加密後得到myHash, 然後拼接BCrypt版本號+salt鹽+myHash等到最終的bcrypt密碼 ,存入資料庫中。

這樣同一個密碼,每次登入都可以根據自省業務需要生成不同的myHash, myHash中包含了版本和salt,存入資料庫。
bcrypt密碼圖解:(此部分來源:https://www.jianshu.com/p/2b131bfc2f10

如Spring Security crypto 專案中實現的BCrypt方法加密:BCrypt.hashpw(myPassword, BCrypt.gensalt())

那即使黑客得到了bcrypt密碼,他也無法轉換明文,因為之前說了bcrypt是單向hash演算法

 

OWASP - 開放式Web應用程式安全專案


開放式Web應用程式安全專案(OWASP,Open Web Application Security Project)是一個組織,它提供有關計算機和網際網路應用程式的公正、實際、有成本效益的資訊。其目的是協助個人、企業和機構來發現和使用可信賴軟體。

OWASP Top 10是針對開發人員和Web應用程式安全性的標準意識文件。它代表了對Web應用程式最嚴重的安全風險的廣泛共識。

 

相關文章


 

相關文章