HarmonyOS Next 對稱金鑰生成全攻略:從原理到實踐

SameX發表於2024-11-18

本文旨在深入探討華為鴻蒙HarmonyOS Next系統(截止目前API12)的技術細節,基於實際開發實踐進行總結。
主要作為技術分享與交流載體,難免錯漏,歡迎各位同仁提出寶貴意見和問題,以便共同進步。
本文為原創內容,任何形式的轉載必須註明出處及原作者。

一、引言

在資料安全的浩瀚領域中,對稱金鑰猶如一把堅固的鎖,守護著我們寶貴的資訊資產。它的重要性怎麼強調都不為過,無論是個人隱私資料的加密儲存,還是企業敏感資訊在網路中的傳輸,對稱金鑰都扮演著關鍵角色。透過使用對稱金鑰進行加密,只有擁有相同金鑰的授權方才能解密並獲取原始資料,從而有效地防止資料被未授權訪問和竊取。在各種加密技術中,對稱金鑰以其加密和解密速度快的優勢,成為處理大量資料加密任務的首選,如檔案加密、資料庫加密以及實時通訊中的資料加密等場景。接下來,我們將深入探討 HarmonyOS Next 中對稱金鑰的生成和轉換,從原理到實踐全方位剖析這一重要技術。

二、對稱金鑰生成和轉換規格

(一)AES、3DES、SM4 等演算法的特點與適用場景

  1. AES 演算法
    - AES(Advanced Encryption Standard)作為當今最為常用的對稱加密演算法之一,具有諸多顯著特點。它是一種分組密碼演算法,分組長度固定為 128 位,金鑰長度則可靈活選擇 128 位、192 位或 256 位。與 3DES 相比,AES 展現出更高的安全性,這得益於其更為先進的加密演算法結構。同時,AES 的處理速度更快,能夠高效地處理大量資料加密任務。在實際應用中,AES 廣泛應用於各種對安全性和效能要求較高的場景,如線上支付系統中對使用者銀行卡資訊的加密儲存、雲端計算環境下的資料中心資料加密等。
  2. 3DES 演算法
    - 3DES(Triple Data Encryption Algorithm),也稱為 3DESede 或 TripleDES,其加密原理是使用 3 個 64 位的金鑰對資料塊進行三次加密,相當於對每個資料塊執行三次 DES(Data Encryption Standard)加密演算法。這種加密方式使得 3DES 的金鑰長度更長,從而提供了比 DES 更高的安全性。然而,相對而言,其處理速度不如 AES 快。3DES 適用於一些對安全性有一定要求,但對效能要求不是特別苛刻的場景,例如某些企業內部網路中的資料加密傳輸,在硬體資源有限且 AES 支援不完全的情況下,3DES 可以作為一種過渡性的加密解決方案。
  3. SM4 演算法
    - SM4 是我國自主研發的分組密碼演算法,分組長度同樣為 128 位,金鑰長度為 128 位,並且可透過擴充套件金鑰增加金鑰長度。SM4 的加密演算法與金鑰擴充套件演算法都採用 32 輪非線性迭代結構,其獨特之處在於資料解密和資料加密的演算法結構相同,只是輪金鑰的使用順序相反,解密輪金鑰是加密輪金鑰的逆序。SM4 在國內的一些安全敏感領域得到了廣泛應用,如政府部門的資料加密、國內金融機構的部分業務加密等,以保障國家資訊保安和關鍵基礎設施的安全。

(二)字串引數承載金鑰規格的方式及示例

