魏 榮, 鄭昉昱, 林璟鏘
1. 中國(guó)科學(xué)院 信息工程研究所 信息安全國(guó)家重點(diǎn)實(shí)驗(yàn)室, 北京100093
2. 中國(guó)科學(xué)院 數(shù)據(jù)與通信保護(hù)研究教育中心, 北京100093
3. 中國(guó)科學(xué)院大學(xué) 網(wǎng)絡(luò)空間安全學(xué)院, 北京100049
4. 中國(guó)科學(xué)技術(shù)大學(xué) 網(wǎng)絡(luò)空間安全學(xué)院, 合肥230026
Web 應(yīng)用是指以B/S (瀏覽器/服務(wù)器, Browser/Server) 模式提供服務(wù)的網(wǎng)絡(luò)程序, 相對(duì)C/S (客戶(hù)端/服務(wù)器, Client/Server) 架構(gòu)的傳統(tǒng)桌面應(yīng)用而言, 其具有跨平臺(tái)、兼容性好、維護(hù)成本低、免安裝的優(yōu)勢(shì), 因而在近年來(lái)迅猛發(fā)展, 甚至曾一度出現(xiàn)了Web 應(yīng)用取代桌面應(yīng)用的呼聲.
當(dāng)然, 在未來(lái)相當(dāng)長(zhǎng)的一段時(shí)期內(nèi), Web 應(yīng)用都難以完全淘汰桌面應(yīng)用, 因?yàn)樗艿搅吮镜刭Y源訪(fǎng)問(wèn)限制、網(wǎng)絡(luò)設(shè)施建設(shè)等因素的影響, 除了在功能豐富度方面無(wú)法與桌面程序比擬外, 其響應(yīng)速度也極度依賴(lài)網(wǎng)絡(luò)性能, 常出現(xiàn)內(nèi)容加載緩慢等問(wèn)題, 而最致命的還是Web 技術(shù)在實(shí)現(xiàn)密碼運(yùn)算時(shí)天然存在的短板:
(1) Web 應(yīng)用的鑒權(quán)過(guò)程往往需要將用戶(hù)口令發(fā)送到服務(wù)端進(jìn)行比對(duì), 盡管客戶(hù)端會(huì)使用加鹽哈希來(lái)予以一定保護(hù), 但仍不能徹底解決竊聽(tīng)、重放等問(wèn)題;
(2) 雖然一些口令身份鑒別機(jī)制可以讓W(xué)eb 應(yīng)用不用發(fā)送口令信息就能完成密鑰協(xié)商, 例如EKE(Encrypted Key Exchange)[1]、J-PAKE (Password-Authenticated Key Exchange by Juggling)[2]等, 但需要客戶(hù)端能夠完成較為復(fù)雜的密碼運(yùn)算——如果以瀏覽器密碼插件的形式實(shí)現(xiàn), 則要求插件程序兼容各個(gè)系統(tǒng)平臺(tái)和瀏覽器內(nèi)核, 維護(hù)成本較高; 而如果讓JavaScript 來(lái)完成這部分工作, 則要求瀏覽器內(nèi)核對(duì)JavaScript 的解釋速度足夠快, 以免影響用戶(hù)體驗(yàn);
(3) 雖然瀏覽器都內(nèi)置了HTTPS (Hyper Text Transfer Protocol over Secure Socket Layer, 超文本傳輸安全協(xié)議) 功能, 但該功能只提供統(tǒng)一的認(rèn)證、加密和完整性保護(hù)服務(wù), 開(kāi)發(fā)者無(wú)法利用其內(nèi)置的密碼算法來(lái)實(shí)現(xiàn)自定義的安全協(xié)議.
不難看出, 讓JavaScript 承擔(dān)密碼運(yùn)算工作是Web 應(yīng)用發(fā)展的大勢(shì)所趨, 由于終端設(shè)備和瀏覽器多種多樣, 性能良莠不齊, 難免有人擔(dān)心作為腳本語(yǔ)言的JavaScript 無(wú)法勝任復(fù)雜運(yùn)算工作(如橢圓曲線(xiàn)標(biāo)量乘). 不過(guò), 隨著近年來(lái)計(jì)算機(jī)硬件性能大幅度提升和瀏覽器內(nèi)核更新?lián)Q代, JavaScript 的執(zhí)行速度已經(jīng)有了很大改觀(guān), 可以勝任復(fù)雜密碼運(yùn)算的工作, 尤其是移動(dòng)互聯(lián)網(wǎng)時(shí)代的到來(lái)和HTML5[3](HyperText Markup Language 5, 超文本標(biāo)記語(yǔ)言5) 技術(shù)的發(fā)展, 使得Web 應(yīng)用在智能移動(dòng)終端中也大放異彩. 讓前端腳本承擔(dān)更多力所能及的計(jì)算工作已然時(shí)機(jī)成熟.
而在我國(guó), 由于計(jì)算機(jī)硬件、操作系統(tǒng)和軟件設(shè)施建設(shè)長(zhǎng)期落后國(guó)際水平, 導(dǎo)致缺乏基本的國(guó)產(chǎn)化軟硬件平臺(tái), 國(guó)產(chǎn)密碼推進(jìn)工作遲滯. 雖然SM2[4-8]、SM3[9]和SM9[10-14]算法已經(jīng)上升為國(guó)際標(biāo)準(zhǔn), 但要得到主流瀏覽器內(nèi)核的支持, 還有相當(dāng)長(zhǎng)的路要走. 目前也只有360[15]、密信[16]、贏達(dá)信[17]等個(gè)別企業(yè)推出了支持國(guó)密算法的瀏覽器產(chǎn)品, 其普及度還很低, 而國(guó)內(nèi)為數(shù)眾多的Web 應(yīng)用都還在使用國(guó)外密碼算法來(lái)保障數(shù)據(jù)安全, 其中不乏MD5、SHA-1、DES、RSA-1024 等已經(jīng)被建議淘汰或明令禁止的不安全算法.
值得高興的是, 使用JavaScript 實(shí)現(xiàn)密碼算法不必拘泥于軟硬件平臺(tái)的限制, 這意味著我們可以方便地使用國(guó)產(chǎn)密碼算法, 不用考慮瀏覽器是否支持的問(wèn)題.
我們旨在用JavaScript 實(shí)現(xiàn)一款適用于Web 應(yīng)用的通用密碼庫(kù), 可以提供國(guó)密SM2、SM3 和SM4[18]算法, 并保證該庫(kù)壓縮后的大小控制在50 KB 以?xún)?nèi).
在Web 應(yīng)用中, JavaScript 的性能體現(xiàn)在加載速度和執(zhí)行速度兩方面, 而這兩者往往處于對(duì)立關(guān)系. 例如, AES (Advanced Encryption Standard, 高級(jí)加密標(biāo)準(zhǔn)) 算法在OpenSSL 中的實(shí)現(xiàn)采用了TTable[19]和循環(huán)展開(kāi)的技巧, 前者將狀態(tài)矩陣每一列的列混淆和字節(jié)代替操作融合在一張1 KB 大小的查找表中, 只需一次訪(fǎng)存就可以完成上述變換, 還可以省略行移位步驟, 但該方法需要加密和解密函數(shù)各自維護(hù)4 KB 大小的查找表, 這在本地應(yīng)用中并不算很大的存儲(chǔ)負(fù)載, 不過(guò)在Web 應(yīng)用中, 從服務(wù)端下載8 KB 的查找表會(huì)明顯增加網(wǎng)絡(luò)延遲; 循環(huán)展開(kāi)方式也存在類(lèi)似問(wèn)題, 以AES-128 為例, 如果將循環(huán)展開(kāi),則會(huì)導(dǎo)致主函數(shù)代碼量增加近十倍, 同樣會(huì)顯著增加網(wǎng)絡(luò)延遲. 因此, 在實(shí)現(xiàn)算法時(shí), 應(yīng)權(quán)衡代碼量和執(zhí)行速度之間的利害取舍, 對(duì)可以通過(guò)少許代碼預(yù)計(jì)算出來(lái)的常量, 盡量延后到本地生成, 以減小流量消耗, 但也要注意, 預(yù)計(jì)算的時(shí)間開(kāi)銷(xiāo)不宜過(guò)長(zhǎng).
當(dāng)然, 針對(duì)JavaScript 難以進(jìn)行高性能計(jì)算的問(wèn)題, 最理想的解決方案還是盡可能利用設(shè)備本地的資源和計(jì)算能力, 這樣不僅可以避免重復(fù)下載密碼庫(kù), 還可以省去腳本解釋執(zhí)行的漫長(zhǎng)過(guò)程, 在Web 技術(shù)的發(fā)展過(guò)程中, 也確實(shí)產(chǎn)生了很多相關(guān)的支撐技術(shù), 例如現(xiàn)代瀏覽器普遍支持的JIT (Just In Time,即時(shí)) 編譯技術(shù)[20]大大彌補(bǔ)了JavaScript 作為腳本語(yǔ)言的天然速度劣勢(shì); 此外, 還出現(xiàn)了WebGL[21]、WebAssembly[22]、和asm.js[23]等更深程度的優(yōu)化執(zhí)行技術(shù), 它們力求讓JavaScript 的運(yùn)行速度能夠媲美Native 代碼, 然而, 除了瀏覽器支持程度不理想外, 其較大的編譯輸出會(huì)嚴(yán)重增加下載時(shí)間; 隨著HTML5 技術(shù)的發(fā)展, 一些主流瀏覽器也加入了對(duì)Web Worker[24]的支持, 從而改變了長(zhǎng)期以來(lái)JavaScript 只能單線(xiàn)程執(zhí)行的狀況, 讓W(xué)eb 應(yīng)用也開(kāi)始步入并行計(jì)算的時(shí)代.
上述各種技術(shù)的演進(jìn)都是以提升用戶(hù)體驗(yàn)為導(dǎo)向的, 其優(yōu)先考慮的是頁(yè)面渲染和響應(yīng)速度, 而非數(shù)據(jù)安全問(wèn)題, 密碼庫(kù)的開(kāi)發(fā)者可以對(duì)其加以利用, 以提高密碼計(jì)算效率, 但敏感數(shù)據(jù)的安全暫時(shí)還要靠瀏覽器的隔離機(jī)制來(lái)保證.
考慮到瀏覽器中的數(shù)據(jù)安全問(wèn)題, W3C (World Wide Web Consortium, 萬(wàn)維網(wǎng)聯(lián)盟) 于2017 年正式提出了關(guān)于Web Cryptography API[25]的建議, 期望能夠以JavaScript 接口形式為Web 應(yīng)用提供基礎(chǔ)的密碼服務(wù), 各主流瀏覽器也開(kāi)始加入對(duì)上述接口的實(shí)現(xiàn). 由于處于更底層位置, 這類(lèi)密碼服務(wù)的性能遠(yuǎn)比第三方JavaScript 密碼庫(kù)更接近Native 代碼[26], 但截至目前, 不同瀏覽器所實(shí)現(xiàn)的算法集合或多或少都存在差別, 只有極個(gè)別瀏覽器(如Samsung Internet[27]) 完整實(shí)現(xiàn)了所有API[28]. 因此, 在未來(lái)很長(zhǎng)一段時(shí)期內(nèi), Web 開(kāi)發(fā)者依然需要集成自己的JavaScript 密碼庫(kù)以備不時(shí)之需.
可見(jiàn), 即便是應(yīng)用廣泛的國(guó)際算法, 也未能如HTTPS 一般成為瀏覽器的標(biāo)配功能, 而在國(guó)外廠(chǎng)商占據(jù)主流瀏覽器市場(chǎng)的今天, 國(guó)產(chǎn)密碼算法要得到瀏覽器的集成則更是任重道遠(yuǎn). 2017 年, 中科院DCS 中心研制了通過(guò)Windows CNG[29]接口提供服務(wù)的國(guó)產(chǎn)商用密碼算法庫(kù), 并基于該庫(kù)研制了支持商密算法的Edge 瀏覽器和IE 瀏覽器[30], 上述兩款瀏覽器利用了操作系統(tǒng)的密碼服務(wù)來(lái)為Web 程序提供更安全的密碼功能, 這也是未來(lái)Web 密碼服務(wù)形態(tài)的一大發(fā)展方向——Web 應(yīng)用中的密碼服務(wù)最終是要沉降到更為快速和安全的瀏覽器內(nèi)核甚至操作系統(tǒng)中來(lái)實(shí)現(xiàn)的. 但與前文所述的技術(shù)類(lèi)似, 上述產(chǎn)品也僅僅提供了基于Windows 10 系統(tǒng)上兩種瀏覽器的密碼服務(wù), 并不具備普適性, 鑒于我國(guó)在操作系統(tǒng)和瀏覽器領(lǐng)域長(zhǎng)期落后的現(xiàn)狀, JavaScript 庫(kù)仍將是國(guó)產(chǎn)密碼算法入駐瀏覽器的主要形態(tài).
本節(jié)主要闡述JavaScript 庫(kù)中對(duì)國(guó)密算法的實(shí)現(xiàn)和優(yōu)化方案, 并不介紹原算法過(guò)程, 讀者如果想了解算法原理, 可以查閱相關(guān)國(guó)密標(biāo)準(zhǔn)[4-8,18,31].
目前已經(jīng)有很多較為著名的JavaScript 國(guó)際密碼算法庫(kù), 如clipperz[32]、OpenPGP.js[33]、sjcl[34]、jwcrypto[35]、cryptico[36]、jscrypto[37]和cryptojs[38]等. 綜合考慮文件大小、代碼架構(gòu)、密碼算法集合和優(yōu)化程度, 我們決定基于sjcl 庫(kù)完成對(duì)國(guó)產(chǎn)密碼算法的集成和優(yōu)化.
sjcl 是由斯坦福大學(xué)Stark 等于2009 年推出的一款適用于瀏覽器和Node JS 平臺(tái)的JavaScript 密碼庫(kù), 該庫(kù)最初圍繞AES 算法進(jìn)行優(yōu)化實(shí)現(xiàn), 隨著版本演進(jìn), 目前已經(jīng)能夠支持國(guó)際上常用的對(duì)稱(chēng)、非對(duì)稱(chēng)密碼算法、哈希算法、消息認(rèn)證函數(shù)、KDF (Key Derivation Function, 密鑰派生函數(shù)) 以及隨機(jī)數(shù)發(fā)生函數(shù), 成為了一款比較全面的密碼套件, 該庫(kù)還針對(duì)腳本加載速度進(jìn)行了一定程度的優(yōu)化, 以提升用戶(hù)體驗(yàn).
相比上文中其他較流行的密碼庫(kù), sjcl 重點(diǎn)關(guān)注密碼原語(yǔ)的優(yōu)化實(shí)現(xiàn), 而非更高層的通信或密碼協(xié)議,因此非常精簡(jiǎn), 具有更小的體量和更好的兼容性, 這不僅體現(xiàn)在平臺(tái)兼容性上(它通過(guò)了Mac、Linux 和Windows 系統(tǒng)下所有主流瀏覽器的測(cè)試), 還體現(xiàn)在對(duì)舊的ES5[39](ECMAScript 5) 標(biāo)準(zhǔn)的完美兼容上.
更重要的是, sjcl 庫(kù)的模塊化代碼結(jié)構(gòu)對(duì)二次開(kāi)發(fā)非常友好, 各個(gè)模塊之間的松散耦合便于開(kāi)發(fā)者根據(jù)實(shí)際需要選擇性地打包, 隨時(shí)去除不必要的功能, 這有利于縮減文件大小, 同時(shí)也讓該庫(kù)具備了很好的可擴(kuò)展性, 新算法的集成工作比其他同類(lèi)庫(kù)更為方便. 此外, sjcl 庫(kù)一直致力于針對(duì)Web 應(yīng)用場(chǎng)景對(duì)密碼算法進(jìn)行特殊優(yōu)化[34], 相比同類(lèi)密碼庫(kù), 它在文件大小和運(yùn)算速度之間達(dá)到了較好的平衡[26].
我們基于sjcl 密碼庫(kù)的框架, 用JavaScript 實(shí)現(xiàn)了SM2 簽名和加密算法、SM3 摘要算法和SM4 對(duì)稱(chēng)加密算法, 支持瀏覽器和Node JS 平臺(tái), 接口與sjcl 庫(kù)保持了風(fēng)格一致, 繼承了其調(diào)用簡(jiǎn)單的優(yōu)點(diǎn); 與此同時(shí), 針對(duì)最為耗時(shí)的ECC (Elliptic Curves Cryptography, 橢圓曲線(xiàn)密碼學(xué)) 算法, 我們也進(jìn)行了一定程度的優(yōu)化, 將ECC 密鑰生成和簽名速度提升了一倍.
由于sjcl 庫(kù)代碼架構(gòu)的原因, 對(duì)SM2 算法的優(yōu)化實(shí)際上也可以惠及庫(kù)中其他ECC 算法.
對(duì)ECC 橢圓曲線(xiàn)算法的優(yōu)化通常集中在最為耗時(shí)的點(diǎn)乘運(yùn)算上, sjcl 庫(kù)用了常見(jiàn)的固定基窗口方式[40]來(lái)加速點(diǎn)乘, 但沒(méi)有對(duì)乘法標(biāo)量進(jìn)行長(zhǎng)度擴(kuò)充, 使其與橢圓曲線(xiàn)基點(diǎn)的階等長(zhǎng), 容易在時(shí)序分析下暴露乘法標(biāo)量(如私鑰) 長(zhǎng)度信息, 當(dāng)然, 這只是一個(gè)小問(wèn)題, 我們對(duì)其進(jìn)行了修復(fù).
考慮到內(nèi)存占用和預(yù)計(jì)算的時(shí)間開(kāi)銷(xiāo), sjcl 庫(kù)所選的窗口寬度為4. 例如, 對(duì)256 位長(zhǎng)的標(biāo)量乘數(shù)t 和點(diǎn)P, 通過(guò)64 次“訪(fǎng)存-16 倍點(diǎn)-點(diǎn)加” 操作來(lái)完成[t]P 運(yùn)算, 步驟如下:
(1) 將t 表示為16 進(jìn)制:
(2) 計(jì)算所有Pk=[k]P, 其中k =0,1,··· ,15;
(3) 按公式(1)計(jì)算[t]P:
還有一種固定基的comb 方法[9], 以另外一種形式來(lái)分割乘法標(biāo)量, 通過(guò)64 次“訪(fǎng)存-2 倍點(diǎn)-點(diǎn)加”操作來(lái)計(jì)算[t]P, 但是乘法標(biāo)量的預(yù)處理和查找表的預(yù)計(jì)算也相對(duì)更繁瑣一些. 以模長(zhǎng)l = 256, 窗口寬w =4 為例, 使用固定基comb 方法計(jì)算[t]P 的步驟如下:
(1) 將t 表示為二進(jìn)制, 并均分為4 部分:
(2) 計(jì)算所有[2192s3+2128s2+264s1+s0]P, 記作Pk, k =s3|s2|s1|s0, s0、s1、s2和s3為0 或1;
(3) 按公式(2)計(jì)算[t]P:
與窗口方法不同, comb 方法的預(yù)計(jì)算無(wú)法只通過(guò)點(diǎn)加和倍點(diǎn)完成, 需要調(diào)用點(diǎn)乘方法, 因而不能在點(diǎn)乘運(yùn)行時(shí)進(jìn)行. 該方法更適合將預(yù)計(jì)算結(jié)果直接硬編碼在程序中, 但這種做法與sjcl 庫(kù)精簡(jiǎn)代碼、降低下載流量的設(shè)計(jì)原則不符, 加之預(yù)計(jì)算比窗口方法耗時(shí), 最終沒(méi)有被sjcl 庫(kù)采納.
不過(guò), 對(duì)于固定點(diǎn)(如橢圓曲線(xiàn)基點(diǎn)) 乘法來(lái)說(shuō), comb 方法只需在曲線(xiàn)初始化時(shí)進(jìn)行一次預(yù)計(jì)算即可,我們?yōu)榍€(xiàn)基點(diǎn)編寫(xiě)了單獨(dú)的點(diǎn)乘方法, 使用comb 方法省去了75% 的倍點(diǎn)運(yùn)算, 讓基點(diǎn)的點(diǎn)乘運(yùn)算速度提升了約110%, 從而加速了ECC 密鑰生成和簽名過(guò)程. 在Maxthon 瀏覽器中, ECDSA (Elliptic Curve Digital Signature Algorithm, 橢圓曲線(xiàn)數(shù)字簽名算法) 和SM2 簽名算法優(yōu)化前后的性能數(shù)據(jù)如表1 所示:
表1 ECC 優(yōu)化前后性能對(duì)比Table 1 Performance with and without optimization for ECC
另外, SM2 簽名算法中, 對(duì)消息的預(yù)處理需要公鑰參與, 而每次重復(fù)計(jì)算公鑰會(huì)造成顯著的時(shí)間開(kāi)銷(xiāo),我們?cè)谏珊蛯?dǎo)入密鑰對(duì)時(shí), 將公鑰也保存在了私鑰對(duì)象中, 以節(jié)省一次不必要的標(biāo)量乘.
在支持多線(xiàn)程的平臺(tái)上實(shí)現(xiàn)上述兩種優(yōu)化方法時(shí), 如果將公式(1)和公式(2)分派給多個(gè)線(xiàn)程去運(yùn)算,還可以獲得成倍的加速效果. 例如: 在固定基comb 方法中, 如果將i ∈[0,31] 和i ∈[32,63] 部分的累加工作分派給兩個(gè)子線(xiàn)程去完成, 最后在主線(xiàn)程中合并結(jié)果, 從理論上來(lái)講, 就可以獲得近兩倍的加速效果.
就固定基comb 方法應(yīng)該使用多少線(xiàn)程的問(wèn)題, 我們?cè)肅 語(yǔ)言在64 位PC 平臺(tái)(4 核處理器) 和ARM 平臺(tái)(8 核處理器) 上分別測(cè)試了開(kāi)啟1、2、4、8 個(gè)子線(xiàn)程時(shí)的SM2 點(diǎn)乘運(yùn)算速度. 實(shí)驗(yàn)表明, 在開(kāi)啟4 個(gè)子線(xiàn)程時(shí), 速度達(dá)到了最佳——可見(jiàn), 并不是線(xiàn)程數(shù)越多, 并行度越高, 效率就越高, 如果線(xiàn)程太多, 而每個(gè)線(xiàn)程的計(jì)算量太小, 則線(xiàn)程創(chuàng)建和銷(xiāo)毀的開(kāi)銷(xiāo)在運(yùn)行時(shí)間中的占比也會(huì)升高, 變得不可忽略, 反而導(dǎo)致性能下降.
不幸的是, 由于瀏覽器中UI (User Interface, 用戶(hù)界面) 渲染線(xiàn)程和JavaScript 引擎對(duì)DOM (Document Object Model, 文檔對(duì)象模型) 樹(shù)的訪(fǎng)問(wèn)是互斥的, 曾經(jīng)有很長(zhǎng)一段時(shí)間, 為了保證線(xiàn)程安全,JavaScript 都不提供多線(xiàn)程機(jī)制. 雖然HTML5 提供了Web Worker 機(jī)制, 允許將不訪(fǎng)問(wèn)DOM 的JavaScript 代碼放在后臺(tái)線(xiàn)程中運(yùn)行, 但它要求將子線(xiàn)程需要用到的所有對(duì)象和函數(shù)結(jié)構(gòu)化拷貝到新的上下文環(huán)境中, 而一次這樣的拷貝往往要耗時(shí)上百毫秒, 其線(xiàn)程本身的開(kāi)銷(xiāo)遠(yuǎn)遠(yuǎn)高于C 語(yǔ)言, 可見(jiàn)Web Worker 機(jī)制的主要用途在于確保執(zhí)行腳本時(shí)不阻塞頁(yè)面渲染, 而非高性能并行計(jì)算. 因此, 我們最終決定基于單線(xiàn)程JavaScript 來(lái)完成實(shí)現(xiàn).
JavaScript 作為一種弱類(lèi)型的腳本語(yǔ)言, 默認(rèn)的number 類(lèi)型為64 位雙精度浮點(diǎn)數(shù), 相當(dāng)于C 語(yǔ)言中的double 類(lèi)型. 但是在參與位運(yùn)算時(shí), 會(huì)默認(rèn)轉(zhuǎn)化為32 位整數(shù), 也就是說(shuō)它并不支持32 位以上的長(zhǎng)整數(shù), 這不利于實(shí)現(xiàn)高性能的密碼學(xué)大數(shù)運(yùn)算, 好在SM3 和SM4 算法中的位操作所針對(duì)的至多是32 位長(zhǎng)的字, 不會(huì)受到影響.
sjcl 庫(kù)的AES 算法實(shí)現(xiàn)采用了T-Table 優(yōu)化, 而前文也提到過(guò), 這種方法需要維護(hù)8 KB 大小的查找表, 不宜直接使用硬編碼方式, Stark 等人將S 盒、逆向S 盒以及擴(kuò)展查找表都放在預(yù)計(jì)算階段中, 在第一次調(diào)用AES 算法時(shí)才會(huì)動(dòng)態(tài)生成上述查找表, 而只存儲(chǔ)了硬編碼的輪常量. 需要注意的是, Web 應(yīng)用場(chǎng)景下, 敵手更容易獲得加密耗時(shí), 進(jìn)而發(fā)起時(shí)序攻擊, sjcl 庫(kù)在使用T-Table 方案時(shí), 在AES 函數(shù)首輪和末輪放棄使用T-Table 表, 轉(zhuǎn)而選擇了查找S 盒的傳統(tǒng)方式, 這可以在一定程度上防止基于緩存的時(shí)序攻擊.
與SPN (Substitution-Permutation Network, 代替-置換網(wǎng)絡(luò)) 結(jié)構(gòu)的AES 算法相比, SM4 算法則屬于非對(duì)稱(chēng)Feistel 結(jié)構(gòu), 其輪函數(shù)的處理對(duì)象也迥異于AES 算法的4×4 狀態(tài)矩陣, 從理論上來(lái)看, 對(duì)SM4 使用T-Table 方案所能產(chǎn)生的優(yōu)化效果雖然遠(yuǎn)不如AES, 但在編碼時(shí), 也理應(yīng)能在每輪處理中節(jié)省7 次位操作.
SM4 算法分組長(zhǎng)度 16 字節(jié), 需要進(jìn)行 32 輪變換, 將第 i 輪狀態(tài)記作 4 個(gè) 32 位字:(Xi,Xi+1,Xi+2,Xi+3), 記第i 輪輪密鑰為Ki, 其中i=1,2,··· ,32, 則輪變換步驟如下:
(1) A=(a0,a1,a2,a3)=Xi+1⊕Xi+2⊕Xi+3⊕Ki;
(2) B =(b0,b1,b2,b3)=(S[a0],S[a1],S[a2],S[a3]);
(3) C =B ⊕(B <<<2)⊕(B <<<10)⊕(B <<<18)⊕(B <<<24);
(4) Xi+4=Xi⊕C.
步驟(2) 中, 符號(hào)S 表示查找S 盒. 而在T-Table 方案中, 可以將步驟(2) 和步驟(3) 合并如下:
(1) y =S[x],x=0,1,··· ,255;
(2) Ti[x]=(y ⊕(y <<2),y ⊕(y >>6),y <<<2,y <<<2)>>>8i,i=0,1,2,3.
上述步驟(2) 就是借助SM4 的S 盒生成T-Table 查找表的方法. 我們測(cè)試了SM4 算法T-Table 方案的優(yōu)化效果, 結(jié)果很出乎意料——在JavaScript 實(shí)現(xiàn)中, 采用T-Table 的SM4 加密速度略慢于未優(yōu)化版本. 經(jīng)過(guò)實(shí)驗(yàn)與分析, 我們發(fā)現(xiàn)查找T-Table 表的耗時(shí)超過(guò)了查找S 盒一倍, 可見(jiàn)至少在測(cè)試瀏覽器的JavaScript 解釋器下, 對(duì)32 位字的訪(fǎng)存所消耗的機(jī)器周期要多于對(duì)字節(jié)的訪(fǎng)存, 這一點(diǎn)與Native 代碼有著明顯差異.
除了T-Table 外, bit slicing[41]也是一種常用于對(duì)稱(chēng)加密算法的優(yōu)化技巧, 可以實(shí)現(xiàn)對(duì)大規(guī)模數(shù)據(jù)的并行處理. 然而, AES 和SM4 的S 盒是基于有限域理論設(shè)計(jì)的, 在bit slicing 實(shí)現(xiàn)時(shí)會(huì)分解為大量位操作[42,43], 這意味著JavaScript 代碼量的急劇增加, 因此并不適合在Web 應(yīng)用中采用.
基于以上考慮, 我們最終采用了原始版SM4, 雖然加密輪數(shù)多于AES, 速度也比T-Table 版AES 要慢很多, 但只需維護(hù)256 B 大小的S 盒即可. 由于預(yù)計(jì)算S 盒的代碼量超過(guò)了硬編碼的大小, 直接使用硬編碼方式更為合理.
由于缺乏可橫向?qū)Ρ鹊耐?lèi)通用密碼套件, 我們僅對(duì)擴(kuò)充后的sjcl 庫(kù)進(jìn)行了測(cè)試, 并對(duì)國(guó)密算法和參數(shù)規(guī)模與之相當(dāng)?shù)膶?duì)應(yīng)國(guó)際算法進(jìn)行了性能對(duì)比.
我們通過(guò)腳本將源代碼打包成了47 KB 的密碼庫(kù)文件, 并在64 位Windows 平臺(tái)上, 使用了三種主流瀏覽器和一款國(guó)產(chǎn)瀏覽器進(jìn)行性能測(cè)試, 測(cè)試平臺(tái)的具體型號(hào)、配置和版本如表2 和表3 所示.作為最具代表性的瀏覽器, 上述幾種平臺(tái)均在不同程度上實(shí)現(xiàn)了Web Crypto API, 但目前都不支持國(guó)產(chǎn)密碼算法.
表2 系統(tǒng)/硬件平臺(tái)Table 2 System/Hardwares
表3 軟件平臺(tái)Table 3 Softwares
我們分別對(duì)比了ECDSA 和SM2 簽名算法、SHA-256 和SM3 哈希算法以及AES-128 和SM4 對(duì)稱(chēng)加密算法的性能, 結(jié)果分別見(jiàn)表4、表5 和表6.
表4 ECC 簽名算法(單線(xiàn)程) 性能Table 4 Performance of ECC Signature Algorithms (with Single Thread)
表5 哈希算法性能(Mbps)Table 5 Performance of Hash Algorithms (Mbps)
表6 對(duì)稱(chēng)加密算法性能(Mbps)Table 6 Performance of Symmetric Encryption Algorithms (Mbps)
由于我們對(duì)定點(diǎn)標(biāo)量乘進(jìn)行了優(yōu)化, 因此ECC 算法中涉及基點(diǎn)乘法運(yùn)算的密鑰生成和簽名過(guò)程要比驗(yàn)簽快很多.
T-Table 方法旨在節(jié)省對(duì)稱(chēng)加密算法查找S 盒之后的混淆和擴(kuò)散步驟, 與S 盒類(lèi)似, Feistel 結(jié)構(gòu)的算法(如DES、SM4) 加解密過(guò)程共用一套T-Table 查找表, 而AES 則不然, 并且在使用該方法對(duì)AES 算法進(jìn)行優(yōu)化時(shí), 由于解密過(guò)程中的逆向字節(jié)代替無(wú)法融入查找表, 所以?xún)?yōu)化程度較加密過(guò)程要低, 從表6 中可以看出, AES 算法的加密速度要高于解密速度.
Maxthon 瀏覽器實(shí)際上使用了Chrome 的webkit[44]內(nèi)核并作出了優(yōu)化, 其內(nèi)置JavaScript 引擎為Chrome V8[45], 因此二者性能都很接近使用Carakan[46]引擎的Opera 瀏覽器. 相對(duì)于Chrome 而言,FireFox 所使用的SpiderMonkey[47]引擎顯然具有更高的計(jì)算性能.
我們基于sjcl 密碼庫(kù), 實(shí)現(xiàn)了JavaScript 版國(guó)密SM2、SM3 和SM4 算法, 形成了一款新的通用密碼套件, 可以為Web 應(yīng)用提供適度安全的前端通用密碼服務(wù). 此外, 我們使用固定基comb 方法對(duì)橢圓曲線(xiàn)點(diǎn)乘進(jìn)行了加速, 將ECC 密鑰生成和簽名的運(yùn)算速度提升了一倍以上.目前存在的問(wèn)題和下一步工作:
(1) 雖然實(shí)現(xiàn)了SM2 等非對(duì)稱(chēng)算法, 但使用場(chǎng)景十分有限, 不論是安全性還是功能都無(wú)法與驅(qū)動(dòng)加硬件Key 的模式相比, 目前至多可以用于J-PAKE 等協(xié)議以及加密、驗(yàn)簽工作, 在未來(lái)工作中,我們將考慮利用拆分或口令派生機(jī)制, 予以私鑰更高等級(jí)的保護(hù);
(2) 目前所實(shí)現(xiàn)的SM4 算法系基礎(chǔ)版本, 在部分平臺(tái)上比sjcl 的AES-128 慢一倍左右, 我們也嘗試過(guò)利用SIMD.js[48]或bit slicing 來(lái)進(jìn)行優(yōu)化, 但沒(méi)有得出可行有效的方法, 反倒是AES-128 可以利用SIMD.js 進(jìn)行向量化實(shí)現(xiàn), SM4 可能還存在軟件優(yōu)化空間, 希望下一步工作中能夠找到有效方法來(lái)提升其性能;
(3) 在移動(dòng)互聯(lián)網(wǎng)應(yīng)用中, HTML5+Native 的架構(gòu)大行其道, 它用Web 代碼來(lái)實(shí)現(xiàn)需要跨平臺(tái)的核心功能, 極大地簡(jiǎn)化了開(kāi)發(fā)工作, 還讓HTML5 可以方便地訪(fǎng)問(wèn)移動(dòng)終端Native 資源, 如傳感器、相機(jī)、通信錄等, 這在傳統(tǒng)PC 上是很難實(shí)現(xiàn)的, 因此可以很大程度上解決Web 應(yīng)用功能受限的問(wèn)題, 而這也給了我們新的啟發(fā)——至少在移動(dòng)端上, 能否利用對(duì)Native 的訪(fǎng)問(wèn)來(lái)擴(kuò)展非對(duì)稱(chēng)密碼算法的應(yīng)用場(chǎng)景, 實(shí)現(xiàn)移動(dòng)軟件Key 的效果?能否利用Native 資源為移動(dòng)Web 應(yīng)用構(gòu)造高質(zhì)量的隨機(jī)數(shù)發(fā)生器?我們相信這些設(shè)想都值得在下一步工作中去嘗試.