我今天正在學習 SHA2,并到達了我不明白的代碼位置。
RFC 4634(其中定義了 SHA2)在檔案中定義了兩個變數Length_Low和:Length_Highsha.h
uint32_t Length_Low; /* Message length in bits */
uint32_t Length_High; /* Message length in bits */
例如,在sha224-256.c檔案中,變數Length_Low在兩個地方被主動更改。這里:
/*
* add "length" to the length
*/
static uint32_t addTemp;
#define SHA1AddLength(context, length) \
(addTemp = (context)->Length_Low, \
(context)->Corrupted = \
(((context)->Length_Low = (length)) < addTemp) && \
( (context)->Length_High == 0) ? 1 : 0)
和這里:
/*
* Store the message length as the last 8 octets
*/
context->Message_Block[56] = (uint8_t) (context->Length_High >> 24);
context->Message_Block[57] = (uint8_t) (context->Length_High >> 16);
context->Message_Block[58] = (uint8_t) (context->Length_High >> 8);
context->Message_Block[59] = (uint8_t) (context->Length_High);
context->Message_Block[60] = (uint8_t) (context->Length_Low >> 24);
context->Message_Block[61] = (uint8_t) (context->Length_Low >> 16);
context->Message_Block[62] = (uint8_t) (context->Length_Low >> 8);
context->Message_Block[63] = (uint8_t) (context->Length_Low);
我了解 RFC 4634 和 SHA2 的原理。但是,作為 CI 初學者,只能理解論文中 99% 的代碼。我附上的代碼片段屬于這剩下的 1%。
你能解釋一下,Length_Low和Length_High變數在 SHA2 的實作中起什么作用?它們在代碼層面的含義是什么?
其次,代碼片段中發生了什么?我可以識別復合運算子和移位,但是代碼的難度讓我不知所措,尤其是在第二個片段中,其中取消參考、增量、定義等發生在同一行代碼中。
uj5u.com熱心網友回復:
Meta:stackexchange,尤其是 stackoverflow,政策是不發布“代碼”的影像,定義為包括組態檔和日志或錯誤訊息之類的內容,因為它們在移動設備上很難閱讀,視障人士無法閱讀人,不可剪切和粘貼,不可搜索。加上你的,我認為你的 IDE 重新格式化和著色,在我看來非常難看。幸運的是,所有的 RFC 都是以文本形式發布的,我可以很容易地替換它。
另外,順便說一句:SHA-256 和 SHA-224(以及它們之前的 SHA-1 和 MD5)的輸入塊大小是 64個八位位元組或 512 位,而不是 64 位,無論如何與長度欄位無關。長度欄位確實是 64 位,并在代碼中實作為高半和低半的兩個 32 位變數。
static uint32_t addTemp;
#define SHA224_256AddLength(context, length) \
(addTemp = (context)->Length_Low, (context)->Corrupted = \
(((context)->Length_Low = (length)) < addTemp) && \
( (context)->Length_High == 0) ? 1 : 0)
將一段輸入資料的長度(對于完整八位位元組實際上總是使用 8 或對于剩余位總是使用 1-7)添加到 2x32 位長度欄位是相當棘手的代碼。首先它保存傳入的Length_Lowin addTemp,然后,從內到外:
(context)->Length_Low = (length) // call this CODE1
將 的值添加length到Length_Low結構中的欄位;因為這在 C 中使用無符號算術,如果結果(數學上)溢位,它會被環繞(取模 2 32)。因此Length_low,addTemp當且僅當發生溢位/回繞時,總和( 中的新值)小于原始值。這是經過測驗的,在這種情況下,該Length_High欄位會增加:
( CODE1 < addTemp) && ( (context)->Length_High == 0) // call this CODE2
如果在增加高半部分后為零,則意味著它也溢位/環繞,這意味著實際訊息長度太大而無法適應規范要求的 64 位欄位,因此這被視為錯誤并存盤在該Corrupted欄位中,稍后將對其進行測驗以報告散列操作失敗:
(addTemp=..., (context)->Corrupted = CODE2 ? 1 : 0)
應該注意的? 1 : 0是,這在技術上是不必要的;C 中的&&and||運算子(以及像<and 之類的比較/相等運算子==)被定義為已經為真回傳 1,為假回傳零(盡管測驗像if(x)并while(x) 接受任何非零值為真)。然而,有些人覺得寫出來更清楚,而且這種動機在 RFC 中尤其強烈,該 RFC 發布給廣泛的受眾,包括那些(像你一樣!)對 C 知之甚少的人。
事實上,將它寫成一個(非常小的)函式而不是宏可能會更好,這將允許使用更明顯的陳述句而不是復雜的嵌套運算式,并且在 2006 年的任何體面的編譯器(現在更少)行內和折疊以生成與宏相同的代碼。但世界并不完美。
相比之下,你的第三塊非常簡單。它只需要 2x32 位長度的欄位并將其作為 8 個 8 位單元的 big-endian 序列存盤在當前Message_Block.
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/371819.html
上一篇:沒有值的索引的參考位置
