最近在Crypto 2023上看到一篇有趣的文章[1],其旨在一個存在擁有所有金鑰並知道所有訊息的“獨裁者”的通道中,透過安排與常規密文無法區分的隱藏的“變形”訊息來進行機密通訊的方法——變形簽名,但由於本人技術水平有限無法完整實現整個系統。而當閱讀到其中的一個技術分支——Chaffing and Winnowing時驚喜地發現其實現方法之巧妙,又恰好在圖靈班的密碼學課程中學到了相關的Diffie-Hellman金鑰交換協議和訊息驗證碼MAC等知識,於是選取這篇上世紀的論文[2]來進行評論和模擬實驗。
(是的你沒看錯,這是我在學校寫的某低水平評論論文,覺得方法比較新穎巧妙,於是分享出來)
摘要: 本文介紹了 Rivest 提出的 Chaffing and Winnowing 技術,該技術透過在訊息中混入無關資訊 (chaff) 並新增認證碼 (MAC) 來實現機密性,即使在擁有所有加密金鑰的“獨裁者”通道中進行通訊也能保證訊息安全。文章詳細闡述了該技術的原理、應用場景、潛在威脅以及未來研究方向,並透過實驗模擬實現了整個技術流程。
一、簡介
Rivest為我們介紹了一種新技術Chaffing and Winnowing——原意是指從穀粒中分離穀殼的過程,它不進行傳統意義上的加密,而是將訊息(wheat)分塊並作認證,混入無關資訊(chaff)之後再進行通訊。
該項技術可以說是變形簽名[1]的奠基之作,二者同樣考慮一個問題:若獨裁者擁有一個“後門”能夠恢復金鑰來對訊息進行解密,那麼如何在這樣的通道上為訊息提供機密性。Rivest說“像往常一樣,關於規範技術的政策辯論最終會被技術創新所淘汰。試圖透過規範加密來規範保密性,關閉了一扇門,卻留下了另外兩扇門(隱寫術和Chaffing and Winnowing).”後者與前者不同,隱寫術[3]注重於在較大的、看似普通的資訊(如圖片)中隱藏機密,使得在演算法不公開的前提下,一個PPT敵手無法有效區分機密內容和普通內容。顯然這樣的機密性是由演算法保密性提供,並不符合卡爾霍夫原則[4],即“一個密碼系統的安全性不應依賴於演算法的秘密性,而應依賴於金鑰的秘密性”。
而在Chaffing and Winnowing中,訊息機密性的保證被歸因到MAC演算法的認證性上,即在適應性選擇明文攻擊下具有存在不可偽造性[5]。對手無法懷疑兩種資料包的存在,不具有機密認證則亦無法區分它們,即使原訊息不受任何加密。
二、技術概要
原文中,作者循序漸進地介紹了這種技術的原理。
總體而言,傳送方與接收方共享一個金鑰,傳送訊息有兩個部分:認證(新增訊息認證碼MAC)和新增chaff;接收方會透過驗證MAC去除chaff(這個過程稱為“winnowing”)以獲得原始訊息。整個過程中,沒有對任何東西進行加密,因此可能不受出口管制(MAC不是加密)。
這是一個十分原始的想法,而後作者在考慮了實際運用的問題並做出諸多改進措施。
- 訊息包的拆分與組裝中,定義一個訊息包為包含序列號、訊息和MAC的三元組,以便接收方除重、組裝和識別丟失。並在這裡提出一種最佳化:傳送方按順序傳送包,接收方一旦驗證成功該序列號,則丟棄後續所有相同序列號的包。
- 一個良好的混淆過程會為訊息使用的每一個序列號至少新增一個chaff。
- 對手可能透過每個包裹的內容來區分chaff和wheat,無限拆分wheat只會讓傳輸更加低效。
為了解決以上問題,作者引用了自己的一項技術——全或無加密和包變換[11]。簡單來說,透過這種變換之後,只有接收者收到全部訊息才可逆轉變換得到原文,否則只能得到垃圾訊息。(讓我們把演算法具體實現放在模擬實驗的部分。)使用此變換後,再對訊息進行分包簽名和傳送,能夠減少敵手直接透過辨識訊息來查詢wheat組合的機會。
三、研究分類、現狀、難點分析與未來方向
我們現在已經瞭解到Chaffing and Winnowing技術的原理,可以發現資料包被分為了兩種——為己用和混淆視聽。前者的用法似乎已經固定,後者則隱藏著更大的利用潛能與危機。
1. 可否認加密[6]
如果對於每個wheat訊息包,都生成一個使用特定金鑰MAC認證的chaff,該chaff實際包含無害的訊息,當使用該特定金鑰進行認證時只能得到無害的訊息,而真正在通訊雙方交流的內容則被視為垃圾。如此使得在沒有正確的解密金鑰的情況下無法證明明文訊息的來源或存在,即可否認加密。缺點在於,如果暴力機關要求通訊者提供所有金鑰,則始終無法證明其是否已經提供全部金鑰。
2. 防止流量分析
我尚未查詢到已有的研究,只有維基百科中提及該技術的變體能夠在分組網路中防止訊息洩露和流量分析[7]。
3. 潛在的誣陷攻擊
試想通訊雙方之間存在一個發起中間人攻擊的主動敵手,能夠用自己的金鑰生成MAC並嵌入有害資訊,這對於通訊雙方接受訊息沒有影響。此時敵手擁有通訊的全文和自己的金鑰,則他可以對通訊雙方進行誣陷:指定其通訊內容為有害資訊而他們無法辯解。一方面,由於可否認加密的存在,他們可被認定為提供虛假無害的訊息金鑰;另一方面,通訊雙方根本沒有機密性需求,也沒有使用Chaffing and Winnowing技術,他們本身就沒有金鑰,敵手嵌入的資訊在通訊雙方的可忽視區內。
4. 如何協商一個私鑰
原文中僅用一個段落草草帶過雙方協商金鑰的過程——“例如”使用Diffie-Hellman金鑰交換協議[8],即通訊雙方交換對方的公鑰與自己的私鑰計算得到共有的金鑰。然而原始的協議僅在竊聽敵手存在的情況下是安全的,通訊雙方並不知道對方的身份,如果要抵禦主動攻擊敵手,則需要涉及數字證書和指定驗證者簽名[9]等技術。這不在作者Rivest討論的範圍內,因為他的安全目標規定獨裁者只知道加密金鑰,而不限制認證。
5. 訊息體積劇增與對抗暴力列舉
通訊雙方仍需傳送足夠量的chaff包以迷惑敵手,使之在計算上找到包的組合不可行。這也無疑增大了包的體積,加之需要足夠長度的MAC對抗碰撞。
目前該技術亟需解決的問題個人認為就是以上的3、4、5點;由此技術衍生的變形加密和變形簽名相關研究已連續兩年在CRYPTO發表[1][10]。
四、實驗模擬
以下使用C# .NET 9 on Windows平臺進行實驗,模擬通訊雙方使用Chaffing and Winnowing技術的全部過程。
1. 通訊雙方協商金鑰
生成ECDiffieHellmanCng實體並生成金鑰對,輸出公鑰,要求輸入私鑰後計算共同金鑰:
Console.WriteLine("Step 1: Key Exchange"); Console.WriteLine("Generating key..."); using var client = new ECDiffieHellmanCng() { KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash, HashAlgorithm = CngAlgorithm.Sha256 }; var publicKey = client.PublicKey.ToByteArray(); Console.WriteLine($"Public Key: {Convert.ToBase64String(publicKey)}"); Console.WriteLine("Enter the public key of the other party:"); string otherKey = Console.ReadLine(); byte[] otherPublicKey = Convert.FromBase64String(otherKey); var privateKey = client.DeriveKeyMaterial(CngKey.Import(otherPublicKey, CngKeyBlobFormat.EccPublicBlob));
2. 實現一個AONT變換
這裡採用原作者的簡單變換:將資料按BLOCK_SIZE分塊,生成與塊等大的隨機生成的金鑰塊key,將每個資料塊與key逐位元異或得到結果,再將key與結果做異或儲存在結果的最後一塊之後:
public static readonly int BLOCK_SIZE = 16; public static byte[] Transform(byte[] data){ int blocks= (data.Length+BLOCK_SIZE-1)/BLOCK_SIZE; byte[] result = new byte[(blocks+1)*BLOCK_SIZE];//reserve one block for the hash byte[] key= new byte[BLOCK_SIZE]; RandomNumberGenerator.Fill(key); Console.WriteLine($"Key: {string.Join(',',key)}"); for(int i=0;i<blocks;i++){ int offset = i*BLOCK_SIZE; for(int j=0;j<BLOCK_SIZE&&offset+j<data.Length;j++){ result[offset+j]=(byte)(data[offset+j]^key[j]); } } for(int i=0;i<blocks*BLOCK_SIZE;i++){ key[i%BLOCK_SIZE]^=result[i]; //key XOR with data blocks } Array.Copy(key,0,result,blocks*BLOCK_SIZE,BLOCK_SIZE); Console.WriteLine($"Last Block: {string.Join(',',key)}"); return result; }
逆變換即先按BLOCK_SIZE分塊,取出最後一塊,依次與資料塊做異或,解出key,再用key與資料塊做異或還原原始資料。(注意,後續分包時,包的大小應該為BLOCK_SIZE的整數倍,以確保key按照相同的方式還原;逆變換時可能發現最後一塊為{0}*,這並不影響解除key,因為與0異或為其本身。)
public static bool Reverse(byte[] data,out byte[] result){ if(data.Length%BLOCK_SIZE!=0){ result=null; return false; } int oriBlocks = data.Length/BLOCK_SIZE-1; result= new byte[oriBlocks*BLOCK_SIZE]; byte[] key= new byte[BLOCK_SIZE]; Array.Copy(data,oriBlocks*BLOCK_SIZE,key,0,BLOCK_SIZE); Console.WriteLine($"Last Block: {string.Join(',',key)}"); for(int i=0;i<oriBlocks*BLOCK_SIZE;i++){ key[i%BLOCK_SIZE]^=data[i]; //key XOR with data blocks } Console.WriteLine($"Key: {string.Join(',',key)}"); for(int i=0;i<oriBlocks;i++){ int offset = i*BLOCK_SIZE; for(int j=0;j<BLOCK_SIZE&&offset+j<result.Length;j++){ result[offset+j]=(byte)(data[offset+j]^key[j]); } } return true; }
以上,如果不首先訪問訊息的每個塊,就不可能恢復原始明文。
有後人使用更復雜的演算法實現AONT,例如使用線性變換而無任何加密假設的Stinson 演算法[12]。似乎能提供更高的安全性。
呼叫ANOT變換,這裡預先設定了傳送的訊息。
Console.WriteLine("Step 2: AONT"); string content = """ The power to authenticate is in many cases the power to control, and handing all authentication power to the government is beyond all reason. -- Ronald L. Rivest, 1998 """; byte[] dataBytes = Encoding.UTF8.GetBytes(content); byte[] transformed = AONT.Transform(dataBytes);
3. 建立MAC訊息驗證碼
這裡使用HMAC-SHA256演算法[13][14]給出簡單的MAC演算法三元組,其中Gen已由最初的金鑰交換提供。
public static byte[] Sign(byte[] key,byte[] data){ using var hmac = new HMACSHA256(key); return hmac.ComputeHash(data); } public static bool Verify(byte[] key,byte[] data,byte[] signature){ using var hmac = new HMACSHA256(key); byte[] computed = hmac.ComputeHash(data); return computed.Length==signature.Length&&computed.AsSpan().SequenceEqual(signature); }
4. 分包和簽名
Console.WriteLine("Step 3: Packaging and Signing"); int numBlocks = (transformed.Length + BLOCK_SIZE - 1) / BLOCK_SIZE; List<Package> packages = []; for (int index = 0; index < numBlocks; index++) { int offset = index * BLOCK_SIZE; int blockSize = Math.Min(BLOCK_SIZE, transformed.Length - offset); byte[] block = new byte[BLOCK_SIZE]; Array.Copy(transformed, offset, block, 0, blockSize); byte[] signature = HMACHelper.Sign(privateKey, block); packages.Add(new Package(index, block, signature)); } int packageCount = packages.Count; Console.WriteLine($"Wheat packages: {packageCount}");
5. 加入帶有隨機資料的chaff
Console.WriteLine("Step 4: Adding Chaff Packages"); var rand = new Random(); for (int i = 0; i < packageCount; i++) { int randCount = rand.Next(1, 5); for (int j = 0; j < randCount; j++) { var randData = new byte[BLOCK_SIZE]; RandomNumberGenerator.Fill(randData); var randSignature = new byte[32]; RandomNumberGenerator.Fill(randSignature); packages.Add(new Package(i, randData, randSignature)); } } var sendPkg = packages.OrderBy(p => p.index);
6. 模擬傳送
將所有的包按照index順序排列後以Base64編碼輸出模擬傳送,在接收端輸入內容模擬接收。Base64編碼能將byte[]轉為文字格式,便於實驗。
Console.WriteLine("Step 5: Sending Packages"); foreach (var pkg in sendPkg) { Console.WriteLine($"{pkg.index},{Convert.ToBase64String(pkg.data)},{Convert.ToBase64String(pkg.signature)}"); } Console.ReadLine();
7. 模擬接收
要求輸入所有的包,鍵空以結束。
Console.WriteLine("Enter packages, done with empty line:"); List<Package> received = []; try { while (true) { string line = Console.ReadLine(); if (string.IsNullOrEmpty(line)) break; string[] parts = line.Split(','); int index = int.Parse(parts[0]); byte[] data = Convert.FromBase64String(parts[1]); byte[] signature = Convert.FromBase64String(parts[2]); received.Add(new Package(index, data, signature)); } Console.WriteLine($"Received packages: {received.Count}"); } catch { Console.WriteLine("Invalid input."); continue; }
8. Winnowing和逆變獲得原訊息
Console.WriteLine("Winnowing..."); var wheat = received.Where(p => HMACHelper.Verify(privateKey, p.data, p.signature)).OrderBy(p => p.index).ToList(); var wheatCount = wheat.Count; Console.WriteLine($"Wheat packages: {wheatCount}"); Console.WriteLine("Reverse AONT..."); byte[] assembly = new byte[wheatCount * BLOCK_SIZE]; for (int i = 0; i < wheatCount; i++) { Array.Copy(wheat[i].data, 0, assembly, i * BLOCK_SIZE, BLOCK_SIZE); } Console.WriteLine($"Assembly: {Convert.ToBase64String(assembly)}"); if (AONT.Reverse(assembly, out byte[] result)) { Console.WriteLine($"Result: {Encoding.UTF8.GetString(result)}"); } else { Console.WriteLine("Reverse failed."); }
9. 測試
兩例項交換公鑰並在內部生成私鑰:
傳送方生成訊息包:
接收方收到不完整包流,逆變得到亂碼;如果接受不完整塊流,逆變將失敗:
只有完整獲得包流才能解出原始資訊:
註釋:為了方便起見,這裡沒有處理原訊息長度,padding產生的位元組被編為亂碼。
在實際運用中,包的結構並非像實驗中一樣直接暴露。
以上實驗專案程式碼在Github上[16]由本人公開。
五、結論
Chaffing and Winnowing 技術提供了一種非傳統的思路,利用 MAC 的認證性為訊息提供機密性保障,即使在擁有所有加密金鑰的通道中也能保證訊息安全。該技術具有潛在的應用價值,但仍需解決一些挑戰,例如協商私鑰的安全性和訊息體積的膨脹。未來研究可以探索更復雜的混淆過程、更高效的壓縮演算法以及更安全的金鑰協商協議,以進一步提升 Chaffing and Winnowing 技術的安全性、效率和實用性。
參考文獻:
[1] Kutyłowski, M., Persiano, G., Phan, D.H., Yung, M., Zawada, M. (2023). “Anamorphic Signatures: Secrecy from a Dictator Who Only Permits Authentication!”. In: Handschuh, H., Lysyanskaya, A. (eds) Advances in Cryptology – CRYPTO 2023. Lecture Notes in Computer Science, vol 14082. Springer, Cham. https://doi.org/10.1007/978-3-031-38545-2_25
[2] Ronald L. Rivest. “Chaffing and Winnowing: Confidentiality without Encryption”. Cryptobytes, Summer 1998. MIT Laboratory for Computer Science. Web. 23 Nov. 2024. https://people.csail.mit.edu/rivest/pubs/Riv98a.pdf
[3] Peter Wayner. 1996. “Disappearing cryptography: being and nothingness on the net”. Academic Press Professional, Inc., USA. https://dl.acm.org/doi/10.5555/229879
[4] Kerckhoffs, A. (1883). “La cryptographie militaire”. Journal des sciences militaires. https://www.petitcolas.net/kerckhoffs/crypto_militaire_1.pdf
[5] Krawczyk, H., Bellare, M., and R. Canetti, “HMAC: Keyed-Hashing for Message Authentication”, RFC2104, February 1997. https://www.rfc-editor.org/rfc/rfc2104
[6] Canetti, Ran, Cynthia Dwork, Moni Naor, and Rafail Ostrovsky, “Deniable Encryption”, Proceedings CRYPTO ’97 (Springer 1997). https://link.springer.com/content/pdf/10.1007/BFb0052229.pdf
[7] Chaffing and Winnowing – Variations WikiPedia. https://en.wikipedia.org/wiki/Chaffing_and_winnowing#Variations
[8] Diffie, Whitfield; Hellman, Martin E. (November 1976). “New Directions in Cryptography”. IEEE Transactions on Information Theory. https://ee.stanford.edu/~hellman/publications/24.pdf
[9] Jakobsson, Markus, Kazue Sako, and Russell Impagliazzo, “Designated Verifier Proofs and Their Applications’’, Pro-ceedings Eurocrypt ’ 96 (Springer 1996), 143—154. https://link.springer.com/content/pdf/10.1007/3-540-68339-9_13.pdf
[10] Persiano, G., Phan, D.H., Yung, M. (2022). “Anamorphic Encryption: Private Communication Against a Dictator”. In: Dunkelman, O., Dziembowski, S. (eds) Advances in Cryptology – EUROCRYPT 2022. EUROCRYPT 2022. Lecture Notes in Computer Science, vol 13276. Springer, Cham. https://doi.org/10.1007/978-3-031-07085-3_2
[11] Rivest, R. “All-Or-Nothing Encryption and the Package Transform”. Proceedings of the 1997 Fast Software Encryption Conference (Springer, 1997). https://people.csail.mit.edu/rivest/pubs/Riv97d.pdf
[12] Stinson, D.R. “Something About All or Nothing (Transforms)”. Designs, Codes and Cryptography 22, 133–138 (2001). https://link.springer.com/article/10.1023/A:1008304703074
[13] HMACSHA256 Class (System.Security.Cryptography) | Microsoft Learn. https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.hmacsha256
[14] Preneel, B. (2024). “HMAC”. In: Jajodia, S., Samarati, P., Yung, M. (eds) Encyclopedia of Cryptography, Security and Privacy. Springer, Berlin, Heidelberg. https://doi.org/10.1007/978-3-642-27739-9_581-2
[15] Siriwardena, P. (2020). “Base64 URL Encoding”. In: Advanced API Security. Apress, Berkeley, CA. https://doi.org/10.1007/978-1-4842-2050-4_20
[16] TwilightLemon/TestCWCrypto | Github. https://github.com/TwilightLemon/TestCWCrypto
本作品採用 知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議 進行許可。歡迎轉載、使用、重新發布,但務必保留文章署名TwilightLemon(https://blog.twlmgatito.cn),不得用於商業目的,基於本文修改後的作品務必以相同的許可釋出。