Linux

Linux 使用 TPM 2.0 產生真實隨機亂數教學與範例

介紹如何在 Linux 系統中使用 TPM 2.0 產生真實的隨機亂數(true random numbers)。

TPM(Trusted Platform Module)是一個安全加密處理器,透過加密金鑰來保護硬體的安全,而 TPM 也同時意指安全加密處理器的國際標準(也稱為 ISO/IEC 11889),在實務上 TPM 可用於安全開機(secure boot)、金鑰儲存以及隨機亂數的產生等。

TPM 硬體亂數生成器

TPM 中含有硬體亂數生成器,在 TPM 2.0 的規範中的 11.4.11.2 Entropy Source and Collector 部份有提到 TPM 2.0 的硬體模組必須內建至少一個熵源(source of entropy,也就是亂數來源的意思):

A TPM should have at least one internal source of entropy, and possibly more. These sources could include noise, clock variations, air movement, and other types of events.

所以只要是合規的 TPM 處理器都可以用來生成真正的隨機亂數。

Linux 核心與 TPM 硬體亂數生成器

Linux 核心的 CONFIG_HW_RANDOM_TPM 選項可以啟用 TPM 硬體亂數生成器功能,這項功能可以將 TPM 做為 hwrng 設備,在 Linux 系統開機時讓核心從 TPM 取得亂數,並將亂數注入 /dev/hwrng

檢查 Linux 系統是否支援 TPM 2.0

TPM 主要有 TPM 2.0 與 TPM 1.2 兩種版本,兩種版本有很大的差異,這裡我們只討論 TPM 2.0 的使用方式。若在 Linux 系統中要檢查自己的硬體是否有支援 TPM 2.0,可以查看 dmesg 的輸出,檢查是否有 TPM 的字樣:

# 查看 dmesg 輸出是否包含 tpm 字樣
dmesg | grep -i tpm
[    0.000000] efi: ACPI 2.0=0x797c5000 ACPI=0x797c5000 TPMFinalLog=0x797e9000 SMBIOS=0x799fc000 SMBIOS 3.0=0x799fb000 ESRT=0x74185898 MEMATTR=0x7209b018 
[    0.011479] ACPI: TPM2 0x00000000797DB970 000034 (v03 GBT    GBTUACPI 00000001 AMI  00000000)
[    0.011579] ACPI: Reserving TPM2 table memory at [mem 0x797db970-0x797db9a3]
[    5.875662] systemd[1]: systemd 252.6-1 running in system mode (+PAM +AUDIT +SELINUX +APPARMOR +IMA +SMACK +SECCOMP +GCRYPT -GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN +IPTC +KMOD +LIBCRYPTSETUP +LIBFDISK +PCRE2 -PWQUALITY +P11KIT +QRENCODE +TPM2 +BZIP2 +LZ4 +XZ +ZLIB +ZSTD -BPF_FRAMEWORK -XKBCOMMON +UTMP +SYSVINIT default-hierarchy=unified)

或是檢查系統上的 TPM 相關設備檔是否存在:

# 檢查 TPM 相關設備檔是否存在
ls /dev/tpm*
/dev/tpm0  /dev/tpmrm0

如果 /dev/tpm0/dev/tpmrm0 兩個設備檔都存在,則代表系統有支援 TPM 2.0,如果只有 /dev/tpm0 存在,則代表系統只有支援 TPM 1.2。

如果 Linux 核心版本在 5.6 以上,也可以直接查看 TPM 的版本:

# 查看 TPM 的版本
cat /sys/class/tpm/tpm0/tpm_version_major
2

或是查看 TPM 設備資訊:

# 查看 TPM 設備版本
cat /sys/class/tpm/tpm0/device/description
TPM 2.0 Device

tpm2-tools

tpm2-tools 是以 tpm2-tss 為基礎所開發的 TPM 工具組,裡面包含許多加密與簽章相關的 TPM 工具程式,使用前可用 apt 安裝:

# 安裝 tpm2-tools
sudo apt install tpm2-tools

在大部份的 Linux 系統中,只有 root 管理者可以直接存取 TPM 的設備檔,若要讓一般使用者也可以使用 TPM 設備,必須將使用者加入對應的群組,以 Ubuntu 或 Debian 這類的 Linux 系統來說,對應的群組就是 tss

# 將 myuser 使用者加入 tss 群組
sudo usermod -a -G tss myuser

在 tpm2-tools 套件中,有一個 tpm2_getrandom 指令工具可以用來從 TPM 產生真正的隨機亂數:

# 使用 TPM 產生 8 位元組的隨機資料,以 16 進位輸出
tpm2_getrandom --hex 8
2c82b9ecc8934be0

若要以原始的亂數資料輸出,可以使用 -o 參數指定輸出的檔案:

# 使用 TPM 產生 8 位元組的隨機資料,輸出至檔案
tpm2_getrandom -o random.out 8

常見問題

如果在執行 tpm2_getrandom 的時候,出現類似以下這樣的 Permission denied 錯誤,代表目前的使用者沒有權限存取 /dev/tpmrm0 設備檔:

ERROR:tcti:src/tss2-tcti/tcti-device.c:452:Tss2_Tcti_Device_Init() Failed to open specified TCTI device file /dev/tpmrm0: Permission denied 
ERROR:tcti:src/tss2-tcti/tctildr-dl.c:154:tcti_from_file() Could not initialize TCTI file: libtss2-tcti-device.so.0 
ERROR:tcti:src/tss2-tcti/tcti-device.c:452:Tss2_Tcti_Device_Init() Failed to open specified TCTI device file /dev/tpm0: Permission denied 
ERROR:tcti:src/tss2-tcti/tctildr-dl.c:154:tcti_from_file() Could not initialize TCTI file: libtss2-tcti-device.so.0 
WARNING:tcti:src/util/io.c:262:socket_connect() Failed to connect to host 127.0.0.1, port 2321: errno 111: Connection refused 
ERROR:tcti:src/tss2-tcti/tcti-swtpm.c:614:Tss2_Tcti_Swtpm_Init() Cannot connect to swtpm TPM socket 
ERROR:tcti:src/tss2-tcti/tctildr-dl.c:154:tcti_from_file() Could not initialize TCTI file: libtss2-tcti-swtpm.so.0 
WARNING:tcti:src/util/io.c:262:socket_connect() Failed to connect to host 127.0.0.1, port 2321: errno 111: Connection refused 
ERROR:tcti:src/tss2-tcti/tctildr-dl.c:154:tcti_from_file() Could not initialize TCTI file: libtss2-tcti-mssim.so.0 
ERROR:tcti:src/tss2-tcti/tctildr-dl.c:254:tctildr_get_default() No standard TCTI could be loaded 
ERROR:tcti:src/tss2-tcti/tctildr.c:428:Tss2_TctiLdr_Initialize_Ex() Failed to instantiate TCTI 
ERROR: Could not load tcti, got: "(null)"

若遇到這樣的問題,可以先檢查 /dev/tpmrm0 設備檔的權限與擁有者:

# 檢查 /dev/tpmrm0 設備檔的權限與擁有者
ls -l /dev/tpmrm0
crw-rw---- 1 tss tss 253, 65536  5月 24 07:26 /dev/tpmrm0

確認檔案權限之後,使用上面的 usermod 指令將要存取 /dev/tpmrm0 設備檔的使用者加入該群組(以這裡的例子來說就是 tss)。

若不想更改使用者的群組設定,也可以直接使用 root 權限存取 /dev/tpmrm0 設備檔。

tpm2-openssl

tpm2-openssl 是一個可以讓 OpenSSL API 存取 TPM 2.0 設備的 provider,適用於 OpenSSL 3.x 版本,如果是 OpenSSL 1.1 的環境,要改用 tpm2-tss-engine

