一個比較重大的預(yù)告(BCSP)和一個不太重大的發(fā)表(shakenc)
不知不覺一個多小時干了小三千字,允許廣泛傳播的東西就發(fā)專欄吧()現(xiàn)在專欄展示方式也優(yōu)化了,不像以前人們會不愿意點(diǎn)進(jìn)去()
最近在寫一個類似于SSH/TLS,帶有用戶/訪客的密鑰登錄以及類似RPC的消息支持,可運(yùn)行在TCP/WS/RTCDataChannel多種底層協(xié)議的加密協(xié)議,叫做BCSP(Berylsoft Common Security Protocol或Berylsoft Client/Server Protocol),用于之后的多種項(xiàng)目。現(xiàn)代密碼學(xué)非常嚴(yán)謹(jǐn)和奇妙,千萬不要自己發(fā)明和實(shí)現(xiàn)用于生產(chǎn)的密碼學(xué)算法,即使是依據(jù)現(xiàn)代密碼學(xué)的原則組合這些算法形成自己的協(xié)議或者應(yīng)用也要千小心萬小心,乖孩子還是盡量不要學(xué)我搞協(xié)議了。
而我這個協(xié)議除了登錄和類RPC消息支持外,還有一個核心特點(diǎn)是:使用的算法少,有一個算法替代了很多算法。了解到這個算法的優(yōu)良特性也是我搞這個協(xié)議的重要原因。大家可能知道在SHA2之后NIST舉辦了SHA3算法選拔大賽,最終Keccak算法勝出并且成為了SHA3算法。Keccak的核心是一個“海綿函數(shù)”,這使得它其實(shí)可以輸出任意長度的hash值,所以NIST除了SHA3還標(biāo)準(zhǔn)化了兩個叫做SHAKE的算法,和相同位數(shù)的SHA3只是初始值不同,但卻擁有任意長度的輸出,來利用海綿函數(shù)的這個特點(diǎn)。那么一個任意長度輸出的hash函數(shù)(也就是XOF,Extend Output Function,以下沿用此稱)比一般的hash函數(shù)多出了什么用途呢?大家都知道一個優(yōu)良的hash函數(shù),其輸出是盡可能無法預(yù)測下一位的,也就是隨機(jī)的,那么首先一個XOF就是一個密碼學(xué)安全的偽隨機(jī)數(shù)生成器(CSPRNG),種子就是其輸入。其次大家應(yīng)該都聽說過一次性密碼本,這是唯一可以做到完全安全的加密方式(相對于現(xiàn)代密碼學(xué)安全是指可接受時間內(nèi)破譯的安全),也就是用與明文等長的一次性真隨機(jī)熵源對明文進(jìn)行異或進(jìn)行加密,接收端再用相同的熵源再異或一次進(jìn)行解密?,F(xiàn)實(shí)中交換與明文等長的真隨機(jī)熵源對于日常通信來說太過于困難了,于是人們退而求其次將這個真隨機(jī)熵源變成偽隨機(jī)熵源,以種子作為對稱密鑰,這就是流密碼,兩類主流對稱加密算法中除了AES這樣的塊密碼之外的另一種。流密碼具有優(yōu)良的性質(zhì),其性質(zhì)決定了它不像塊密碼那樣加密相同明文塊的密文相同,而且有些流密碼不需要硬件支持就能達(dá)成很快的速度。目前常見的有ChaCha20,移動端常用,它的速度就很快。而回憶一下剛才對XOF以及對它用于偽隨機(jī)數(shù)生成器的描述,大家應(yīng)該能很快明白實(shí)際上XOF也能作為流密碼使用,至少對于SHAKE函數(shù),Keccak團(tuán)隊(duì)認(rèn)可了這個用例。傳統(tǒng)hash函數(shù)也能完成的用例,如MAC(消息驗(yàn)證算法),SHAKE函數(shù)當(dāng)然也能勝任。實(shí)際上這樣一個接受任意長度輸入并且可以獲得任意長度的隨機(jī)輸出的函數(shù)還可以有很多有意思的用途,對信息論和密碼學(xué)敏感的應(yīng)該能有這個感覺。正是因?yàn)镾HAKE函數(shù)具有如此豐富的用例,NIST還定義了一個擴(kuò)展規(guī)范,其中包括了cSHAKE,允許添加一個NIST定義的name和一個用戶定義的custom string,改變海綿函數(shù)的初始狀態(tài),使得不同用途的SHAKE函數(shù)對于相同的輸入得到的輸出不同,因?yàn)槿绻蛔龅竭@一點(diǎn),是有可能造成攻擊面的,有興趣的可以自己查一下。基于cSHAKE,又定義了KMAC、TupleHash等不同用途的衍生函數(shù)。而我的協(xié)議正是通過盡可能多地利用cSHAKE函數(shù),減少了算法的數(shù)量。除了cSHAKE背后的Keccak以外,核心的密碼學(xué)算法就只有用于證書簽名和密鑰交換的Curve25519了,甚至我還不規(guī)范地將與Ed25519簽名過程綁定的SHA2-512函數(shù),也替換為cSHAKE256(有說法認(rèn)為SHA3-512被NIST加入了不必要的復(fù)雜性,對于SHA2-512的替代,SHAKE256輸出512位的強(qiáng)度已經(jīng)足夠),上一條動態(tài)的依賴上的麻煩就是始于這個替換的實(shí)現(xiàn)。這樣做使得協(xié)議的依賴輕便,并且我個人很喜歡,覺得有一種大道歸一的美。但是也不是沒有問題的,首先雖然Keccak團(tuán)隊(duì)認(rèn)可了這些用例,但是也不能說明它確實(shí)是合適的,尤其是和專為這些領(lǐng)域設(shè)計的算法相比,這么用很可能會引入一些作為常規(guī)hash函數(shù)碰不到的隱藏缺陷(我似乎已經(jīng)看到一篇SHAKE函數(shù)可能會生成潛在重復(fù)的模式的文章了),不過實(shí)際設(shè)計協(xié)議的時候我會注意對于一個狀態(tài)少取一些長度的輸出的。還有一個問題是雞蛋放在了同一個籃子里面,只要Keccak一個算法被發(fā)現(xiàn)缺陷,那么相比使用各種算法的一般加密協(xié)議,協(xié)議的更多部分就會陷入危險之中。(最近以SHAKE為切入點(diǎn),為了實(shí)現(xiàn)這個協(xié)議,看密碼學(xué)的東西快看吐了,能這么流暢一氣呵成倒出這一千多字也證明確實(shí)學(xué)進(jìn)去點(diǎn)東西,雖然核心算法原理沒怎么碰,以概念性的理論和實(shí)踐為主,畢竟你碰了難不成要自己發(fā)明或者實(shí)現(xiàn)或者修改嗎,這可是很危險的哦)
上面的是比較重大的預(yù)告,也算是一個背景介紹。下面是一個不太重大的發(fā)表。
昨天傳文件的時候,發(fā)現(xiàn)某網(wǎng)盤會限制分享文件的格式,而且似乎會檢測文件結(jié)構(gòu)。(之后搞WebRTC相關(guān)的東西也會順便搞一個端到端文件傳輸?shù)男」ぞ撸綍r候就用不著網(wǎng)盤了。)利用壓縮包的加密,縱然使用AES256,也只能實(shí)現(xiàn)對內(nèi)容物加密,從外面還是可以看出是一個壓縮包。正好最近在為上面的事情焦頭爛額,就決定順手寫一個利用(c)SHAKE來簡單加密整個文件的小工具。對整個文件加密之后,外表看就是一堆隨機(jī)數(shù),看不出任何文件結(jié)構(gòu),所以能實(shí)現(xiàn)避開文件結(jié)構(gòu)檢測。由于hash函數(shù)的輸入天然就是任意長的,密碼也可以是任意長,而簡單加密不需要那么嚴(yán)謹(jǐn),所以就沒用專用密碼hash算法(如果要做密碼登錄千萬要注意用專用密碼hash算法,比如argon2),密碼就是cSHAKE的輸入。一開始的版本很簡單,沒有緩沖區(qū)設(shè)計,把整個文件讀到內(nèi)存里,直接用SHAKE函數(shù)生成hash流并異或之后寫入整個文件,整個程序就二十多行。后來先是加入了緩沖區(qū);然后是可以動態(tài)設(shè)置緩沖區(qū)大小;然后是引入可以交互式輸入密碼的庫(防止密碼出現(xiàn)在shell歷史里);然后是把簡單的SHAKE改成了cSHAKE(Berylsoft的cSHAKE custom string范式是"__appname__use-purpose",有可能沒有appname,比如替換掉Ed25519的SHA2-512的時候用了一個"ed25519-cshake256");然后是想起對稱加密尤其是流密碼必須得校驗(yàn)(完整協(xié)議的話就直接用MAC了,密鑰內(nèi)容一塊校驗(yàn)),不然密碼不對發(fā)現(xiàn)不了,但是為了強(qiáng)調(diào)流密碼的特性,想做到輸入輸出長度完全相等,不想把校驗(yàn)hash放在文件里,想不指定是加密還是解密,就得把輸入和輸出的hash都算一遍,正好滿足更廣泛的需求,于是加上了輸入和輸出的hash計算并在最后顯示出來;因?yàn)镵eccak的特點(diǎn)決定了計算相同長度的輸入(absorb,海綿吸水)和輸出(squeeze,從海綿里擠水)耗時基本相等,而Keccak又基本沒有硬件加速,就導(dǎo)致速度直接慢了三倍,于是又費(fèi)了半天勁跟Option作對寫了可選hash,并且重新設(shè)計了抽象。這個時候已經(jīng)膨脹到一百多行了,然而我還想再加并行計算流密碼和兩個hash(因?yàn)橛衏ontext一說所以不能并行計算,這也是流密碼不用擔(dān)心塊密碼加密相同明文塊的密文相同的問題的原因,但是三個context之間可以并行計算),這又得加一堆channel之類的東西;還想加一個單獨(dú)直接輸出cSHAKE的輸出的選項(xiàng),這樣作為一個CSPRNG;分離一下bin和lib;可能還有別的想法但是寫了半天文章現(xiàn)在想到的就這些了。經(jīng)典十幾行臨時的小工具越寫想法越多。不過現(xiàn)在以及即使上面那些都加上去也不會很大的,得益于tiny-keccak實(shí)現(xiàn)小巧的體積,Windows release可執(zhí)行文件只有200KB左右。丟一個GitHub地址:
https://github.com/stackinspector/shakenc
有Rust環(huán)境的直接cargo install --git就可以裝上了,沒有的可以配一個(x

總的來說密碼學(xué)真好玩,尤其是不需要考慮生產(chǎn)環(huán)境安全的時候()不過我那個協(xié)議是需要考慮的,瑟瑟發(fā)抖和糾結(jié)中()