在 HarmonyOS Next 中,透過特定的字串引數來承載金鑰規格,從而方便地生成對應的金鑰。以 AES 演算法為例,其字串引數由“對稱金鑰演算法”和“金鑰長度”拼接而成。具體來說,當要生成 128 位的 AES 金鑰時,對應的字串引數為“AES128”;生成 192 位金鑰時,字串引數為“AES192”;生成 256 位金鑰時,字串引數為“AES256”。這種簡潔而明確的方式使得開發者能夠直觀地指定所需的金鑰規格。同樣,對於 3DES 演算法,其字串引數為“3DES192”(表示金鑰長度為 192 位);SM4 演算法的字串引數為“SM4_128”(表示金鑰長度為 128 位)。透過這些字串引數,開發者可以在建立對稱金鑰生成器時,準確地指定所需的金鑰規格,為後續的加密操作奠定基礎。

三、隨機生成對稱金鑰(ArkTS 與 C/C++ 示例)

(一)ArkTS 程式碼實現步驟與解釋

  1. 首先,匯入必要的模組:
import { cryptoFramework } from '@kit.CryptoArchitectureKit';

這裡的 cryptoFramework 是 HarmonyOS Next 提供的加解密演算法框架模組,透過匯入它,我們可以使用其中的各種加密相關功能。
2. 然後,建立對稱金鑰生成器:

let symKeyGenerator = cryptoFramework.createSymKeyGenerator('AES256');

在這一步中,我們使用 createSymKeyGenerator 函式並傳入字串引數“AES256”,表示我們要建立一個金鑰演算法為 AES、金鑰長度為 256 位的對稱金鑰生成器。這一步是根據我們之前提到的字串引數承載金鑰規格的方式來指定所需的金鑰型別。
3. 接下來,生成對稱金鑰:

let promiseSymKey = symKeyGenerator.generateSymKey();

呼叫生成器的 generateSymKey 方法來隨機生成對稱金鑰。這個方法返回一個 Promise 物件,因為金鑰生成可能需要一定的時間,特別是對於較長金鑰長度的情況。
4. 最後,獲取金鑰的二進位制資料並處理結果:

promiseSymKey.then(key => {
  let encodedKey = key.getEncoded();
  console.info('key hex:' + encodedKey.data);
});

當金鑰生成成功後,透過 Promise 的 then 方法獲取生成的金鑰物件,並呼叫 getEncoded 方法獲取金鑰的二進位制資料。這裡將二進位制資料轉換為十六進位制字串並輸出,以便開發者檢視和使用生成的金鑰。

(二)C/C++ 程式碼實現步驟與解釋(包括 CMake 指令碼配置)

  1. CMake 指令碼配置
    - 在 C/C++ 專案中使用 HarmonyOS Next 的加密功能,需要在 CMake 指令碼中正確連結相關動態庫。在 CMakeLists.txt 檔案中新增以下程式碼:
target_link_libraries(entry PUBLIC libohcrypto.so)

這行程式碼的作用是將 libohcrypto.so 動態庫連結到專案中,使得專案能夠使用其中的加密函式和功能。
2. 程式碼實現
- 首先,包含必要的標頭檔案:

#include "CryptoArchitectureKit/crypto_common.h"
#include "CryptoArchitectureKit/crypto_sym_key.h"

這些標頭檔案提供了使用對稱金鑰生成功能所需的函式宣告和資料結構定義。
- 然後,建立對稱金鑰生成器並生成金鑰:

OH_CryptoSymKeyGenerator *ctx = nullptr;
OH_CryptoSymKey *keyCtx = nullptr;
Crypto_DataBlob out = {.data = nullptr,.len = 0};
OH_Crypto_ErrCode ret = OH_CryptoSymKeyGenerator_Create("AES256", &ctx);
if (ret!= CRYPTO_SUCCESS) {
    return ret;
}
ret = OH_CryptoSymKeyGenerator_Generate(ctx, &keyCtx);
if (ret!= CRYPTO_SUCCESS) {
    OH_CryptoSymKeyGenerator_Destroy(ctx);
    return ret;
}

