linyunwen
contributed by <LinYunWen
>
理解
兩人生日相同的機率是多少。而不是你進入了一個有著 22 個人的房間,房間裡有人會和你有相同生日的機率
,因此我們先照文章中所假設的人數為 23 人。在同一天生日的機率
即為
因為自然常數次方的泰勒展開式為
因此
若是只有 22 人則為
若只有 21 人
一開始我真的想不到有什麼資訊安全跟 birthday paradox 有關係,所以我先上網查詢,最先查到的就是 birthday attack ,但是有些看不懂,只能大概知道他在寫跟機率有相關的部份,於是繼續查才比較了解
Reference: The Birthday Problem🎈
所謂『雜湊函數』(Hash Function),是將不定長度訊息的輸入,演算成固定長度雜湊值的輸出,且所計算出來的雜湊值必須符合兩個主要條件:
(1) 由雜湊值是無法反推出原來的訊息
(2) 雜湊值必須隨明文改變而改變。
也就是說,不同明文所計算出來的雜湊值必須是不相同的,甚至僅改變明文中任何一個字元時,雜湊值的輸出也必須差異很大。由此可見,期望中的雜湊值就好像是一個無法冒充的識別碼,且每一份文件都有其特殊的雜湊值,且無法被偽造,故有數位指紋Digital Fingerprint之稱。一般雜湊函數必須具備下列功能:
- 雜湊函數必須對任意長度的訊息輸入,產生固定長度的雜湊值輸出。
- 對於任意訊息 M,雜湊函數可以輕易的計算出 H(M),並且可經由硬體或軟體來實現。
- 如果給予雜湊值 h,在計算上是無法找出原訊息 M,使其符合 h = H(M),此特性稱之為『單向雜湊』(One-way Hash)。
- 對於一個訊息 M1,在計算上是無法找出另一個訊息 M2 (≠ M1),使得 H(M1) = H(M2)。也就是說,給定一個雜湊值(H(M1)),須無法找出另一個訊息(M2),使其所產生的雜湊值相同。
- 就兩訊息 M1、M2 而言,若他們的雜湊值相等,亦即 H(M1) = H(M2),則 M1 與 M2 兩訊息也一定相等(M1 = M2);同理,若 H(M1)≠H(M2),則 M1≠M2。也就是說,給定一個明文與雜湊值,須保證無法找出另一個訊息來產生同樣的雜湊值。
第4項是雜湊函數最基本功能,亦即給予一段不定長度的訊息,能輕易計算出一個固定長度的雜湊值。如果反過來,給予一個固定長度的雜湊值,是無法計算出原來訊息的,也無法找出可以產生同樣雜湊值的另一段訊息,如能達到此功能,一般稱之為弱雜湊函數 (Weak Hash Function)。若再涵蓋第 5 項功能,則稱為強雜湊函數(Strong Hash Function),其表示有了明文與雜湊值,也無法另外偽造一個明文來產生相同的雜湊值。
基本上,雜湊函數是將原來訊息打亂,得到另一個亂無章法的雜湊值,而且是越亂越好。很不幸的,我們發現大部分的傳輸訊息都有一定的格式,譬如:
信件一開始就有 “Dear”,結束時又出現 “Your Best Regards”
。或者資料檔案都有一定的格式,攻擊者既然知道了明文,就可以依照這些標準格式去修改內容,以達到相同的雜湊值。我們用一個例子來說明,假設春嬌希望約志明明天見面(See you tomorrow),寫好了信件,並建立了雜湊值(也許經過加密),世雄找出 {See you yesterday}、{See you upset}、{don’t see you again} 等等,只要能符合相同的雜湊值即可,再將偽造信與春嬌簽署的簽署碼(加密的雜湊值)一起發送給志明。
- Reference: 雜湊
了解完 hash 之後,知道說如果今天想要破解 hash value 就是找出相同的 hash value ,但是以數學的觀點來看訊息經由雜湊演算法計算後,所產生的雜湊碼越長,則可能遺失的訊息就越少;如果採用較短的雜湊碼,可能遺失的訊息相對較多,不同訊息之間產生相同雜湊碼的機會也相對較大,這種觀念如同加密演算法,雜湊碼的位元數越長就越安全,因此攻擊者嘗試用不同的訊息來產生相同的 hash value ,有點像是暴力攻擊法,但在雜湊演算法常稱為生日攻擊法 (birthday attack)
數學上, birthday paradox 是要 n 個人同時在場,他們至少有一組人,生日在同一天的機率會超過 50% 以上,而現在換成 hash value 問題,變成
hacker 要嘗試 n 個訊息,即會有 50% 以上的機率產生至少一組相同 hash value
假設 hash value 的長度為 64 bits ,照該明文的格式修改其內容,譬如,保留原來空白鍵、使用較接近的文字,製造出其它偽造明文;並經過雜湊演算法計算出是否與原明文相同的雜湊值。
因此每次產生不同 hash value 的機率是
會產生相同的機率就是用全部的機率減掉產生不同的機率
,並且求得大於一半的 n
而可以看到一般電腦跑 46 億次,差不多 10s~1m,所以這個有一定程度的危險
因為基本上時間都會是唯一的,因此適合拿來做種子,但是若這隨機的程式攸關安全性,應該要具備不可預測性,而不是任何人都可以猜到的時間,因此有些程式或是硬體
為了滿足更嚴格的需求,現代的作業系統會定期蒐集硬體訊號攪拌入系統內建的位元池當中,供給應用程式作為產生亂數的依據。一些可能被使用的資訊像是:兩次鍵盤觸發的時間間隔、滑鼠移動距離、中斷觸發的時間間隔、甚至是各種硬體雜訊。這些資訊非常難以全盤掌握而且持續在更新,所以遠比純粹數學的方法安全,但也不是完全不可能破解。如果一個系統接受外部資訊的管道很少,理論上有可能被有心人士摸清內部狀態,甚至這些管道也有機會被操弄。
Reference: 電腦的隨機數是如何做到的?
但是事實上,這些亂數方式,看似是隨機,其實仍然是由一套明確的操作運算出來,如 c rand() 原始碼
Reference: gcc(github)、What common algorithms are used for C's rand()?
可以很明顯的看到這是一組可預期的數學運算,這一來其未必能稱作是真正的隨機,真正的隨機是不可預期,所以這些看似隨機卻並不是真正隨機的方式,稱具有偽隨機性(Pseudorandomness),如果直接下 man rand
看到說明第一句也程述出
因此對現在一般的電腦來說是不可能運算出真正的隨機,頂多使得這個類似隨機的機制夠亂、夠不可預期,或許如老師所說,之後的量子電腦將會成功時做出真正的亂數產生器
Reference: 你的程式夠「亂」嗎?、man rand(3)、量子電腦-曙光乍現、【量子密碼】亂數試金石
首先可以先理解兩者的差別
最主要的差別在於 macro 會在 compile 前,行處理,把該體換的地方替換掉,因此不像 function 一樣需要傳入參數,或是呼叫時要先紀錄狀態等等,相對的執行速度上就會較快,但是其是以空間換取時間的方式進行,而且 macro 的置換有相對的問題存在,如:operators priority、condition flow 等等
e.g.
整理出來就是
因此可以推測經常性使用的 linked list 用 macro 方式去編寫,可以提高速度
Reference: What is the difference between a macro and a function in C?、Macros vs Functions
linux/kernel.h
中也有類似的片段
int *my_ptr
指向 this_data
,用 container_of 可以找到裝此位址的變數位址,如下
list_replace
、list_empty
、 list_move_tail
這接雖然未必是必要的存在,但是如果有這些 function 可以使得工程師撰寫程式的負擔下降list_add_valid
、hlist_add_behind
、hlist_add_before
等等,可以方便性為寫出較好的程式碼,如一開始的註解說明
list_for_each_save
是安全的走訪每一個 node ,避免刪除的節點索引
pos=pos->next;
就會是錯誤的狀況,所以先複製一個 pos 暫存於 n 再往下走訪@params
,因此才會在註解中看到許多@。list_add
,然後再去用 assert()
檢查,所作的跟變化跟預期有沒有相同,因此這個 unit test 檔就是用來測試 list_add
是否有誤,其他在 tests/ 下的檔案皆是這個概念。list_add()
,還有第 30 行呼叫到 list_for_each_entry()
如果在測試時,出錯的卻是 list_for_each_entry()
會造成不必要的麻煩,所以應該盡量用原生的方式來做
list_for_each_entry()
,要在 list_add
前測試