在上篇講 Silicon IP 的文 我們稍微提到過 IEEE1735 ,不過後來我發現 IEEE1735 的原理可以講得更深入一些,主要是多解釋一些 IEEE1735 會對 HDL 檔案造成的影響。

會寫這篇是因為最近在使用 Cadence 的 Xcelium ,發現它提供的功能比 Synopsys VCS 還要再多更多,連文件都好上一個數量級,VCS 根本什麼都沒提供,藉此我們更加了解 IEEE1735 的實作。
另外是本來網路上最詳細介紹 IEEE1735 的文章使用 IEEE (1735) Verilog 标准机制进行 IP 保护 已經被鎖成付費觀看了,以致網路上幾乎沒有這方面的文章,就起心動念來篇文章介紹一下。

技術背景

要理解 IEEE1735,需要先理解下列幾個技術名詞,當然我們不用懂背後的原理,從概念上理解就好,概念問題看不懂問 AI 就行了。

1. 對稱式加密演算法

加密與解密都是用同一支金鑰,可以把明文變成一坨沒人看得懂的渣渣,再用同一支金鑰整個解回來。
在 IEEE1735 中通常使用 AES128-CBC 模式,另外可以選擇下列幾個:

  • AES128-CBC
  • AES192-CBC
  • AES256-CBC

以下是 Xcelium 額外支援的:

  • DES-CBC
  • AES128-CTR
  • AES192-CTR
  • AES256-CTR

但 DES 已經不是安全的標準,CTR 則不是 IEEE1735 建議的模式。

2. 非對稱式加密演算法

加解密金鑰則分為公鑰和私鑰,使用公鑰進行加密則只有私鑰可以解密,IEEE 1735 使用的是 RSA,沒有查到任何支援 ECC 的消息。
另外 Xcelium 自己額外支援 RC2, RC4, RC5,但我不確定為什麼會有這三個,理論上這是對稱式的加密,為什麼會出現在非對稱區?

3. 編碼

記得編碼不是加密,只要知道編碼規則,任何人都可以把編碼過的東西還原回來。
IEEE1735 會用到編碼是因為加密完的渣渣有很多會落在不可顯示的內容, 在檔案裡這些內容會經過編碼轉成可顯示的區域,IEEE1735 用的是 base64。

4. 雜湊

確認檔案有沒有遭到修改的演算法,可以把一份檔案濃縮成短短一串數字,任何內容的稍加修改都會生出完全不一樣的東西。
IEEE1735 一般使用 SHA256,可以指定 SHA512

IEEE1735 運作

IEEE1735 的目的是為了讓 silicon IP 的設計者,能把他們的設計交給 IP 使用者, 不讓使用者得知設計的詳細內容;但使用者仍然要能把 IP 塞進 EDA 軟體中進行處理,才能把 silicon IP 的設計轉為實際的電路。

IEEE1735 的運作是這樣子的:

  1. 每家 EDA 公司都會有一把私鑰,寫死在他們的軟體的某處,公鑰則公開出來
  2. 設計者生成一把 AES 的金鑰,將設計檔案加密
  3. 加密完成之後,使用 EDA 工具的公鑰對該對稱式演算法金鑰進行加密,將結果寫在檔案內

拿到 IP 之後,使用者把加密檔案丟進 EDA 軟體,由於私鑰寫死在軟體內,因此可以:

  1. EDA 軟體使用私鑰解密 AES 金鑰
  2. 使用 AES 金鑰解密加密的資料區塊得到原始碼

IEEE1735 加密後的檔案包含下列的區塊:

類別 範例欄位 說明
標頭區 (Metadata) begin_protected, version, encrypt_agent 宣告該檔案受 IEEE 1735 保護,以及加密來源、版本與加密者資訊
授權與權限控制區 commonblock data_usage, rights_digest_method, license_expiration, begin_license 控制可執行動作(模擬、合成等)、授權期限、完整性檢查方式等
金鑰區 toolblock key_keyowner, key_method, key_block 指定哪家 EDA 廠商的公鑰、金鑰演算法、加密後的對稱金鑰內容
資料區 datablock data_block 用 AES 加密後的 HDL 內容
版本與安全性資訊 version, rights_digest_method 指定 IEEE 1735 版本與雜湊算法(例如 SHA-256),用於驗證保護區內容是否遭竄改
結尾宣告 end_protected 宣告受保護區結束

Xcelium 使用 IEEE1735 自動加密

下面是我測試加密的檔案:

`pragma protect begin
module counter (
    input logic clk,
    input logic rst_n,
    output logic [1:0] count
);
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            count <= 2'b00;
        else
            count <= count + 1;
    end
endmodule
`pragma protect end

使用 Xcelium 指令

xmprotect -autoprotect -v2_ip1735 dut.sv`

輸出的加密內容,xcelium 自行選用 Cadence 的金鑰對 CDS_RSA_KEY_VER_2,加密後的 AES 金鑰即是 key_block 指定的內容,可以使用 base64 -d | hexdump -C 解出 hex 的內容。

很神奇的,IEEE1735 在 RSA 的部分並沒有更新到任何現代密碼學的概念,rsa 加密使用的是純粹的 no_padding 模式,連進一階有已知缺陷的 PKCS#1 v1.5 padding 都沒有,更遑論更新更安全的 OAEP padding 了。

`pragma protect begin_protected
`pragma protect version=2
`pragma protect encrypt_agent="NCPROTECT"
`pragma protect encrypt_agent_info="Encrypted using API"
`pragma protect data_method="AES128-CBC"

`pragma protect begin_commonblock
`pragma protect end_commonblock

`pragma protect begin_toolblock
`pragma protect key_keyowner="Cadence Design Systems."
`pragma protect key_keyname="CDS_RSA_KEY_VER_2"
`pragma protect key_method="RSA"
`pragma protect rights_digest_method="sha256"
`pragma protect encoding = (enctype = "BASE64", line_length = 48, bytes = 256)
`pragma protect key_block
AcGtKbMIbm5GriSB9Okgd1fdO+th/gdd7DysikiKL4biU8xh
5WDtXr/Kx4w0X5ohS8u8My1EoCgU80ToR7uj7aX7DO1O57/0
YjJIM36gRB8WWn3Ux/+q8i2TbzrXCReTK/GknF9yVEiDioRJ
p4dc8dgG07CLKOdFtwVeehAak1vSsnX49p3wkadQpaiEursG
RthxxTBRuY34rh2ZRo4z3A/yN4RUR1PGm7/NhGW3kCAH6DSO
rDy5dFGvVRczVZkSImSL1W6eZKKbiw3dcwACo6uk0eYLZKVo
/RmdxcnzVKlVrc7S+YthEElTzH6J0EsGdwLkH1LGlStDsXS3
FChz9Q==

`pragma protect end_toolblock="Tldb4a+fP8nJrj7zI0Wp/4/W9pfiUVYG7Un8J1njQCY="
`pragma protect encoding = (enctype = "BASE64", line_length = 48, bytes = 320)
`pragma protect data_block
lujf2DVPsigDbuCJ6Lzygr8b1okGVlo4oYhVZmKiu39t4R5f
sm0GOf/1lVk0dnXlNJkWwCgd3ycNZEg+W9rr8jyU7DEsxvQw
749dup7fESX+S+Nzt2sq7tUdhKRSZ2RzYZkc8QNx3Mm7XrxG
wJfiLIDkfxv2N/lQJhydcpl0m1VT11pAqNZpiB1SnmD1y4xQ
33cvZL9/04EaURgxSswvvmxldVkWKce7DXpVqfA+36eFLeE0
mVv53dpXl1CqeZ//AETdk/k2KBIU6GySMVCXZ7kycIHNO3om
1NjwwoXRhKIJxL5q49oGuej9rlqPuE057Wo8+ApVWO4STOfJ
4FTydEGSdkKpv8w4zuehdgd461/T8ck3Dr6WtM9brWZhkZoh
HHLtzW2/59KJAyd0P6UDwr6U+rmhU6OrhueTibEscWA=