這裡首先建立一個 OH_CryptoSymKeyGenerator 型別的指標 ctx 來表示對稱金鑰生成器上下文,以及一個 OH_CryptoSymKey 型別的指標 keyCtx 來儲存生成的金鑰。然後使用 OH_CryptoSymKeyGenerator_Create 函式建立一個 AES256 金鑰生成器,傳入字串引數“AES256”來指定金鑰規格。如果建立成功,接著使用 OH_CryptoSymKeyGenerator_Generate 函式生成對稱金鑰。在整個過程中,透過檢查返回的錯誤碼 ret 來確保操作的正確性,如果出現錯誤,及時釋放已分配的資源。
- 最後,獲取金鑰的二進位制資料並釋放資源:

ret = OH_CryptoSymKey_GetKeyData(keyCtx, &out);
OH_CryptoSymKeyGenerator_Destroy(ctx);
OH_CryptoSymKey_Destroy(keyCtx);
if (ret!= CRYPTO_SUCCESS) {
    return ret;
}
OH_Crypto_FreeDataBlob(&out);
return ret;

使用 OH_CryptoSymKey_GetKeyData 函式獲取生成金鑰的二進位制資料,並儲存在 out 結構體中。然後依次銷燬金鑰生成器上下文和金鑰物件,釋放相關資源。最後,使用 OH_Crypto_FreeDataBlob 函式釋放儲存二進位制資料的結構體所佔用的記憶體。

四、指定二進位制資料轉換對稱金鑰(ArkTS 與 C/C++ 示例)

(一)轉換流程與程式碼示例分析(ArkTS)

  1. 首先,獲取指定的對稱金鑰二進位制資料並封裝成 DataBlob 物件:
function genKeyMaterialBlob(): cryptoFramework.DataBlob {
  let arr = [
    0xba, 0x3d, 0xc2, 0x71, 0x21, 0x1e, 0x30, 0x56,
    0xad, 0x47, 0xfc, 0x5a, 0x46, 0x39, 0xee, 0x7c,
    0xba, 0x3b, 0xc2, 0x71, 0xab, 0xa0, 0x30, 0x72]; // 金鑰長度為192位,即24位元組。
  let keyMaterial = new Uint8Array(arr);
  return { data: keyMaterial };
}

這裡定義了一個函式 genKeyMaterialBlob,用於建立一個包含特定二進位制資料的 DataBlob 物件,模擬了從外部獲取或儲存的對稱金鑰二進位制資料。
2. 接著,建立對稱金鑰生成器並進行轉換:

let symKeyGenerator = cryptoFramework.createSymKeyGenerator('3DES192');
let keyMaterialBlob = genKeyMaterialBlob();
try {
  symKeyGenerator.convertKey(keyMaterialBlob, (error, key) => {
    if (error) {
      let e: BusinessError = error as BusinessError;
      console.error(`convertKey error, ${e.code}, ${e.message}`);
      return;
    }
    console.info('key algName:' + key.algName);
    console.info('key format:' + key.format);
    let encodedKey = key.getEncoded();
    console.info('key getEncoded hex: ' + encodedKey.data);
  });
} catch (error) {
  let e: BusinessError = error as BusinessError;
  console.error(`convertKey failed, ${e.code}, ${e.message}`);
}

首先建立一個金鑰演算法為3DES、金鑰長度為192位的對稱金鑰生成器。然後使用 convertKey 方法,傳入之前建立的 DataBlob 物件,嘗試將二進位制資料轉換為對稱金鑰。如果轉換成功,在回撥函式中獲取生成的金鑰物件,輸出其演算法名稱、格式以及二進位制資料(以十六進位制字串形式)。如果轉換過程中出現錯誤,透過捕獲異常並輸出錯誤資訊。

(二)轉換流程與程式碼示例分析(C/C++)

  1. 同樣,先準備好二進位制資料並封裝成 Crypto_DataBlob 結構:
