部分摘要辨識可能嗎?
TL;博士
是否散列私鑰,然後異或
$$ ing $$秘密的摘要(遞歸兩次,帶有偏移量)有任何明顯的問題嗎? 部分摘要辨識可能嗎?
描述
- 使用者提供 16+ 個字元的私鑰
- 使用者提供了一個小於 128 個字元的秘密(暫時)
- 我們計算一個摘要
sha512(privateKey)
- 基於 ASCII 值 % 長度的加擾摘要 XOR 秘密
- 使用步驟#4 作為私鑰(XOR 等)再次執行此操作
- 解密使用相同的
method(privateKey)
- 這將變得更加複雜,但還沒有。
總體概述
我說服我的老闆接受在我們的網路應用程序中添加加密文章的想法;需要注意的是,他想要一些簡單的東西,因為這對於我們的大多數使用者(小學)來說是一個花哨的介紹,我們不會重新工作我們的後端,所以不幸的是沒有iv只是一個鍵
同樣,這不會隱藏關鍵資訊,也許是課堂筆記,在我看來,這只是一個很酷的功能,可能會激發後代對該領域的興趣。無論如何,我想出了這段程式碼:
/** * Encrypt * encrypt text using given key */ async function encrypt(text, key, loop = true) { // step 0. validate input if (text.length > 128) throw "message too large (128 max)"; if (key.length < 16) throw "key size too small (16 min)"; // step 1. generate hash from they key const hash = await sha512(btoa(key)); const pads = hash.length - text.length; // step 2. convert to UInt8Array const ecode = new TextEncoder(); const codex = ecode.encode(hash); const array = ecode.encode(text); // step 3. offset the XORs const multiplier = text.length * key.length; const round = array.map((value, i) => { const index = ((i + 1) * multiplier) % codex.length; return value ^ codex[index]; }); // step 4. convert to string const dcode = new TextDecoder(); let value = dcode.decode(round); // step 5. add additional rounds if (loop === true) { value = encrypt(value, hash + key, false); } // step 6. return value as string return value; } /** * Decrypt * decrypt cipher using given key */ async function decrypt(text, key) { const encoder = new TextEncoder(); const decoder = new TextDecoder(); // step 1. generate hash from they key const hash = await sha512(btoa(key)); // step 2. convert to UInt8Array const codex = encoder.encode(hash); const array = encoder.encode(text); // step 3. xor the results const output = array.map((value, i) => { const index = ((i + 1) * value) % codex.length; return value ^ codex[index]; }); // step 4. convert to string const value = decoder.decode(output); // step 5. return results return value; } /** * Generate sha512 digest * https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest */ async function sha512(message) { const msgUint8 = new TextEncoder().encode(message); // encode as (utf-8) Uint8Array const hashBuffer = await crypto.subtle.digest("SHA-512", msgUint8); // hash the message const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert buffer to byte array const hashHex = hashArray .map((b) => b.toString(16).padStart(2, "0")) .join(""); // convert bytes to hex string return hashHex; } /** * Test case */ async function main() { const key = "n,mWqrE@!#sS+Gbc$5"; const msg = "my namme is colin"; const out = await encrypt(msg, key); console.log({ out, len: out.length }); const txt = await encrypt(out, key); console.log({ txt, len: txt.length }); } main();
不使用解密功能;****encrypt雙向工作(目前)。我很好奇的是這次洩露的資訊以及可能需要緩解的攻擊媒介。當我有更多時間時,我計劃在此以及其他一些技巧上使用FFT 。
- 這只能遞歸呼叫一次
- 輸出長度是一樣的,但現在沒關係
我知道它不安全,但有多不安全?
未來的舉措
FFT 適用於多項式,我們可以使用數字值加上位置 as
position ** value
來構造複數值。後來的想法是壓縮中間值以
length
盡可能多地扭曲洩漏和傳輸大小$$ ? $$. 這些只是抽象的想法,還有一些其他的。
這裡有很多問題,但我會專注於那些跳出來的問題。打亂 XOR 排序的嘗試基本上什麼也沒做。首先,它幾乎 100% 依賴於攻擊者知道的資訊。使用原始密鑰長度會增加一些熵,但很少。即使撇開單個快速散列不適合密碼,因此“密鑰”可能是已知長度的預散列或隨機輸入,攻擊者可以簡單地嘗試所有這些的可能性也很少。
許多甚至大多數的法典值完全有可能永遠不會被使用。例如,如果乘數是偶數,那麼至少有一半的法典不會被使用,因為任何偶數都與 128 共享一個公因數 (2)。事實上,在不太可能的情況下,乘數是編解碼器長度的精確倍數 - 例如,如果文本正好是 128 個字節長(最大值),或者文本是 56 個(或 8 的其他倍數)長,並且密鑰是 16 個字節長(允許的最短值,以及一個非常常見的隨機密鑰長度:128 位) - 結果是災難。每個
((i + 1) * multiplier) % codex.length
單字節都將返回 0,因此明文 (array
) 的每個字節都將與相同的值(雜湊摘要的第一個字節)進行異或運算。即使在密鑰長度完全未知且消息長度不是 128 的倍數的情況下,攻擊者也可能會發現比僅知道消息長度的每 128 個字元更頻繁的重複。重複循環的長度最多為 128 / GCF(128, text.length),其中 GCF 是最大公因子函式。因此,如果文本長度是偶數,則將周期長度減半(如上所述,必要時將抄本減半)。如果文本長度是 8 的倍數,則循環長度將減少 8 倍(最多僅降至 16 ),消除 87.5% 的 codex 熵……這是最好的結果,假設密鑰長度相對以 codex 長度為質數(也就是說,假設密鑰長度是奇數)。
對於每個這樣的重複,可以預測重複位置的攻擊者可以將任何兩個對應的密文字節進行異或運算,以掩蓋密碼字節並獲得兩個明文字節的異或。如果攻擊者知道任何此類字節的值,他們可以立即解密使用該法典條目的所有其他位置。即使不知道這些值,如果您有足夠的重複值,也可以對重複執行頻率分析,以確定可能的明文值。這樣的分析將依賴於這樣一個事實,即某些字元在文本中以可預測的比率比其他字元更頻繁地出現。不同字元之間的異或是已知的這一事實使它變得更加容易,並且即使對於任何給定的法典條目的重複次數很少,也會有所補償。
這類問題——可靠地避免一個問題的失敗嘗試最終引入了潛在的災難性故障模式——在密碼學中非常常見,尤其是在業餘愛好者中。密碼學非常困難,尤其是如果您甚至沒有從過去嘗試的已知失敗開始。
話雖如此……我什至不是數論家或數學專業,更不用說密碼學家了;我的大部分數學知識只是獲得 CS 學位所需的知識。因此,我希望大量的人能夠並且會發現這個問題(而且知識淵博的人會發現很多很多),如果他們費心去看的話。
但是等等,還有更多!
在 XOR 步驟中,您將消息(文本)的每個字節與 codex 的單個字節(密鑰的 base64 散列)組合在一起,以生成密文。但是,雖然消息字節可以是 0-255 (0x0-0xFF) 範圍內的任何值,但 codex 是從十六進制編碼的字元串生成的。codex 的每個字節只能是 16 個值之一(0-9,af,編碼為十進制 48-57,97-102)。因此,對於每個密文字節,只有 16 個可能的明文字節(攻擊者知道它們是什麼)。這使得消息的簡單粗暴短部分成為可能;特別是對於遠離字元集中任何其他常用字元的常用字元(例如空格),無論您的鍵或乘數如何。這是一個災難性的弱點,
一些想法:
- 如果你真的想這樣做,為什麼不在 ECB 模式下使用流密碼(沒有 IV/nonce 或完整性)或分組密碼?兩者都不安全,但它們比這安全得多。這三種方法都有一個問題,即使用相同密鑰加密的兩條相同消息將具有相同的密文。您的密碼與流密碼有另一個問題(位翻轉攻擊是微不足道的),但即使是嚴重破壞的流密碼也沒有短週期問題,更不用說每字節 4 位熵的問題了。ECB 存在通過塊重複洩漏結構的問題,但它僅適用於塊邊界對齊塊之間所有 16 個字節(如果您使用像 AES 這樣的現代塊密碼)相同的塊。
- 或者,為什麼不能儲存 IV 和身份驗證/完整性標籤?消息的長度可變。
簡單的設計或程式碼質量問題,不一定會影響密碼的安全性:
key
如果包含任何多字節字元,則程式碼將拋出,因為atob
不允許這些字元。- 你為什麼還要打電話
atob
?它不是必需的。- 如果
text
包含任何多字節字元(在將密文解碼為 UTF-8 的步驟上),程式碼可能會拋出,因為並非所有字節序列都是有效的 UTF-8。- 您在測試中沒有遇到這個問題,因為您從未設置或清除最高有效位,並且每個字節的 MSB 未設置的所有字節序列都是有效的 UTF-8(實際上只是 ASCII),但您從未聲明或驗證這個前提。
- 即使程式碼沒有拋出,如果
text
包含在 UTF-8 中編碼為多個字節的任何字元,您可能會得到字元串長度出現在邊界內(即text.length
<= 128),但在編碼為 UTF-8 之後,長度array
可能會大大超過 128(單個 Unicode 字元可能需要 3 個甚至更多 UTF-8 字節),即使在最好的情況下也能保證重複使用 codex 值。- 您計算一個值 ,
pads
然後從不使用它。- 一次只能“工作”最多 128 個字節的密碼幾乎毫無價值,除非它可以用於分組密碼操作模式。大概這個限制是為了盡量避免codex值的重複,但代價是什麼?你說課堂筆記,但這甚至不能容納一條推文。
- 在知道最終消息長度完全不適合在任何需要性能的地方使用之前,不能做任何工作的密碼,因為這是通過流數據實現的。當然,前一點在很大程度上使它沒有實際意義。