在 Ubuntu 或 Debian 系列的 Linux 中可用 apt 安裝:

# 安裝 tpm2-openssl 套件
sudo apt install tpm2-openssl

安裝好 tpm2-openssl 之後,就可以在 OpenSSL 中使用 tpm2 這個 provider 了,例如若要以 TPM 產生 8 位元組的隨機資料,並以 16 進位輸出,可以執行:

# 使用 TPM 產生 8 位元組的隨機資料,以 16 進位輸出
openssl rand -provider tpm2 -hex 8
2a0e1fd3e96ad0cb

若要將隨機資料輸出至檔案,可以執行:

# 使用 TPM 產生 8 位元組的隨機資料,輸出至檔案
openssl rand -provider tpm2 -out random.out 8

tpm2-tss

tpm2-tss 函式庫是 Trusted Computing Group(TCG)TPM2 Software Stack(TSS)的一個實作版本,TSS 從高階到低階,包含了 Feature API(FAPI)Enhanced System API(ESAPI)System API(SAPI)Marshaling/Unmarshaling(MU)TPM Command Transmission Interface(TCTI)

在 Ubuntu 或 Debian 系列的 Linux 中,若要使用 tpm2-tss 函式庫,可以使用 apt 安裝:

# 安裝 libtss2-dev 相關開發套件
apt install libtss2-dev

安裝好之後,即可使用 tpm2-tss 函式庫內的 API 進行開發。

以下是使用 Enhanced System API(ESAPI)以 TPM 產生亂數的 C 語言範例:

#include <stdlib.h>
#include <stdio.h>
#include <tss2/tss2_esys.h>
#include <tss2/tss2_rc.h>

int main() {
	ESYS_CONTEXT *context = NULL;

	// ESYS 初始化
	TSS2_RC rc = Esys_Initialize(&context, NULL, NULL);

	// 檢查 ESYS 初始化是否成功
	if (rc != TSS2_RC_SUCCESS) {
		fprintf(stderr, "Esys_Initialize: %s\n", Tss2_RC_Decode(rc));
		return EXIT_FAILURE;
	}

	TPM2B_DIGEST *bytes = NULL;

	// 使用 TPM 產生亂數
	rc = Esys_GetRandom(context,
			ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
			8,  // 產生的亂數資料長度
			&bytes);

	// 檢查 TPM 產生亂數是否成功
	if (rc != TSS2_RC_SUCCESS) {
		fprintf(stderr, "Esys_GetRandom: %s\n", Tss2_RC_Decode(rc));
		return EXIT_FAILURE;
	}

	// 輸出亂數
	for (size_t i = 0; i < bytes->size; i++) {
		printf("%02x", bytes->buffer[i]);
	}
	printf("\n");

	Esys_Free(bytes);
	Esys_Finalize(&context);
	return EXIT_SUCCESS;
}

將上面這段程式碼儲存為 my_random.c,使用以下 gcc 指令進行編譯:

# 編譯程式
gcc -o my_random my_random.c -ltss2-esys -ltss2-rc

編譯完成後,執行產生的 my_random 程式:

# 執行程式
./my_random
01071414c00a3009

參考資料

Share
Published by
Office Guide
Tags: 資訊安全

Recent Posts

Python 使用 PyAutoGUI 自動操作滑鼠與鍵盤

本篇介紹如何在 Python ...

1 年 ago

Ubuntu Linux 以 WireGuard 架設 VPN 伺服器教學與範例

本篇介紹如何在 Ubuntu ...

1 年 ago

Linux 網路設定 ip 指令用法教學與範例

本篇介紹如何在 Linux 系...

1 年 ago

Linux 以 Cryptsetup、LUKS 加密 USB 隨身碟教學與範例

介紹如何在 Linux 系統中...

1 年 ago