One-Time-Pad
在小容量物聯網通信中使用 One-Time-Pad + HMAC 的可行性
在物聯網世界中,某些應用程序產生的通信量非常小。例如,我會想到每小時讀取一次水錶。如果讀數可以編碼為 32 位無符號整數並添加 24 位序列號,則該設備將在假定的 10 年壽命(7 字節 * 24 小時 * 365 天 * 10 年)內僅傳輸約 614 KB 的數據)。
我想討論一下 One-Time-Pad (OTP) 解決方案加上 HMAC 在這種情況下是否是可行的解決方案。可以輕鬆地預先生成 614 KB 的密鑰流並將其儲存在設備上,儘管實現“OTP + HMAC”的硬體安全模組 (HSM)可能還不存在。
我知道在實踐中使用 One-Time-Pads 的核心問題。假設可以克服這些挑戰(至少以足夠安全的方式來傳輸每小時一次的水錶讀數),以下虛擬碼解釋了該方法。
# KEYSTREAM is a file containing at least 614 KBytes of random bytes. # COUNTER is the current offset into KEYSTREAM. function encrypt_and_hmac(plaintext): fp = open(KEYSTREAM) fp.seek(COUNTER) # Remember the current offset into the KEYSTREAM pos = fp.pos() # Read bytes from KEYSTREAM for encrypting the plaintext cipherpad = fp.read(len(plaintext)) ciphertext = plaintext XOR cipherpad # Read 8 bytes (in this example) from KEYSTREAM for HMAC macpad = fp.read(8) hmac = hash(ciphertext + macpad) # Safely(!) erase the used bytes from the KEYSTRAM erase(KEYSTREAM, pos, pos+len(plaintext)+8) return pos, ciphertext, hmac
現在可以傳輸密鑰流 (pos)、密文和 HMAC 的目前偏移量。解密和驗證將像這樣工作。
function decrypt_and_verify(pos, ciphertext, hmac): fp = open(KEYSTREAM) fp.seek(pos) cipherpad = fp.read(len(plaintext)) macpad = fp.read(8) assert hash(ciphertext + macpad) == hmac plaintext = ciphertext XOR cipherpad return plaintext
只是為了搶占一些潛在的評論:
- 是的,AES-EAX之類的可能是更好的解決方案。
- 除非使用密鑰交換協議,否則安全分發 KEYSTREAM 的挑戰與使用任何其他共享密鑰沒有什麼不同。
- 理想情況下,加密和 HMAC 應該在 HSM 模組內完成,否則如果有人訪問水錶,安全性很容易受到損害。
- 擁有少量受損的水錶可能是一種可接受的商業風險,類似於簡單故障的水錶。這將消除 HSM 模組的成本。
- 如果傳輸通道的有效負載大小非常小,如 Sigfox(12 字節)和 LoRaWan 和 Weightless 的較小數據包大小選項,則會出現一個有趣的挑戰。可以只傳輸 HMAC 的前幾個字節嗎???
我期待您的評論、回饋和批評。
我看到的兩個主要缺點是:
- 您必須預測在設備生命週期內將加密多少字節。在我看來,這是相當具有挑戰性的。
- 但是,假設您能夠修復上限。在您的範例中,您需要在 IoT 設備中儲存 614kB。如果你考慮誤差範圍會是什麼?在物聯網設備中儲存大約 1GB 的數據似乎並不合適,因為許多晶片都是低成本的。因此,他們可能沒有可用的儲存空間。
此外,由於您建議使用 HMAC 來實現完整性/真實性,因此仍然需要對稱密鑰管理。因此,為什麼不使用 AEAD 密碼呢?
要回答您的問題,是的,截斷 MAC(這是在 LoRa 中完成的)是一種常見做法,如此處所述。