`pragma protect end_protected

注意上面的金鑰區 begin_toolblock 並不僅限於一家,同一把 AES 金鑰可以用所有你想得到的軟體的公鑰加密過, 以這個公開檔案 為例,如果用了各家的 key 去加密完就會長這個樣子。
每家都留一個金鑰區,EDA 軟體會去爬到自己公司的部分用私鑰解密,以 VCS 為例,如果去跑 Xcelium 加密出來的檔案,會得到下面的錯誤訊息:

Error-[DECSPE] Decryption failed
encrypted/dut.svp, 29
  Error while decrypting source file
  Failed to load key needed to decrypt data_block. No key_block found for VCS.
  Please use vcs RSA public key and pragma expressions to identify the 
  keyblock mentioned in vcs documentation while encrypting to be able to 
  decrypt with vcs.

除了 CDS_RSA_KEY_VER_2 之外,Xcelium 也可以指定下面兩把 key 進行加密,使用 -use_key “key_name” 來指定使用:

  • CDS_XM:Cadence 工具通用,Xcelium 加密後可以給 Jasper 或是 Palladium 使用。
  • CDS_XM_PUBKEY:Xcelium 特有的,其他 Cadence 不能使用加密後的檔案。

上面提到的幾把 keys 是 Cadence 未公開的金鑰對,他們的私鑰應該是還沒被解… 應該啦,就算我知道破掉的結果我也不敢大聲嚷嚷我才不告訴逆雷
另一把金鑰 CDS_RSA_KEY_VER_1 應該是已經被破解了,指定它 xmprotect 會跳出 non-secure 的警告。

權限 hash 的部分

加密檔案會有如下的 end_toolblock。

end_toolblock="Tldb4a+fP8nJrj7zI0Wp/4/W9pfiUVYG7Un8J1njQCY="

這是把檔案中 commonblock 與 toolblock 的內容使用 sha256 計算出的雜湊值,有些 EDA tool 會在這裡加入權限等區段,以免使用者偷改檔案拿到更高權限。
如果修改這個雜湊值,在 xcelium 模擬會出現下列的錯誤:

xmvlog: *F,DECERR (encrypted/dut.svp,28|26): Error while decrypting : AEAD signature in end_protected/end_toolblock pragma doesn't match.
xrun: *E,VLGERR: An error occurred during parsing.  Review the log file for errors with the code *E and fix those identified problems to proceed.  Exiting with code (status 2).

理論上它輸入是 commonblock 和 toolblock 內的文字,並經過下列的處理:

  1. 去掉開頭的 `pragma protect
  2. 去掉開頭與結尾的空白
  3. 把換行符號換成 Line Feed \n

不過理論如此,實際上我卻沒辦法重現它的結果,我把文字直接塞進 SHA256 並用 base64 encode 之後,還是沒有辦法重現出一樣的結果,下面是處理用的 python script。
如果有任何人知道怎麼算這個 end_toolblock 的雜湊值,或是你碰出了一樣的雜湊值,就麻煩大大指教了 (如果是後者的話,建議可以先去買一張樂透)。

import hashlib
import base64

content = """
`pragma protect key_keyowner="Cadence Design Systems."
`pragma protect key_keyname="CDS_RSA_KEY_VER_2"
`pragma protect key_method="RSA"
`pragma protect rights_digest_method="sha256"
`pragma protect encoding = (enctype = "BASE64", line_length = 48, bytes = 256)
`pragma protect key_block
AcGtKbMIbm5GriSB9Okgd1fdO+th/gdd7DysikiKL4biU8xh
5WDtXr/Kx4w0X5ohS8u8My1EoCgU80ToR7uj7aX7DO1O57/0
YjJIM36gRB8WWn3Ux/+q8i2TbzrXCReTK/GknF9yVEiDioRJ
p4dc8dgG07CLKOdFtwVeehAak1vSsnX49p3wkadQpaiEursG
RthxxTBRuY34rh2ZRo4z3A/yN4RUR1PGm7/NhGW3kCAH6DSO
rDy5dFGvVRczVZkSImSL1W6eZKKbiw3dcwACo6uk0eYLZKVo
/RmdxcnzVKlVrc7S+YthEElTzH6J0EsGdwLkH1LGlStDsXS3
FChz9Q==
""".strip()

cleaned_content = ""
for line in content.splitlines():
    line = line.replace("`pragma protect", "").strip()
    cleaned_content += line + '\n'

# Compute SHA256 hash
sha256_hash = hashlib.sha256(cleaned_content).digest()
sha256_hash_base64 = base64.b64encode(sha256_hash).decode('utf-8')
print(f"Hash (Base64): {sha256_hash_base64}")

總結

IEEE1735 其實是一個有點破碎的標準,排除掉 RSA 私鑰為了支援離線解密必須寫死在 EDA 軟體之外,有些部分的規定也沒有跟上最新的密碼學標準;當然,安全程度降低跟資料實際被破解是有一段很大的差距, 密碼學家很常被說是杞人憂天就是這個原因。
但說正經的,一般來說最容易出問題的都是密碼學的實作,理論寫得再漂亮實作亂作,再怎麼安全的理論立刻變成空話; IEEE1735 自己也被挖過好幾次的漏洞。

如同在使用 IP 篇所說,IP 生態系之所以活得好好的沒崩潰,靠的是行規而不是加密, 解出來你也不敢昭告天下也不能真拿去下線,有點風吹草動立馬得罪全天下的矽產業被業界封殺。