#include "CryptoArchitectureKit/crypto_common.h"
#include "CryptoArchitectureKit/crypto_sym_key.h"
#include <string.h>
static OH_Crypto_ErrCode testConvertHmacKey() {
    const char *algName = "HMAC";
    OH_CryptoSymKeyGenerator *ctx = nullptr;
    OH_CryptoSymKey *convertKeyCtx = nullptr;
    Crypto_DataBlob out = {.data = nullptr,.len = 0};
    OH_Crypto_ErrCode ret;
    char *arr = const_cast<char *>("12345678abcdefgh12345678abcdefgh12345678abcdefgh12345678abcdefgh");
    Crypto_DataBlob convertBlob = {.data = (uint8_t *)(arr),.len = strlen(arr)};

這裡定義了一個函式 testConvertHmacKey,建立了一個包含特定字串(模擬二進位制資料)的 Crypto_DataBlob 結構,用於後續的轉換操作。
2. 然後,建立對稱金鑰生成器並進行轉換:

ret = OH_CryptoSymKeyGenerator_Create(algName, &ctx);
if (ret!= CRYPTO_SUCCESS) {
    return ret;
}
ret = OH_CryptoSymKeyGenerator_Convert(ctx, &convertBlob, &convertKeyCtx);
if (ret!= CRYPTO_SUCCESS) {
    OH_CryptoSymKeyGenerator_Destroy(ctx);
    return ret;
}

使用 OH_CryptoSymKeyGenerator_Create 函式建立一個HMAC金鑰生成器(這裡以HMAC為例,其他對稱金鑰演算法類似),傳入演算法名稱字串。然後使用 OH_CryptoSymKeyGenerator_Convert 函式,傳入準備好的二進位制資料 convertBlob,嘗試將其轉換為對稱金鑰。如果轉換成功,繼續後續操作;如果轉換失敗,及時銷燬已建立的金鑰生成器上下文並返回錯誤碼。
3. 最後,獲取轉換後的金鑰二進位制資料並釋放資源:

ret = OH_CryptoSymKey_GetKeyData(convertKeyCtx, &out);
OH_CryptoSymKeyGenerator_Destroy(ctx);
OH_CryptoSymKey_Destroy(convertKeyCtx);
if (ret!= CRYPTO_SUCCESS) {
    return ret;
}
OH_Crypto_FreeDataBlob(&out);
return ret;

使用 OH_CryptoSymKey_GetKeyData 函式獲取轉換後金鑰的二進位制資料,並儲存在 out 結構體中。然後依次銷燬金鑰生成器上下文和金鑰物件,釋放相關資源。最後,使用 OH_Crypto_FreeDataBlob 函式釋放儲存二進位制資料的結構體所佔用的記憶體。

五、總結

在本次對 HarmonyOS Next 對稱金鑰生成的深入探索中,我們詳細瞭解了多種生成和轉換對稱金鑰的方式。透過對 AES、3DES、SM4 等演算法特點和適用場景的分析,我們能夠根據實際需求選擇最合適的演算法。在隨機生成對稱金鑰方面,ArkTS 和 C/C++ 兩種實現方式各有特點,ArkTS 藉助 Promise 實現了非同步操作,方便在複雜應用中管理金鑰生成過程,而 C/C++ 則透過傳統的函式呼叫和錯誤碼處理方式提供了高效的效能。在指定二進位制資料轉換對稱金鑰時,同樣的兩種語言實現都清晰地展示了轉換流程,從資料準備、生成器建立到轉換操作和結果處理。
對於選擇何種生成和轉換方式,我們開發者需要綜合考慮多個因素。如果應用是基於 ArkTS 開發且注重非同步操作和簡潔的程式碼結構,那麼 ArkTS 的相關方法會是不錯的選擇;而如果對效能有較高要求且熟悉 C/C++ 程式設計,C/C++ 實現則更能發揮其優勢。同時,還需考慮金鑰的使用場景、系統資源以及與其他元件的相容性等因素,以上。

相關文章