openHiTLS開源發布HPKE(混合公鑰加密)特性:讓數據加密在 “魚與熊掌”間找到最優解

引言

數字世界里,信息傳遞都面臨著兩難挑戰,我們既要跑得夠快,又要防止被不法分子半路 “搶包”或者“偷換”。HPKE(混合公鑰加密)可以結合傳統對稱和非對稱算法優勢,兼具高速傳輸與強安全性,成為構筑未來網絡安全體系的重要基石。

1. 混合公鑰加密機制優勢

當前傳統加密存在明顯的局限性,對稱加密雖高效,但密鑰分發存在安全隱患,非對稱加密解決了密鑰分發問題,但算法復雜度較高導致性能偏低。HPKE是一種融合二者優勢的混合加密體系,既保留了公鑰加密的安全性與靈活性,又繼承了對稱加密的高效性,讓數據加密不再陷入 “安全與效率不可兼得” 的困境。

而TLS協議同為混合加密體系,需處理身份驗證、連接握手等復雜流程,協議棧復雜且資源消耗高,適用于瀏覽器與服務器的長連接場景。而 HPKE 專注于 “單條信息加密傳輸”,無需建立持久連接,流程更加輕量,應用場景更加靈活。二者定位互補,可共通守護互聯網的數字安全。

2. 三步流程解析HPKE算法

RFC9180中定義了HPKE算法的主要流程, 算法設定了消息的發送者和接收者, 以下簡單介紹Base模式算法流程:

發送者首先需要獲取接收者的長期公鑰,然后執行以下流程:

  1. 臨時生成密鑰對,使用密鑰封裝算法(KEM)計算共享密鑰, 并輸出封裝密鑰;
  2. 通過密鑰派生函數(KDF)對共享密鑰及其上下文信息派生出對稱密鑰與base_nonce,以及其他密鑰導出材料;
  3. 使用對稱算法(AEAD)對數據進行加密, 輸出密文。

接收者收到發送者的封裝密鑰與密文后執行以下流程:

  1. 使用密鑰封裝算法(KEM)計算共享密鑰,輸入為收到的封裝密鑰與自己的長期私鑰;
  2. 通過密鑰派生函數(KDF)對共享密鑰及其上下文信息派生出對稱密鑰與其他所需信息;
  3. 數據加密:使用對稱算法(AEAD)對數據進行解密, 輸出明文。

詳細交互流程可參考下圖

3. HPKE核心技術優勢

HPKE 的技術競爭力體現在以下四個方面:

1.安全性:采用臨時密鑰機制,每次加密生成全新密鑰對,降低泄露風險。在密鑰封裝階段,通過哈希函數對密鑰材料進行處理,有效抵抗碰撞攻擊。?

2. 高效性:非對稱加密僅用于密鑰交換環節,數據傳輸依賴高效對稱加密,在大文件傳輸、高頻通信場景表現優異,尤其適配算力受限的物聯網設備。

3. 靈活性:HPKE算法不依賴特定的網絡協議或通信模式,不依賴通信雙方同時在線,可以能在各類場景中靈活部署。

4. 可擴展性:HPKE的“密鑰封裝 + 數據加密”架構設計為功能擴展預留了充足空間,對于融合后量子算法有天然優勢,可從容應對未來的安全挑戰。

4. 典型應用場景

HPKE憑借其特有優勢,可在多個領域展現出強大的應用價值,如:

1. 即時通訊場景:在即時通訊場景中,用戶的聊天內容屬于高度隱私信息。HPKE 能為每一條消息提供端到端的加密保護,發送方通過接收方的公鑰對消息加密,只有擁有對應私鑰的接收方才能解密查看。即使是通訊服務提供商,也無法獲取消息的真實內容,有效防止了聊天記錄被監聽、泄露,為用戶的私密對話保駕護航。

2. 物聯網場景:物聯網設備數量龐大且類型多樣,傳感器實時采集的溫度、濕度、設備運行狀態等數據在傳輸過程中面臨被篡改、竊取的風險。HPKE 的輕量化特性使其能在算力有限的物聯網設備上高效運行,確保數據從采集端到平臺端的安全傳輸。

3. 郵件系統場景:商務郵件和個人私密郵件往往包含重要信息,一旦泄露可能造成嚴重后果。HPKE能實現郵件的端到端加密,發件人撰寫郵件后,利用收件人的公鑰對郵件內容加密,郵件服務器僅負責傳輸加密后的內容,無法解密查看。收件人收到郵件后,用自己的私鑰解密即可讀取。這種方式有效防范了郵件在傳輸環節和存儲環節的安全風險,讓郵件通信更加安全可靠。

5. 未來展望

在隱私保護需求激增的背景下,混合加密融合對稱加密和非對稱加密算法優勢,兼顧安全與性能,優勢日益凸顯。值得關注的是,openHiTLS已高效完成了該算法的落地實現,進一步推動了該技術在實際場景中的落地應用,從理論走向實踐,為不同行業、不同場景提供了 “量體裁衣” 的加密解決方案,也讓HPKE成為數字時代加密技術的重要選擇。

未來,隨著后量子算法的不斷成熟和普及,HPKE也有望成為連接傳統加密體系與后量子加密體系的重要橋梁,為數字世界在量子時代的安全提供持續保障,推動安全技術邁向新的高度。

開源實踐:openHiTLS開源HPKE代碼實現

代碼倉鏈接:GitCode - 全球開發者的開源社區,開源代碼托管平臺

/** This file is part of the openHiTLS project.** openHiTLS is licensed under the Mulan PSL v2.* You can use this software according to the terms and conditions of the Mulan PSL v2.* You may obtain a copy of Mulan PSL v2 at:**     http://license.coscl.org.cn/MulanPSL2** THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.* See the Mulan PSL v2 for more details.*/#include "hitls_build.h"#if defined(HITLS_CRYPTO_EAL) && defined(HITLS_CRYPTO_HPKE)#include <string.h>
#include "securec.h"
#include "crypt_eal_pkey.h"
#include "crypt_eal_kdf.h"
#include "crypt_eal_cipher.h"
#include "crypt_eal_rand.h"
#include "crypt_algid.h"
#include "crypt_errno.h"
#include "crypt_bn.h"
#include "crypt_params_key.h"
#include "bsl_err_internal.h"
#include "bsl_sal.h"
#include "bsl_bytes.h"#include "crypt_eal_hpke.h"// Data from RFC9180
#define HPKE_HKDF_MAX_EXTRACT_KEY_LEN 64
#define HPKE_KEM_MAX_SHARED_KEY_LEN  64
#define HPKE_KEM_MAX_ENCAPSULATED_KEY_LEN  133
#define HPKE_KEM_MAX_PUBLIC_KEY_LEN  133
#define HPKE_KEM_MAX_PRIVATE_KEY_LEN  66
#define HPKE_KEM_DH_MAX_SHARED_KEY_LEN 66 // p521 key length
#define MAX_ECC_PARAM_LEN 66#define HPKE_AEAD_NONCE_LEN  12
#define HPKE_AEAD_TAG_LEN  16#define HPKE_KEM_SUITEID_LEN 5
#define HPKE_HPKE_SUITEID_LEN 10typedef struct {// PSK modeuint8_t *psk;uint32_t pskLen;uint8_t *pskId;uint32_t pskIdLen;// AUTH mode, Sender's private key held by the sender, Sender's public key held by the recipientCRYPT_EAL_PkeyCtx *authPkey;
} AuthInfo;struct CRYPT_EAL_HpkeCtx {uint8_t role;                    // Sender or Recipientuint8_t mode;                    // HPKE modeuint8_t kemIndex;uint8_t kdfIndex;uint8_t aeadIndex;uint8_t *symKey;uint8_t *baseNonce;uint32_t symKeyLen;uint32_t baseNonceLen;uint8_t *exporterSecret;uint8_t *sharedSecret;uint32_t exporterSecretLen;uint32_t sharedSecretLen;uint64_t seq;                   // Message sequence numberCRYPT_EAL_KdfCTX *kdfCtx;CRYPT_EAL_CipherCtx *cipherCtx;CRYPT_EAL_LibCtx *libCtx;char *attrName;AuthInfo *authInfo;
};typedef struct {uint16_t hpkeKemId;CRYPT_PKEY_AlgId pkeyId;CRYPT_PKEY_ParaId curveId;CRYPT_MAC_AlgId macId;uint16_t privateKeyLen;uint16_t sharedKeyLen;uint16_t encapsulatedKeyLen;uint16_t hkdfExtractKeyLen;
} HPKE_KemAlgInfo;typedef struct {uint16_t hpkeKdfId;uint16_t hkdfExtractKeyLen;CRYPT_MAC_AlgId macId;
} HPKE_KdfAlgInfo;typedef struct {uint16_t hpkeAeadId;uint16_t keyLen;CRYPT_CIPHER_AlgId cipherId;
} HPKE_AeadAlgInfo;#define HPKE_INVALID_ALG_INDEX 0xFFstatic HPKE_KemAlgInfo g_hpkeKemAlgInfo[] = {{CRYPT_KEM_DHKEM_P256_HKDF_SHA256, CRYPT_PKEY_ECDH, CRYPT_ECC_NISTP256, CRYPT_MAC_HMAC_SHA256, 32, 32, 65, 32},{CRYPT_KEM_DHKEM_P384_HKDF_SHA384, CRYPT_PKEY_ECDH, CRYPT_ECC_NISTP384, CRYPT_MAC_HMAC_SHA384, 48, 48, 97, 48},{CRYPT_KEM_DHKEM_P521_HKDF_SHA512, CRYPT_PKEY_ECDH, CRYPT_ECC_NISTP521, CRYPT_MAC_HMAC_SHA512, 66, 64, 133, 64},{CRYPT_KEM_DHKEM_X25519_HKDF_SHA256, CRYPT_PKEY_X25519, CRYPT_PKEY_PARAID_MAX, CRYPT_MAC_HMAC_SHA256, 32, 32, 32,32},
};static HPKE_KdfAlgInfo g_hpkeKdfAlgInfo[] = {{CRYPT_KDF_HKDF_SHA256, 32, CRYPT_MAC_HMAC_SHA256},{CRYPT_KDF_HKDF_SHA384, 48, CRYPT_MAC_HMAC_SHA384},{CRYPT_KDF_HKDF_SHA512, 64, CRYPT_MAC_HMAC_SHA512},
};static HPKE_AeadAlgInfo g_hpkeAeadAlgInfo[] = {{CRYPT_AEAD_AES_128_GCM, 16, CRYPT_CIPHER_AES128_GCM},{CRYPT_AEAD_AES_256_GCM, 32, CRYPT_CIPHER_AES256_GCM},{CRYPT_AEAD_CHACHA20_POLY1305, 32, CRYPT_CIPHER_CHACHA20_POLY1305},{CRYPT_AEAD_EXPORT_ONLY, 0, CRYPT_CIPHER_MAX},
};static int32_t HpkeCheckCipherSuite(const CRYPT_HPKE_CipherSuite *cipherSuite, uint8_t *kemIndex, uint8_t *kdfIndex,uint8_t *aeadIndex)
{uint8_t kemPosition = HPKE_INVALID_ALG_INDEX;uint8_t kdfPosition = HPKE_INVALID_ALG_INDEX;uint8_t aeadPosition = HPKE_INVALID_ALG_INDEX;uint8_t i;for (i = 0; i < sizeof(g_hpkeKemAlgInfo) / sizeof(HPKE_KemAlgInfo); i++) {if (cipherSuite->kemId == g_hpkeKemAlgInfo[i].hpkeKemId) {kemPosition = i;break;}}for (i = 0; i < sizeof(g_hpkeKdfAlgInfo) / sizeof(HPKE_KdfAlgInfo); i++) {if (cipherSuite->kdfId == g_hpkeKdfAlgInfo[i].hpkeKdfId) {kdfPosition = i;break;}}for (i = 0; i < sizeof(g_hpkeAeadAlgInfo) / sizeof(HPKE_AeadAlgInfo); i++) {if (cipherSuite->aeadId == g_hpkeAeadAlgInfo[i].hpkeAeadId) {aeadPosition = i;break;}}if (kemPosition == HPKE_INVALID_ALG_INDEX || kdfPosition == HPKE_INVALID_ALG_INDEX ||aeadPosition == HPKE_INVALID_ALG_INDEX) {BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);return CRYPT_INVALID_ARG;}if (kemIndex != NULL) {*kemIndex = kemPosition;}if (kdfIndex != NULL) {*kdfIndex = kdfPosition;}if (aeadIndex != NULL) {*aeadIndex = aeadPosition;}return CRYPT_SUCCESS;
}static int32_t InitCipherSuiteCtx(CRYPT_EAL_HpkeCtx *ctx, uint8_t aeadIndex, CRYPT_EAL_LibCtx *libCtx,const char *attrName)
{CRYPT_EAL_KdfCTX *kdfCtx = NULL;CRYPT_EAL_CipherCtx *cipherCtx = NULL;kdfCtx = CRYPT_EAL_ProviderKdfNewCtx(libCtx, CRYPT_KDF_HKDF, attrName);if (kdfCtx == NULL) {return CRYPT_HPKE_FAILED_FETCH_KDF;}if (g_hpkeAeadAlgInfo[aeadIndex].hpkeAeadId != CRYPT_AEAD_EXPORT_ONLY) {cipherCtx = CRYPT_EAL_ProviderCipherNewCtx(libCtx, g_hpkeAeadAlgInfo[aeadIndex].cipherId, attrName);if (cipherCtx == NULL) {CRYPT_EAL_KdfFreeCtx(kdfCtx);return CRYPT_HPKE_FAILED_FETCH_CIPHER;}}ctx->kdfCtx = kdfCtx;ctx->cipherCtx = cipherCtx;return CRYPT_SUCCESS;
}static int32_t HpkeInitCipherSuite(CRYPT_EAL_HpkeCtx *ctx, CRYPT_HPKE_CipherSuite *cipherSuite,CRYPT_EAL_LibCtx *libCtx, const char *attrName)
{uint8_t kemIndex;uint8_t kdfIndex;uint8_t aeadIndex;int32_t ret;ret = HpkeCheckCipherSuite(cipherSuite, &kemIndex, &kdfIndex, &aeadIndex);if (ret != CRYPT_SUCCESS) {return ret;}ret = InitCipherSuiteCtx(ctx, aeadIndex, libCtx, attrName);if (ret != CRYPT_SUCCESS) {BSL_ERR_PUSH_ERROR(ret);return ret;}ctx->kemIndex = kemIndex;ctx->aeadIndex = aeadIndex;ctx->kdfIndex = kdfIndex;return CRYPT_SUCCESS;
}CRYPT_EAL_HpkeCtx *CRYPT_EAL_HpkeNewCtx(CRYPT_EAL_LibCtx *libCtx, const char *attrName, CRYPT_HPKE_Role role,CRYPT_HPKE_Mode mode, CRYPT_HPKE_CipherSuite cipherSuite)
{if (role != CRYPT_HPKE_SENDER && role != CRYPT_HPKE_RECIPIENT) {BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);return NULL;}if (mode != CRYPT_HPKE_MODE_BASE && mode != CRYPT_HPKE_MODE_PSK && mode != CRYPT_HPKE_MODE_AUTH &&mode != CRYPT_HPKE_MODE_AUTH_PSK) {BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);return NULL;}CRYPT_EAL_HpkeCtx *ctx = (CRYPT_EAL_HpkeCtx*)BSL_SAL_Calloc(1, sizeof(CRYPT_EAL_HpkeCtx));if (ctx == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);return NULL;}int32_t ret = HpkeInitCipherSuite(ctx, &cipherSuite, libCtx, attrName);if (ret != CRYPT_SUCCESS) {CRYPT_EAL_HpkeFreeCtx(ctx);return NULL;}if (attrName != NULL && strlen(attrName) > 0) {ctx->attrName = BSL_SAL_Dump(attrName, (uint32_t)strlen(attrName) + 1);if (ctx->attrName == NULL) {CRYPT_EAL_HpkeFreeCtx(ctx);BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);return NULL;}}if (mode == CRYPT_HPKE_MODE_PSK || mode == CRYPT_HPKE_MODE_AUTH || mode == CRYPT_HPKE_MODE_AUTH_PSK) {AuthInfo *authInfo = (AuthInfo *)BSL_SAL_Calloc(1, sizeof(AuthInfo));if (authInfo == NULL) {CRYPT_EAL_HpkeFreeCtx(ctx);BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);return NULL;}ctx->authInfo = authInfo;}ctx->mode = mode;ctx->role = role;ctx->libCtx = libCtx;return ctx;
}int32_t CRYPT_EAL_HpkeGetEncapKeyLen(CRYPT_HPKE_CipherSuite cipherSuite, uint32_t *encapKeyLen)
{if (encapKeyLen == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);return CRYPT_NULL_INPUT;}uint8_t kemIndex;int32_t ret = HpkeCheckCipherSuite(&cipherSuite, &kemIndex, NULL, NULL);if (ret != CRYPT_SUCCESS) {return ret;}*encapKeyLen = g_hpkeKemAlgInfo[kemIndex].encapsulatedKeyLen;return CRYPT_SUCCESS;
}static int32_t HpkeCreatePkeyCtx(uint8_t kemIdex, CRYPT_EAL_PkeyCtx **pkeyCtx, CRYPT_EAL_LibCtx *libCtx,const char *attrName)
{CRYPT_PKEY_AlgId algId = g_hpkeKemAlgInfo[kemIdex].pkeyId;CRYPT_EAL_PkeyCtx *pkey = NULL;
#ifdef HITLS_CRYPTO_PROVIDERpkey = CRYPT_EAL_ProviderPkeyNewCtx(libCtx, algId, CRYPT_EAL_PKEY_EXCH_OPERATE, attrName);
#else(void)libCtx;(void)attrName;pkey = CRYPT_EAL_PkeyNewCtx(algId);
#endifif (pkey == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_HPKE_FAILED_FETCH_PKEY);return CRYPT_HPKE_FAILED_FETCH_PKEY;}if (algId == CRYPT_PKEY_ECDH) {CRYPT_PKEY_ParaId curveId = g_hpkeKemAlgInfo[kemIdex].curveId;int32_t ret = CRYPT_EAL_PkeySetParaById(pkey, curveId);if (ret != CRYPT_SUCCESS) {CRYPT_EAL_PkeyFreeCtx(pkey);return ret;}}*pkeyCtx = pkey;return CRYPT_SUCCESS;
}static int32_t HpkeCreatePubKey(uint8_t kemIdex, uint8_t *pubKey, uint32_t pubKeyLen, CRYPT_EAL_PkeyCtx **pkey,CRYPT_EAL_LibCtx *libCtx, const char *attrName)
{CRYPT_EAL_PkeyCtx *tmpPkey = NULL;int32_t ret = HpkeCreatePkeyCtx(kemIdex, &tmpPkey, libCtx, attrName);if (ret != CRYPT_SUCCESS) {return ret;}CRYPT_EAL_PkeyPub pub = {0};pub.id = CRYPT_EAL_PkeyGetId(tmpPkey);pub.key.eccPub.data = pubKey; // compatible curve25519Pubpub.key.eccPub.len = pubKeyLen;ret = CRYPT_EAL_PkeySetPub(tmpPkey, &pub);if (ret != CRYPT_SUCCESS) {CRYPT_EAL_PkeyFreeCtx(tmpPkey);return ret;}*pkey = tmpPkey;return CRYPT_SUCCESS;
}static int32_t HpkeCreatePriKey(uint8_t kemIdex, uint8_t *priKey, uint32_t priKeyLen, CRYPT_EAL_PkeyCtx **pkey,CRYPT_EAL_LibCtx *libCtx, const char *attrName)
{CRYPT_EAL_PkeyCtx *tmpPkey = *pkey;int32_t ret;if (tmpPkey == NULL) {ret = HpkeCreatePkeyCtx(kemIdex, &tmpPkey, libCtx, attrName);if (ret != CRYPT_SUCCESS) {return ret;}}CRYPT_EAL_PkeyPrv prv = {0};prv.id = CRYPT_EAL_PkeyGetId(tmpPkey);prv.key.eccPrv.data = priKey;prv.key.eccPrv.len = priKeyLen;ret = CRYPT_EAL_PkeySetPrv(tmpPkey, &prv);if (ret != CRYPT_SUCCESS) {goto EXIT;}if (g_hpkeKemAlgInfo[kemIdex].hpkeKemId == CRYPT_KEM_DHKEM_X25519_HKDF_SHA256) {ret = CRYPT_EAL_PkeyCtrl(tmpPkey, CRYPT_CTRL_GEN_X25519_PUBLICKEY, NULL, 0);} else {ret = CRYPT_EAL_PkeyCtrl(tmpPkey, CRYPT_CTRL_GEN_ECC_PUBLICKEY, NULL, 0);}if (ret == CRYPT_SUCCESS) {*pkey = tmpPkey;return CRYPT_SUCCESS;}EXIT:if (*pkey == NULL) {CRYPT_EAL_PkeyFreeCtx(tmpPkey);}return ret;
}static inline void HpkeGenerateHpkeSuiteId(uint8_t kemIndex, uint8_t kdfIndex, uint8_t aeadIndex, uint8_t *suiteId,uint32_t suiteIdLen)
{(void)memcpy_s(suiteId, suiteIdLen, "HPKE", strlen("HPKE"));uint32_t offset = strlen("HPKE");BSL_Uint16ToByte(g_hpkeKemAlgInfo[kemIndex].hpkeKemId, suiteId + offset);offset += sizeof(uint16_t);BSL_Uint16ToByte(g_hpkeKdfAlgInfo[kdfIndex].hpkeKdfId, suiteId + offset);offset += sizeof(uint16_t);BSL_Uint16ToByte(g_hpkeAeadAlgInfo[aeadIndex].hpkeAeadId, suiteId + offset);
}static inline void HpkeGenerateKemSuiteId(uint8_t kemIdex, uint8_t *suiteId, uint32_t suiteIdLen)
{uint16_t kemId = g_hpkeKemAlgInfo[kemIdex].hpkeKemId;(void)memcpy_s(suiteId, suiteIdLen, "KEM", strlen("KEM"));uint32_t offset = strlen("KEM");BSL_Uint16ToByte(kemId, suiteId + offset);
}typedef struct {int32_t macId;uint8_t *key;uint32_t keyLen;uint8_t *salt;uint32_t saltLen;
} HPKE_HkdfExtractParams;typedef struct {int32_t macId;uint8_t *prk;uint32_t prkLen;uint8_t *info;uint32_t infoLen;
} HPKE_HkdfExpandParam;static int32_t HpkeHkdfExtract(CRYPT_EAL_KdfCTX *hkdfCtx, HPKE_HkdfExtractParams *extractParams, uint8_t *out,uint32_t outLen)
{int32_t ret;CRYPT_HKDF_MODE mode = CRYPT_KDF_HKDF_MODE_EXTRACT;BSL_Param params[6] = {{0}, {0}, {0}, {0}, {0}, BSL_PARAM_END}; // 6 parametersret = BSL_PARAM_InitValue(&params[0], CRYPT_PARAM_KDF_MAC_ID, BSL_PARAM_TYPE_UINT32, (void *)&extractParams->macId,sizeof(int32_t));if (ret != CRYPT_SUCCESS) {return ret;}ret = BSL_PARAM_InitValue(&params[1], CRYPT_PARAM_KDF_MODE, BSL_PARAM_TYPE_UINT32, (void *)&mode, sizeof(mode));if (ret != CRYPT_SUCCESS) {return ret;}ret = BSL_PARAM_InitValue(&params[2], CRYPT_PARAM_KDF_KEY, BSL_PARAM_TYPE_OCTETS, // param index 2(void *)extractParams->key, extractParams->keyLen);if (ret != CRYPT_SUCCESS) {return ret;}ret = BSL_PARAM_InitValue(&params[3], CRYPT_PARAM_KDF_SALT, BSL_PARAM_TYPE_OCTETS, // param index 3(void *)extractParams->salt, extractParams->saltLen);if (ret != CRYPT_SUCCESS) {return ret;}ret = BSL_PARAM_InitValue(&params[4], CRYPT_PARAM_KDF_EXLEN, BSL_PARAM_TYPE_UINT32_PTR, // param index 4(void *)&outLen, sizeof(outLen));if (ret != CRYPT_SUCCESS) {return ret;}ret = CRYPT_EAL_KdfSetParam(hkdfCtx, params);if (ret != CRYPT_SUCCESS) {return ret;}ret = CRYPT_EAL_KdfDerive(hkdfCtx, out, outLen);CRYPT_EAL_KdfDeInitCtx(hkdfCtx);return ret;
}static int32_t HpkeHkdfExpand(CRYPT_EAL_KdfCTX *hkdfCtx, HPKE_HkdfExpandParam *expandParams, uint8_t *out,uint32_t outLen)
{int32_t ret;CRYPT_HKDF_MODE mode = CRYPT_KDF_HKDF_MODE_EXPAND;BSL_Param params[5] = {{0}, {0}, {0}, {0}, BSL_PARAM_END}; // 5 parametersret = BSL_PARAM_InitValue(&params[0], CRYPT_PARAM_KDF_MAC_ID, BSL_PARAM_TYPE_UINT32, (void *)&expandParams->macId,sizeof(int32_t));if (ret != CRYPT_SUCCESS) {return ret;}ret = BSL_PARAM_InitValue(&params[1], CRYPT_PARAM_KDF_MODE, BSL_PARAM_TYPE_UINT32, (void *)&mode, sizeof(mode));if (ret != CRYPT_SUCCESS) {return ret;}ret = BSL_PARAM_InitValue(&params[2], CRYPT_PARAM_KDF_PRK, BSL_PARAM_TYPE_OCTETS, // param index 2(void *)expandParams->prk, expandParams->prkLen);if (ret != CRYPT_SUCCESS) {return ret;}ret = BSL_PARAM_InitValue(&params[3], CRYPT_PARAM_KDF_INFO, BSL_PARAM_TYPE_OCTETS, // param index 3(void *)expandParams->info, expandParams->infoLen);if (ret != CRYPT_SUCCESS) {return ret;}ret = CRYPT_EAL_KdfSetParam(hkdfCtx, params);if (ret != CRYPT_SUCCESS) {return ret;}ret = CRYPT_EAL_KdfDerive(hkdfCtx, out, outLen);CRYPT_EAL_KdfDeInitCtx(hkdfCtx);return ret;
}typedef struct {int32_t macId;uint8_t *salt;uint32_t saltLen;uint8_t *label;uint32_t labelLen;uint8_t *ikm;uint32_t ikmLen;uint8_t *suiteId;uint32_t suiteIdLen;
} HPKE_LabeledExtractParams;typedef struct {int32_t macId;uint8_t *prk;uint32_t prkLen;uint8_t *label;uint32_t labelLen;uint8_t *info;uint32_t infoLen;uint8_t *suiteId;uint32_t suiteIdLen;
} HPKE_LabeledExpandParams;static int32_t HpkeLabeledExtract(CRYPT_EAL_KdfCTX *hkdfCtx, HPKE_LabeledExtractParams *params, uint8_t *out,uint32_t outLen)
{// labeled_ikm = "HPKE-v1" || suite_id || label || ikmconst uint8_t *version = (const uint8_t *)"HPKE-v1";uint32_t versionLen = strlen("HPKE-v1");uint32_t partialLen = versionLen + params->suiteIdLen + params->labelLen;if (params->ikmLen > (UINT32_MAX - partialLen)) {BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);return CRYPT_INVALID_ARG;}uint32_t labeledIkmLen = partialLen + params->ikmLen;uint8_t *labeledIkm = (uint8_t *)BSL_SAL_Malloc(labeledIkmLen);if (labeledIkm == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);return CRYPT_MEM_ALLOC_FAIL;}uint32_t offset = 0;(void)memcpy_s(labeledIkm + offset, labeledIkmLen - offset, version, versionLen);offset += versionLen;(void)memcpy_s(labeledIkm + offset, labeledIkmLen - offset, params->suiteId, params->suiteIdLen);offset += params->suiteIdLen;(void)memcpy_s(labeledIkm + offset, labeledIkmLen - offset, params->label, params->labelLen);offset += params->labelLen;(void)memcpy_s(labeledIkm + offset, labeledIkmLen - offset, params->ikm, params->ikmLen);HPKE_HkdfExtractParams extractParams = {params->macId, labeledIkm, labeledIkmLen, params->salt, params->saltLen};int32_t ret = HpkeHkdfExtract(hkdfCtx, &extractParams, out, outLen);BSL_SAL_ClearFree(labeledIkm, labeledIkmLen);return ret;
}static int32_t HpkeLabeledExpand(CRYPT_EAL_KdfCTX *hkdfCtx, HPKE_LabeledExpandParams *params, uint8_t *out,uint32_t outLen)
{// labeled_info = I2OSP(L, 2) || "HPKE-v1" || suite_id || label || infoconst uint8_t *version = (const uint8_t *)"HPKE-v1";uint32_t versionLen = strlen("HPKE-v1");uint32_t partialLen = sizeof(uint16_t) + versionLen + params->suiteIdLen + params->labelLen;if (params->infoLen > (UINT32_MAX - partialLen)) {BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);return CRYPT_INVALID_ARG;}uint32_t labeledInfoLen = partialLen + params->infoLen;uint8_t *labeledInfo = (uint8_t *)BSL_SAL_Malloc(labeledInfoLen);if (labeledInfo == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);return CRYPT_MEM_ALLOC_FAIL;}BSL_Uint16ToByte((uint16_t)outLen, labeledInfo);uint32_t offset = sizeof(uint16_t);(void)memcpy_s(labeledInfo + offset, labeledInfoLen - offset, version, versionLen);offset += versionLen;(void)memcpy_s(labeledInfo + offset, labeledInfoLen - offset, params->suiteId, params->suiteIdLen);offset += params->suiteIdLen;(void)memcpy_s(labeledInfo + offset, labeledInfoLen - offset, params->label, params->labelLen);offset += params->labelLen;(void)memcpy_s(labeledInfo + offset, labeledInfoLen - offset, params->info, params->infoLen);HPKE_HkdfExpandParam expandParams = {params->macId, params->prk, params->prkLen, labeledInfo, labeledInfoLen};int32_t ret = HpkeHkdfExpand(hkdfCtx, &expandParams, out, outLen);BSL_SAL_FREE(labeledInfo);return ret;
}static int32_t GetPubKeyData(CRYPT_EAL_PkeyCtx *pkey, uint8_t *out, uint32_t *outLen)
{CRYPT_EAL_PkeyPub ephemPub = { 0 };ephemPub.id = CRYPT_EAL_PkeyGetId(pkey);ephemPub.key.eccPub.data = out;ephemPub.key.eccPub.len = *outLen; // compatible curve25519Pub, CRYPT_Data type.int32_t ret = CRYPT_EAL_PkeyGetPub(pkey, &ephemPub);if (ret != CRYPT_SUCCESS) {return ret;}*outLen = ephemPub.key.eccPub.len;return CRYPT_SUCCESS;
}static int32_t HpkeComputeSharedSecret(CRYPT_EAL_HpkeCtx *ctx, CRYPT_EAL_PkeyCtx *priKey, CRYPT_EAL_PkeyCtx *pubKey,CRYPT_EAL_PkeyCtx *authKey, uint8_t *kemContext, uint32_t kemContextLen, uint8_t *sharedSecret,uint32_t sharedSecretLen)
{uint8_t dh[HPKE_KEM_DH_MAX_SHARED_KEY_LEN * 2];uint32_t dhLen = HPKE_KEM_DH_MAX_SHARED_KEY_LEN;int32_t ret = CRYPT_EAL_PkeyComputeShareKey(priKey, pubKey, dh, &dhLen);if (ret != CRYPT_SUCCESS) {memset_s(dh, dhLen, 0, dhLen);return ret;}if (ctx->mode == CRYPT_HPKE_MODE_AUTH || ctx->mode == CRYPT_HPKE_MODE_AUTH_PSK) {uint32_t dh0Len = HPKE_KEM_DH_MAX_SHARED_KEY_LEN;if (ctx->role == CRYPT_HPKE_SENDER) {ret = CRYPT_EAL_PkeyComputeShareKey(authKey, pubKey, dh + dhLen, &dh0Len);}if (ctx->role == CRYPT_HPKE_RECIPIENT) {ret = CRYPT_EAL_PkeyComputeShareKey(priKey, authKey, dh + dhLen, &dh0Len);}if (ret != CRYPT_SUCCESS) {memset_s(dh, dhLen + dh0Len, 0, dhLen + dh0Len);return ret;}dhLen = dhLen + dh0Len;}uint8_t suiteId[HPKE_KEM_SUITEID_LEN];HpkeGenerateKemSuiteId(ctx->kemIndex, suiteId, HPKE_KEM_SUITEID_LEN);CRYPT_MAC_AlgId macId = g_hpkeKemAlgInfo[ctx->kemIndex].macId;uint32_t eaePrkLen = g_hpkeKemAlgInfo[ctx->kemIndex].hkdfExtractKeyLen;uint8_t eaePrk[HPKE_HKDF_MAX_EXTRACT_KEY_LEN];HPKE_LabeledExtractParams extractParams = {macId, NULL, 0, (uint8_t *)"eae_prk", strlen("eae_prk"), dh, dhLen,suiteId, HPKE_KEM_SUITEID_LEN};ret = HpkeLabeledExtract(ctx->kdfCtx, &extractParams, eaePrk, eaePrkLen);BSL_SAL_CleanseData(dh, dhLen);if (ret != CRYPT_SUCCESS) {return ret;}HPKE_LabeledExpandParams expandParams = {macId, eaePrk, eaePrkLen, (uint8_t *)"shared_secret",strlen("shared_secret"), kemContext, kemContextLen, suiteId, HPKE_KEM_SUITEID_LEN};ret = HpkeLabeledExpand(ctx->kdfCtx, &expandParams, sharedSecret, sharedSecretLen);BSL_SAL_CleanseData(eaePrk, eaePrkLen);return ret;
}static int32_t HpkeCreateKemContext(uint8_t *enc, uint32_t encLen, uint8_t *pkR, uint32_t pkRLen,CRYPT_EAL_PkeyCtx *authKey, uint8_t **out, uint32_t *outLen)
{uint8_t pkSm[HPKE_KEM_MAX_PUBLIC_KEY_LEN] = { 0 };uint32_t pkSmLen = HPKE_KEM_MAX_PUBLIC_KEY_LEN;if (authKey != NULL) {int32_t ret = GetPubKeyData(authKey, pkSm, &pkSmLen);if (ret != CRYPT_SUCCESS) {return ret;}} else {pkSmLen = 0;}// kemContext = enc || pkRm || pkSmuint32_t kemContextLen = encLen + pkRLen + pkSmLen;uint8_t *kemContext = (uint8_t *)BSL_SAL_Malloc(kemContextLen);if (kemContext == NULL) {return CRYPT_MEM_ALLOC_FAIL;}(void)memcpy_s(kemContext, encLen, enc, encLen);(void)memcpy_s(kemContext + encLen, pkRLen, pkR, pkRLen);if (authKey != NULL) {(void)memcpy_s(kemContext + encLen + pkRLen, pkSmLen, pkSm, pkSmLen);}*out = kemContext;*outLen = kemContextLen;return CRYPT_SUCCESS;
}static int32_t HpkeEncap(CRYPT_EAL_HpkeCtx *ctx, CRYPT_EAL_PkeyCtx *pkey, uint8_t *pkR, uint32_t pkRLen,uint8_t *encapsulatedKey, uint32_t *encapsulatedKeyLen, uint8_t *sharedSecret, uint32_t sharedSecretLen)
{int32_t ret;CRYPT_EAL_PkeyCtx *pkeyS = pkey;if (pkeyS == NULL) {CRYPT_HPKE_CipherSuite cipherSuite = {g_hpkeKemAlgInfo[ctx->kemIndex].hpkeKemId,g_hpkeKdfAlgInfo[ctx->kdfIndex].hpkeKdfId, g_hpkeAeadAlgInfo[ctx->aeadIndex].hpkeAeadId};ret = CRYPT_EAL_HpkeGenerateKeyPair(ctx->libCtx, ctx->attrName, cipherSuite, NULL, 0, &pkeyS);if (ret != CRYPT_SUCCESS) {return ret;}}CRYPT_EAL_PkeyCtx *pkeyR = NULL;uint8_t enc[HPKE_KEM_MAX_PUBLIC_KEY_LEN] = { 0 };uint32_t encLen = HPKE_KEM_MAX_PUBLIC_KEY_LEN;uint32_t kemContextLen = 0;uint8_t *kemContext = NULL;CRYPT_EAL_PkeyCtx *authKey = NULL;if (ctx->mode == CRYPT_HPKE_MODE_AUTH || ctx->mode == CRYPT_HPKE_MODE_AUTH_PSK) {authKey = ctx->authInfo->authPkey;}ret = GetPubKeyData(pkeyS, enc, &encLen);if (ret != CRYPT_SUCCESS) {goto EXIT;}ret = HpkeCreatePubKey(ctx->kemIndex, pkR, pkRLen, &pkeyR, ctx->libCtx, ctx->attrName);if (ret != CRYPT_SUCCESS) {goto EXIT;}ret = HpkeCreateKemContext(enc, encLen, pkR, pkRLen, authKey, &kemContext, &kemContextLen);if (ret != CRYPT_SUCCESS) {goto EXIT;}ret = HpkeComputeSharedSecret(ctx, pkeyS, pkeyR, authKey, kemContext, kemContextLen, sharedSecret, sharedSecretLen);if (ret == CRYPT_SUCCESS) {(void)memcpy_s(encapsulatedKey, *encapsulatedKeyLen, enc, encLen);*encapsulatedKeyLen = encLen;}
EXIT:BSL_SAL_FREE(kemContext);CRYPT_EAL_PkeyFreeCtx(pkeyR);if (pkey == NULL) {CRYPT_EAL_PkeyFreeCtx(pkeyS);}return ret;
}static int32_t HpkeGenKeyScheduleCtx(CRYPT_EAL_HpkeCtx *ctx, uint8_t *info, uint32_t infoLen, uint8_t *pskId,uint32_t pskIdLen, uint8_t *suiteId, uint32_t suiteIdLen, uint8_t **keyScheduleContext,uint32_t *keyScheduleContextLen)
{uint32_t extractKeyLen = g_hpkeKdfAlgInfo[ctx->kdfIndex].hkdfExtractKeyLen;uint32_t contextLen = sizeof(uint8_t) + extractKeyLen + extractKeyLen;uint8_t *context = (uint8_t *)BSL_SAL_Malloc(contextLen);if (context == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);return CRYPT_MEM_ALLOC_FAIL;}context[0] = ctx->mode;uint32_t offset = sizeof(uint8_t);CRYPT_MAC_AlgId macId = g_hpkeKdfAlgInfo[ctx->kdfIndex].macId;HPKE_LabeledExtractParams params = {macId, NULL, 0, (uint8_t*)"psk_id_hash", strlen("psk_id_hash"), pskId, pskIdLen,suiteId, suiteIdLen};int32_t ret = HpkeLabeledExtract(ctx->kdfCtx, &params, context + offset, extractKeyLen);if (ret != CRYPT_SUCCESS) {goto EXIT;}offset += extractKeyLen;params.label = (uint8_t*)"info_hash";params.labelLen = strlen("info_hash");params.ikm = info;params.ikmLen = infoLen;ret = HpkeLabeledExtract(ctx->kdfCtx, &params, context + offset, extractKeyLen);if (ret != CRYPT_SUCCESS) {goto EXIT;}*keyScheduleContext = context;*keyScheduleContextLen = contextLen;return CRYPT_SUCCESS;
EXIT:BSL_SAL_ClearFree(context, contextLen);return ret;
}static void HpkeFreeKeyInfo(CRYPT_EAL_HpkeCtx *ctx)
{BSL_SAL_ClearFree(ctx->symKey, ctx->symKeyLen);ctx->symKey = NULL;ctx->symKeyLen = 0;BSL_SAL_ClearFree(ctx->baseNonce, ctx->baseNonceLen);ctx->baseNonce = NULL;ctx->baseNonceLen = 0;BSL_SAL_ClearFree(ctx->exporterSecret, ctx->exporterSecretLen);ctx->exporterSecret = NULL;ctx->exporterSecretLen = 0;
}static int32_t HpkeMallocKeyInfo(CRYPT_EAL_HpkeCtx *ctx)
{if (g_hpkeAeadAlgInfo[ctx->aeadIndex].hpkeAeadId != CRYPT_AEAD_EXPORT_ONLY) {ctx->symKeyLen = g_hpkeAeadAlgInfo[ctx->aeadIndex].keyLen;ctx->symKey = BSL_SAL_Malloc(ctx->symKeyLen);ctx->baseNonceLen = HPKE_AEAD_NONCE_LEN;ctx->baseNonce = BSL_SAL_Malloc(HPKE_AEAD_NONCE_LEN);if (ctx->symKey == NULL || ctx->baseNonce == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);HpkeFreeKeyInfo(ctx);return CRYPT_MEM_ALLOC_FAIL;}}ctx->exporterSecretLen = g_hpkeKdfAlgInfo[ctx->kdfIndex].hkdfExtractKeyLen;ctx->exporterSecret = BSL_SAL_Malloc(ctx->exporterSecretLen);if (ctx->exporterSecret == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);HpkeFreeKeyInfo(ctx);return CRYPT_MEM_ALLOC_FAIL;}return CRYPT_SUCCESS;
}static int32_t HpkeDeriveKeyInfo(CRYPT_EAL_HpkeCtx *ctx, HPKE_LabeledExpandParams *expandParams)
{CRYPT_HPKE_AEAD_AlgId aeadId = g_hpkeAeadAlgInfo[ctx->aeadIndex].hpkeAeadId;if (aeadId != CRYPT_AEAD_EXPORT_ONLY) {int32_t ret = HpkeLabeledExpand(ctx->kdfCtx, expandParams, ctx->symKey, ctx->symKeyLen);if (ret != CRYPT_SUCCESS) {return ret;}expandParams->label = (uint8_t*)"base_nonce";expandParams->labelLen = strlen("base_nonce");ret = HpkeLabeledExpand(ctx->kdfCtx, expandParams, ctx->baseNonce, ctx->baseNonceLen);if (ret != CRYPT_SUCCESS) {return ret;}}expandParams->label = (uint8_t*)"exp";expandParams->labelLen = strlen("exp");return HpkeLabeledExpand(ctx->kdfCtx, expandParams, ctx->exporterSecret, ctx->exporterSecretLen);
}static int32_t HpkeKeySchedule(CRYPT_EAL_HpkeCtx *ctx, uint8_t *sharedSecret, uint32_t sharedSecretLen, uint8_t *info,uint32_t infoLen)
{uint8_t suiteId[HPKE_HPKE_SUITEID_LEN];uint8_t suiteIdLen = HPKE_HPKE_SUITEID_LEN;HpkeGenerateHpkeSuiteId(ctx->kemIndex, ctx->kdfIndex, ctx->aeadIndex, suiteId, HPKE_HPKE_SUITEID_LEN);uint32_t contextLen;uint8_t *context = NULL;uint8_t *pskId = (uint8_t *)"";uint32_t pskIdLen = 0;uint8_t *psk = (uint8_t *)"";uint32_t pskLen = 0;if (ctx->mode == CRYPT_HPKE_MODE_PSK || ctx->mode == CRYPT_HPKE_MODE_AUTH_PSK) {pskId = ctx->authInfo->pskId;pskIdLen = ctx->authInfo->pskIdLen;psk = ctx->authInfo->psk;pskLen = ctx->authInfo->pskLen;}int32_t ret = HpkeGenKeyScheduleCtx(ctx, info, infoLen, pskId, pskIdLen, suiteId, suiteIdLen, &context,&contextLen);if (ret != CRYPT_SUCCESS) {return ret;}CRYPT_MAC_AlgId macId = g_hpkeKdfAlgInfo[ctx->kdfIndex].macId;uint8_t secret[HPKE_KEM_MAX_SHARED_KEY_LEN] = {0};uint32_t secretLen = g_hpkeKdfAlgInfo[ctx->kdfIndex].hkdfExtractKeyLen;HPKE_LabeledExtractParams extractparams = {macId, sharedSecret, sharedSecretLen, (uint8_t*)"secret",strlen("secret"), psk, pskLen, suiteId, suiteIdLen};HPKE_LabeledExpandParams expandParams = {macId, secret, secretLen, (uint8_t*)"key", strlen("key"), context,contextLen, suiteId, suiteIdLen};ret = HpkeLabeledExtract(ctx->kdfCtx, &extractparams, secret, secretLen);if (ret != CRYPT_SUCCESS) {goto EXIT;}ret = HpkeMallocKeyInfo(ctx);if (ret != CRYPT_SUCCESS) {goto EXIT;}ret = HpkeDeriveKeyInfo(ctx, &expandParams);EXIT:BSL_SAL_CleanseData(secret, HPKE_KEM_MAX_SHARED_KEY_LEN);BSL_SAL_ClearFree(context, contextLen);if (ret != CRYPT_SUCCESS) {HpkeFreeKeyInfo(ctx);}return ret;
}static int32_t HpkeCheckAuthInfo(CRYPT_EAL_HpkeCtx *ctx)
{if (ctx->mode == CRYPT_HPKE_MODE_AUTH || ctx->mode == CRYPT_HPKE_MODE_AUTH_PSK) {if (ctx->authInfo == NULL || ctx->authInfo->authPkey == NULL) {return CRYPT_HPKE_ERR_CALL;}}if (ctx->mode == CRYPT_HPKE_MODE_PSK || ctx->mode == CRYPT_HPKE_MODE_AUTH_PSK) {if (ctx->authInfo == NULL || ctx->authInfo->psk == NULL || ctx->authInfo->pskId == NULL) {return CRYPT_HPKE_ERR_CALL;}}return CRYPT_SUCCESS;
}static void HpkeFreeAuthInfo(CRYPT_EAL_HpkeCtx *ctx)
{if (ctx->authInfo == NULL) {return;}BSL_SAL_ClearFree(ctx->authInfo->psk, ctx->authInfo->pskLen);ctx->authInfo->psk = NULL;ctx->authInfo->pskLen = 0;BSL_SAL_ClearFree(ctx->authInfo->pskId, ctx->authInfo->pskIdLen);ctx->authInfo->pskId = NULL;ctx->authInfo->pskIdLen = 0;CRYPT_EAL_PkeyFreeCtx(ctx->authInfo->authPkey);ctx->authInfo->authPkey = NULL;BSL_SAL_FREE(ctx->authInfo);
}static int32_t HpkeCheckSenderParams(CRYPT_EAL_HpkeCtx *ctx, uint8_t *info, uint32_t infoLen, const uint8_t *pkR,uint32_t pkRLen, uint8_t *encapsulatedKey, uint32_t *encapsulatedKeyLen)
{if (ctx == NULL) {return CRYPT_NULL_INPUT;}if (ctx->role != CRYPT_HPKE_SENDER) {return CRYPT_HPKE_ERR_CALL;}if (ctx->sharedSecret != NULL) {return CRYPT_HPKE_ERR_CALL;}if (pkR == NULL || encapsulatedKey == NULL || encapsulatedKeyLen == NULL) {return CRYPT_NULL_INPUT;}if ((info == NULL && infoLen != 0) || (info != NULL && infoLen == 0)) {return CRYPT_INVALID_ARG;}uint32_t encLen = g_hpkeKemAlgInfo[ctx->kemIndex].encapsulatedKeyLen;if (pkRLen != encLen) {return CRYPT_INVALID_ARG;}if (*encapsulatedKeyLen < encLen) {return CRYPT_INVALID_ARG;}return HpkeCheckAuthInfo(ctx);
}int32_t CRYPT_EAL_HpkeSetupSender(CRYPT_EAL_HpkeCtx *ctx, CRYPT_EAL_PkeyCtx *pkey, uint8_t *info, uint32_t infoLen,uint8_t *pkR, uint32_t pkRLen, uint8_t *encapKey, uint32_t *encapKeyLen)
{int32_t ret = HpkeCheckSenderParams(ctx, info, infoLen, pkR, pkRLen, encapKey, encapKeyLen);if (ret != CRYPT_SUCCESS) {BSL_ERR_PUSH_ERROR(ret);return ret;}uint32_t sharedSecretLen = g_hpkeKemAlgInfo[ctx->kemIndex].sharedKeyLen;uint8_t *sharedSecret = BSL_SAL_Malloc(sharedSecretLen);if (sharedSecret == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);return CRYPT_MEM_ALLOC_FAIL;}ret = HpkeEncap(ctx, pkey, pkR, pkRLen, encapKey, encapKeyLen, sharedSecret, sharedSecretLen);if (ret != CRYPT_SUCCESS) {BSL_SAL_ClearFree(sharedSecret, sharedSecretLen);return ret;}ret = HpkeKeySchedule(ctx, sharedSecret, sharedSecretLen, info, infoLen);if (ret != CRYPT_SUCCESS) {BSL_SAL_ClearFree(sharedSecret, sharedSecretLen);return ret;}ctx->sharedSecret = sharedSecret;ctx->sharedSecretLen = sharedSecretLen;HpkeFreeAuthInfo(ctx); // Derived key successfully, no longer requires authinforeturn ret;
}static int32_t HpkeAeadEncrypt(CRYPT_EAL_HpkeCtx *ctx, const uint8_t *nonce, uint32_t nonceLen, uint8_t *aad,uint32_t aadLen, const uint8_t *plainText, uint32_t plainTextLen, uint8_t *cipherText, uint32_t *cipherTextLen)
{CRYPT_EAL_CipherCtx *cipherCtx = ctx->cipherCtx;uint32_t outLen = *cipherTextLen;int32_t ret = CRYPT_EAL_CipherInit(cipherCtx, ctx->symKey, ctx->symKeyLen, nonce, nonceLen, true);if (ret != CRYPT_SUCCESS) {goto EXIT;}if (aad != NULL && aadLen > 0) {ret = CRYPT_EAL_CipherCtrl(cipherCtx, CRYPT_CTRL_SET_AAD, aad, aadLen);if (ret != CRYPT_SUCCESS) {goto EXIT;}}ret = CRYPT_EAL_CipherUpdate(cipherCtx, plainText, plainTextLen, cipherText, &outLen);if (ret != CRYPT_SUCCESS) {goto EXIT;}ret = CRYPT_EAL_CipherCtrl(cipherCtx, CRYPT_CTRL_GET_TAG, cipherText + outLen, HPKE_AEAD_TAG_LEN);if (ret != CRYPT_SUCCESS) {goto EXIT;}*cipherTextLen = outLen + HPKE_AEAD_TAG_LEN;
EXIT:CRYPT_EAL_CipherDeinit(cipherCtx);return ret;
}int32_t CRYPT_EAL_HpkeSetSeq(CRYPT_EAL_HpkeCtx *ctx, uint64_t seq)
{if (ctx == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);return CRYPT_NULL_INPUT;}if (seq == UINT64_MAX) {BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);return CRYPT_INVALID_ARG;}ctx->seq = seq;return CRYPT_SUCCESS;
}int32_t CRYPT_EAL_HpkeGetSeq(CRYPT_EAL_HpkeCtx *ctx, uint64_t *seq)
{if (ctx == NULL || seq == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);return CRYPT_NULL_INPUT;}*seq = ctx->seq;return CRYPT_SUCCESS;
}static void HpkeComputeNonce(CRYPT_EAL_HpkeCtx *ctx, uint8_t *nonce, uint32_t nonceLen)
{uint64_t seq = ctx->seq;for (uint32_t i = 0; i < sizeof(seq); i++) {nonce[nonceLen - i - 1] = seq & UINT8_MAX;seq = seq >> 8; // 8 bits}for (uint32_t i = 0; i < nonceLen; i++) {nonce[i] ^= ctx->baseNonce[i];}
}static int32_t HpkeCheckSealParams(CRYPT_EAL_HpkeCtx *ctx, const uint8_t *plainText, uint32_t plainTextLen,uint32_t *cipherTextLen)
{if (ctx == NULL) {return CRYPT_NULL_INPUT;}if (ctx->role != CRYPT_HPKE_SENDER) {return CRYPT_HPKE_ERR_CALL;}if (g_hpkeAeadAlgInfo[ctx->aeadIndex].hpkeAeadId == CRYPT_AEAD_EXPORT_ONLY) {return CRYPT_HPKE_ERR_CALL;}if (ctx->symKey == NULL || ctx->baseNonce == NULL) {return CRYPT_HPKE_ERR_CALL;}if (plainText == NULL || plainTextLen == 0 || cipherTextLen == NULL) {return CRYPT_NULL_INPUT;}if (plainTextLen > (UINT32_MAX - HPKE_AEAD_TAG_LEN)) {return CRYPT_INVALID_ARG;}return CRYPT_SUCCESS;
}int32_t CRYPT_EAL_HpkeSeal(CRYPT_EAL_HpkeCtx *ctx, uint8_t *aad, uint32_t aadLen, const uint8_t *plainText,uint32_t plainTextLen, uint8_t *cipherText, uint32_t *cipherTextLen)
{int32_t ret = HpkeCheckSealParams(ctx, plainText, plainTextLen, cipherTextLen);if (ret != CRYPT_SUCCESS) {BSL_ERR_PUSH_ERROR(ret);return ret;}if (ctx->seq + 1 == 0) {BSL_ERR_PUSH_ERROR(CRYPT_HPKE_ERR_CALL);return CRYPT_HPKE_ERR_CALL;}if (cipherText == NULL) {*cipherTextLen = plainTextLen + HPKE_AEAD_TAG_LEN;return CRYPT_SUCCESS;}if (*cipherTextLen < (plainTextLen + HPKE_AEAD_TAG_LEN)) {BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);return CRYPT_INVALID_ARG;}uint8_t nonce[HPKE_AEAD_NONCE_LEN] = { 0 };HpkeComputeNonce(ctx, nonce, HPKE_AEAD_NONCE_LEN);ret = HpkeAeadEncrypt(ctx, nonce, HPKE_AEAD_NONCE_LEN, aad, aadLen, plainText, plainTextLen, cipherText,cipherTextLen);if (ret == CRYPT_SUCCESS) {ctx->seq++;}return ret;
}static int32_t HpkeDecap(CRYPT_EAL_HpkeCtx *ctx, CRYPT_EAL_PkeyCtx *pkey, uint8_t *encKey, uint32_t encKeyLen,uint8_t *sharedSecret, uint32_t sharedSecretLen)
{CRYPT_EAL_PkeyCtx *pkeyS = NULL;int32_t ret = HpkeCreatePubKey(ctx->kemIndex, encKey, encKeyLen, &pkeyS, ctx->libCtx, ctx->attrName);if (ret != CRYPT_SUCCESS) {return ret;}uint8_t *kemContext = NULL;uint32_t kemContextLen;uint8_t pubKeyData[HPKE_KEM_MAX_PUBLIC_KEY_LEN];uint32_t pubKeyDataLen = HPKE_KEM_MAX_PUBLIC_KEY_LEN;CRYPT_EAL_PkeyCtx *authKey = NULL;if (ctx->mode == CRYPT_HPKE_MODE_AUTH || ctx->mode == CRYPT_HPKE_MODE_AUTH_PSK) {authKey = ctx->authInfo->authPkey;}ret = GetPubKeyData(pkey, pubKeyData, &pubKeyDataLen);if (ret != CRYPT_SUCCESS) {goto EXIT;}ret = HpkeCreateKemContext(encKey, encKeyLen, pubKeyData, pubKeyDataLen, authKey, &kemContext, &kemContextLen);if (ret != CRYPT_SUCCESS) {goto EXIT;}ret = HpkeComputeSharedSecret(ctx, pkey, pkeyS, authKey, kemContext, kemContextLen, sharedSecret, sharedSecretLen);EXIT:CRYPT_EAL_PkeyFreeCtx(pkeyS);BSL_SAL_FREE(kemContext);return ret;
}static int32_t HpkeCheckRecipientParams(CRYPT_EAL_HpkeCtx *ctx, CRYPT_EAL_PkeyCtx *pkey, uint8_t *info,uint32_t infoLen, const uint8_t *encapsulatedKey, uint32_t encapsulatedKeyLen)
{if (ctx == NULL) {return CRYPT_NULL_INPUT;}if (ctx->role != CRYPT_HPKE_RECIPIENT) {return CRYPT_HPKE_ERR_CALL;}if (ctx->sharedSecret != NULL) {return CRYPT_HPKE_ERR_CALL;}if ((info == NULL && infoLen != 0) || (info != NULL && infoLen == 0)) {return CRYPT_INVALID_ARG;}if (pkey == NULL || encapsulatedKey == NULL) {return CRYPT_NULL_INPUT;}if (encapsulatedKeyLen != g_hpkeKemAlgInfo[ctx->kemIndex].encapsulatedKeyLen) {return CRYPT_INVALID_ARG;}return HpkeCheckAuthInfo(ctx);
}int32_t CRYPT_EAL_HpkeSetupRecipient(CRYPT_EAL_HpkeCtx *ctx, CRYPT_EAL_PkeyCtx *pkey, uint8_t *info, uint32_t infoLen,uint8_t *encapKey, uint32_t encapKeyLen)
{int32_t ret = HpkeCheckRecipientParams(ctx, pkey, info, infoLen, encapKey, encapKeyLen);if (ret != CRYPT_SUCCESS) {BSL_ERR_PUSH_ERROR(ret);return ret;}uint32_t sharedSecretLen = g_hpkeKemAlgInfo[ctx->kemIndex].sharedKeyLen;uint8_t *sharedSecret = BSL_SAL_Malloc(sharedSecretLen);if (sharedSecret == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);return CRYPT_MEM_ALLOC_FAIL;}ret = HpkeDecap(ctx, pkey, encapKey, encapKeyLen, sharedSecret, sharedSecretLen);if (ret != CRYPT_SUCCESS) {BSL_SAL_ClearFree(sharedSecret, sharedSecretLen);return ret;}ret = HpkeKeySchedule(ctx, sharedSecret, sharedSecretLen, info, infoLen);if (ret != CRYPT_SUCCESS) {BSL_SAL_ClearFree(sharedSecret, sharedSecretLen);return ret;}ctx->sharedSecret = sharedSecret;ctx->sharedSecretLen = sharedSecretLen;HpkeFreeAuthInfo(ctx); // Derived key successfully, no longer requires authinforeturn ret;
}static int32_t HpkeAeadDecrypt(CRYPT_EAL_HpkeCtx *ctx, const uint8_t *nonce, uint32_t nonceLen, uint8_t *aad,uint32_t aadLen, const uint8_t *cipherText, uint32_t cipherTextLen, uint8_t *plainText, uint32_t *plainTextLen)
{CRYPT_EAL_CipherCtx *cipherCtx = ctx->cipherCtx;int32_t ret = CRYPT_EAL_CipherInit(cipherCtx, ctx->symKey, ctx->symKeyLen, nonce, nonceLen, false);if (ret != CRYPT_SUCCESS) {CRYPT_EAL_CipherDeinit(cipherCtx);return ret;}if (aad != NULL && aadLen > 0) {ret = CRYPT_EAL_CipherCtrl(cipherCtx, CRYPT_CTRL_SET_AAD, (void *)aad, aadLen);if (ret != CRYPT_SUCCESS) {CRYPT_EAL_CipherDeinit(cipherCtx);return ret;}}ret = CRYPT_EAL_CipherUpdate(cipherCtx, cipherText, cipherTextLen - HPKE_AEAD_TAG_LEN, plainText, plainTextLen);if (ret != CRYPT_SUCCESS) {CRYPT_EAL_CipherDeinit(cipherCtx);return ret;}uint8_t tag[HPKE_AEAD_TAG_LEN];ret = CRYPT_EAL_CipherCtrl(cipherCtx, CRYPT_CTRL_GET_TAG, (void *)tag, HPKE_AEAD_TAG_LEN);if (ret != CRYPT_SUCCESS) {goto EXIT;}if (memcmp(tag, cipherText + (cipherTextLen - HPKE_AEAD_TAG_LEN), HPKE_AEAD_TAG_LEN) != 0) {ret = CRYPT_HPKE_ERR_AEAD_TAG;BSL_ERR_PUSH_ERROR(CRYPT_HPKE_ERR_AEAD_TAG);}EXIT:if (ret != CRYPT_SUCCESS) {BSL_SAL_CleanseData(plainText, *plainTextLen);}CRYPT_EAL_CipherDeinit(cipherCtx);return ret;
}static int32_t HpkeCheckOpenParams(CRYPT_EAL_HpkeCtx *ctx, const uint8_t *cipherText, uint32_t cipherTextLen,uint32_t *plainTextLen)
{if (ctx == NULL) {return CRYPT_NULL_INPUT;}if (ctx->role != CRYPT_HPKE_RECIPIENT) {return CRYPT_HPKE_ERR_CALL;}if (g_hpkeAeadAlgInfo[ctx->aeadIndex].hpkeAeadId == CRYPT_AEAD_EXPORT_ONLY) {return CRYPT_HPKE_ERR_CALL;}if (ctx->symKey == NULL || ctx->baseNonce == NULL) {return CRYPT_HPKE_ERR_CALL;}if (cipherText == NULL || cipherTextLen == 0 || plainTextLen == NULL) {return CRYPT_NULL_INPUT;}return CRYPT_SUCCESS;
}int32_t CRYPT_EAL_HpkeOpen(CRYPT_EAL_HpkeCtx *ctx, uint8_t *aad, uint32_t aadLen, const uint8_t *cipherText,uint32_t cipherTextLen, uint8_t *plainText, uint32_t *plainTextLen)
{int32_t ret = HpkeCheckOpenParams(ctx, cipherText, cipherTextLen, plainTextLen);if (ret != CRYPT_SUCCESS) {BSL_ERR_PUSH_ERROR(ret);return ret;}if (ctx->seq + 1 == 0) {BSL_ERR_PUSH_ERROR(CRYPT_HPKE_ERR_CALL);return CRYPT_HPKE_ERR_CALL;}if (cipherTextLen <= HPKE_AEAD_TAG_LEN) {BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);return CRYPT_INVALID_ARG;}if (plainText == NULL) {*plainTextLen = cipherTextLen - HPKE_AEAD_TAG_LEN;return CRYPT_SUCCESS;}uint8_t nonce[HPKE_AEAD_NONCE_LEN] = { 0 };HpkeComputeNonce(ctx, nonce, HPKE_AEAD_NONCE_LEN);ret = HpkeAeadDecrypt(ctx, nonce, HPKE_AEAD_NONCE_LEN, aad, aadLen, cipherText, cipherTextLen, plainText,plainTextLen);if (ret == CRYPT_SUCCESS) {ctx->seq++;}return ret;
}void CRYPT_EAL_HpkeFreeCtx(CRYPT_EAL_HpkeCtx *ctx)
{if (ctx == NULL) {return;}BSL_SAL_ClearFree(ctx->sharedSecret, ctx->sharedSecretLen);HpkeFreeKeyInfo(ctx);CRYPT_EAL_CipherFreeCtx(ctx->cipherCtx);CRYPT_EAL_KdfFreeCtx(ctx->kdfCtx);BSL_SAL_FREE(ctx->attrName);HpkeFreeAuthInfo(ctx);BSL_SAL_ClearFree(ctx, sizeof(CRYPT_EAL_HpkeCtx));
}static int32_t HpkeGetEccOrder(CRYPT_EAL_PkeyCtx *pkey, BN_BigNum **order)
{uint8_t ecP[MAX_ECC_PARAM_LEN];uint8_t ecA[MAX_ECC_PARAM_LEN];uint8_t ecB[MAX_ECC_PARAM_LEN];uint8_t ecN[MAX_ECC_PARAM_LEN];uint8_t ecH[MAX_ECC_PARAM_LEN];uint8_t ecX[MAX_ECC_PARAM_LEN];uint8_t ecY[MAX_ECC_PARAM_LEN];CRYPT_EAL_PkeyPara para = {0};para.id = CRYPT_EAL_PkeyGetId(pkey);para.para.eccPara.p = ecP;para.para.eccPara.a = ecA;para.para.eccPara.b = ecB;para.para.eccPara.n = ecN;para.para.eccPara.h = ecH;para.para.eccPara.x = ecX;para.para.eccPara.y = ecY;para.para.eccPara.pLen = MAX_ECC_PARAM_LEN;para.para.eccPara.aLen = MAX_ECC_PARAM_LEN;para.para.eccPara.bLen = MAX_ECC_PARAM_LEN;para.para.eccPara.nLen = MAX_ECC_PARAM_LEN;para.para.eccPara.hLen = MAX_ECC_PARAM_LEN;para.para.eccPara.xLen = MAX_ECC_PARAM_LEN;para.para.eccPara.yLen = MAX_ECC_PARAM_LEN;int32_t ret = CRYPT_EAL_PkeyGetPara(pkey, &para);if (ret != CRYPT_SUCCESS) {return ret;}BN_BigNum *bn = BN_Create(para.para.eccPara.nLen * 8);if (bn == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);return CRYPT_MEM_ALLOC_FAIL;}ret = BN_Bin2Bn(bn, para.para.eccPara.n, para.para.eccPara.nLen);if (ret != CRYPT_SUCCESS) {BN_Destroy(bn);return ret;}*order = bn;return CRYPT_SUCCESS;
}static int32_t HpkeExpandEccPriKey(CRYPT_EAL_PkeyCtx *pkey, CRYPT_EAL_KdfCTX *hkdfCtx, uint32_t kemIndex,HPKE_LabeledExpandParams *params, uint8_t *sk, uint32_t skLen)
{BN_BigNum *order = NULL;int32_t ret = HpkeGetEccOrder(pkey, &order);if (ret != CRYPT_SUCCESS) {return ret;}BN_BigNum *skBn = BN_Create(skLen * 8);if (skBn == NULL) {BN_Destroy(order);BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);return CRYPT_MEM_ALLOC_FAIL;}uint8_t counter = 0;uint8_t bitmask = 0xFF; // 0xFF for P256 P384if (g_hpkeKemAlgInfo[kemIndex].hpkeKemId == CRYPT_KEM_DHKEM_P521_HKDF_SHA512) {bitmask = 0x01;}do {if (counter == 255) { // RFC9180 7.1.3, up to 255 attempts.ret = CRYPT_HPKE_ERR_GEN_ASYM_KEY;BSL_ERR_PUSH_ERROR(CRYPT_HPKE_ERR_GEN_ASYM_KEY);break;}*(params->info) = counter;ret = HpkeLabeledExpand(hkdfCtx, params, sk, skLen);if (ret != CRYPT_SUCCESS) {break;}sk[0] = sk[0] & bitmask;ret = BN_Bin2Bn(skBn, sk, skLen);if (ret != CRYPT_SUCCESS) {break;}counter++;} while (BN_IsZero(skBn) || BN_Cmp(skBn, order) >= 0);BN_Destroy(skBn);BN_Destroy(order);if (ret != CRYPT_SUCCESS) {BSL_SAL_CleanseData(sk, skLen);}return ret;
}static int32_t DeriveSk(uint8_t kemIndex, CRYPT_EAL_KdfCTX *kdfCtx, CRYPT_EAL_PkeyCtx *pkey,HPKE_LabeledExpandParams *expandParams, uint8_t *sk, uint32_t skLen)
{if (g_hpkeKemAlgInfo[kemIndex].hpkeKemId == CRYPT_KEM_DHKEM_X25519_HKDF_SHA256) {return HpkeLabeledExpand(kdfCtx, expandParams, sk, skLen);} else {uint8_t counter = 0;expandParams->label = (uint8_t *)"candidate";expandParams->labelLen = strlen("candidate");expandParams->info = (uint8_t *)&counter;expandParams->infoLen = sizeof(uint8_t);return HpkeExpandEccPriKey(pkey, kdfCtx, kemIndex, expandParams, sk, skLen);}
}static int32_t HpkeDeriveKeyPair(uint8_t kemIndex, uint8_t *ikm, uint32_t ikmLen,CRYPT_EAL_PkeyCtx **pctx, CRYPT_EAL_LibCtx *libCtx, const char *attrName)
{uint8_t suiteId[HPKE_KEM_SUITEID_LEN];HpkeGenerateKemSuiteId(kemIndex, suiteId, HPKE_KEM_SUITEID_LEN);uint8_t dkpPrk[HPKE_HKDF_MAX_EXTRACT_KEY_LEN];uint8_t sk[HPKE_KEM_MAX_PRIVATE_KEY_LEN] = { 0 };uint32_t dkpPrkLen = g_hpkeKemAlgInfo[kemIndex].hkdfExtractKeyLen;CRYPT_MAC_AlgId macId = g_hpkeKemAlgInfo[kemIndex].macId;uint32_t skLen = g_hpkeKemAlgInfo[kemIndex].privateKeyLen;CRYPT_EAL_KdfCTX *kdfCtx = NULL;kdfCtx = CRYPT_EAL_ProviderKdfNewCtx(libCtx, CRYPT_KDF_HKDF, attrName);if (kdfCtx == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_HPKE_FAILED_FETCH_KDF);return CRYPT_HPKE_FAILED_FETCH_KDF;}CRYPT_EAL_PkeyCtx *pkey = NULL;int32_t ret = HpkeCreatePkeyCtx(kemIndex, &pkey, libCtx, attrName);if (ret != CRYPT_SUCCESS) {CRYPT_EAL_KdfFreeCtx(kdfCtx);return ret;}HPKE_LabeledExtractParams extractParams = {macId, (uint8_t *)"", 0, (uint8_t *)"dkp_prk", strlen("dkp_prk"),ikm, ikmLen, suiteId, HPKE_KEM_SUITEID_LEN};HPKE_LabeledExpandParams expandParams = {macId, dkpPrk, dkpPrkLen, (uint8_t *)"sk", strlen("sk"), (uint8_t *)"", 0,suiteId, HPKE_KEM_SUITEID_LEN};ret = HpkeLabeledExtract(kdfCtx, &extractParams, dkpPrk, dkpPrkLen);if (ret != CRYPT_SUCCESS) {goto EXIT;}ret = DeriveSk(kemIndex, kdfCtx, pkey, &expandParams, sk, skLen);if (ret != CRYPT_SUCCESS) {goto EXIT;}ret = HpkeCreatePriKey(kemIndex, sk, skLen, &pkey, libCtx, attrName);EXIT:CRYPT_EAL_KdfFreeCtx(kdfCtx);BSL_SAL_CleanseData(sk, skLen);BSL_SAL_CleanseData(dkpPrk, HPKE_HKDF_MAX_EXTRACT_KEY_LEN);if (ret != CRYPT_SUCCESS) {CRYPT_EAL_PkeyFreeCtx(pkey);return ret;}*pctx = pkey;return CRYPT_SUCCESS;
}int32_t CRYPT_EAL_HpkeGenerateKeyPair(CRYPT_EAL_LibCtx *libCtx, const char *attrName,CRYPT_HPKE_CipherSuite cipherSuite, uint8_t *ikm, uint32_t ikmLen, CRYPT_EAL_PkeyCtx **pctx)
{if (pctx == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);return CRYPT_NULL_INPUT;}if (*pctx != NULL) {BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);return CRYPT_INVALID_ARG;}uint8_t kemIndex;int32_t ret = HpkeCheckCipherSuite(&cipherSuite, &kemIndex, NULL, NULL);if (ret != CRYPT_SUCCESS) {return ret;}uint32_t ikmNewLen = g_hpkeKemAlgInfo[kemIndex].privateKeyLen;if (ikm != NULL && ikmLen != 0) {if (ikmLen < ikmNewLen) {BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);return CRYPT_INVALID_ARG;}return HpkeDeriveKeyPair(kemIndex, ikm, ikmLen, pctx, libCtx, attrName);}uint8_t ikmNew[HPKE_KEM_MAX_PRIVATE_KEY_LEN];ret = CRYPT_EAL_RandbytesEx(libCtx, ikmNew, ikmNewLen);if (ret != CRYPT_SUCCESS) {return ret;}ret = HpkeDeriveKeyPair(kemIndex, ikmNew, ikmNewLen, pctx, libCtx, attrName);BSL_SAL_CleanseData(ikmNew, ikmNewLen);return ret;
}int32_t CRYPT_EAL_HpkeExportSecret(CRYPT_EAL_HpkeCtx *ctx, uint8_t *info, uint32_t infoLen, uint8_t *key,uint32_t keyLen)
{if (ctx == NULL || key == NULL || keyLen == 0) {BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);return CRYPT_NULL_INPUT;}if (ctx->exporterSecret == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_HPKE_ERR_CALL);return CRYPT_HPKE_ERR_CALL;}if ((info == NULL && infoLen != 0) || (info != NULL && infoLen == 0)) {BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);return CRYPT_INVALID_ARG;}if (keyLen > 255 * g_hpkeKdfAlgInfo[ctx->kdfIndex].hkdfExtractKeyLen) { // RFC9180 5.3 max L is 255*NhBSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);return CRYPT_INVALID_ARG;}uint8_t suiteId[HPKE_HPKE_SUITEID_LEN];HpkeGenerateHpkeSuiteId(ctx->kemIndex, ctx->kdfIndex, ctx->aeadIndex, suiteId, HPKE_HPKE_SUITEID_LEN);CRYPT_MAC_AlgId macId = g_hpkeKdfAlgInfo[ctx->kdfIndex].macId;HPKE_LabeledExpandParams params = {macId, ctx->exporterSecret, ctx->exporterSecretLen, (uint8_t *)"sec",strlen("sec"), info, infoLen, suiteId, HPKE_HPKE_SUITEID_LEN};return HpkeLabeledExpand(ctx->kdfCtx, &params, key, keyLen);
}int32_t CRYPT_EAL_HpkeGetSharedSecret(CRYPT_EAL_HpkeCtx *ctx, uint8_t *buff, uint32_t *buffLen)
{if (ctx == NULL || buffLen == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);return CRYPT_NULL_INPUT;}if (ctx->sharedSecret == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_HPKE_ERR_CALL);return CRYPT_HPKE_ERR_CALL;}if (buff == NULL) {*buffLen = ctx->sharedSecretLen;return CRYPT_SUCCESS;}if (*buffLen < ctx->sharedSecretLen) {BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);return CRYPT_INVALID_ARG;}(void)memcpy_s(buff, *buffLen, ctx->sharedSecret, ctx->sharedSecretLen);*buffLen = ctx->sharedSecretLen;return CRYPT_SUCCESS;
}int32_t CRYPT_EAL_HpkeSetSharedSecret(CRYPT_EAL_HpkeCtx *ctx, uint8_t *info, uint32_t infoLen,uint8_t *buff, uint32_t buffLen)
{if (ctx == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);return CRYPT_NULL_INPUT;}if (ctx->sharedSecret != NULL) {BSL_ERR_PUSH_ERROR(CRYPT_HPKE_ERR_CALL);return CRYPT_HPKE_ERR_CALL;}if (buff == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);return CRYPT_NULL_INPUT;}if ((info == NULL && infoLen != 0) || (info != NULL && infoLen == 0)) {BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);return CRYPT_INVALID_ARG;}if (buffLen != g_hpkeKemAlgInfo[ctx->kemIndex].sharedKeyLen) {BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);return CRYPT_INVALID_ARG;}if (ctx->mode == CRYPT_HPKE_MODE_PSK || ctx->mode == CRYPT_HPKE_MODE_AUTH_PSK) {if (ctx->authInfo == NULL || ctx->authInfo->psk == NULL || ctx->authInfo->pskId == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_HPKE_ERR_CALL);return CRYPT_HPKE_ERR_CALL;}}int32_t ret = HpkeKeySchedule(ctx, buff, buffLen, info, infoLen);if (ret != CRYPT_SUCCESS) {return ret;}ctx->sharedSecret = BSL_SAL_Dump(buff, buffLen);if (ctx->sharedSecret == NULL) {HpkeFreeKeyInfo(ctx);BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);return CRYPT_MEM_ALLOC_FAIL;}ctx->sharedSecretLen = buffLen;HpkeFreeAuthInfo(ctx); // Derived key successfully, no longer requires authinforeturn CRYPT_SUCCESS;
}int32_t CRYPT_EAL_HpkeSetPsk(CRYPT_EAL_HpkeCtx *ctx, uint8_t *psk, uint32_t pskLen, uint8_t *pskId, uint32_t pskIdLen)
{if (ctx == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);return CRYPT_NULL_INPUT;}if (ctx->mode != CRYPT_HPKE_MODE_PSK && ctx->mode != CRYPT_HPKE_MODE_AUTH_PSK) {BSL_ERR_PUSH_ERROR(CRYPT_HPKE_ERR_CALL);return CRYPT_HPKE_ERR_CALL;}if (ctx->authInfo == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_HPKE_ERR_CALL);return CRYPT_HPKE_ERR_CALL;}if (ctx->authInfo->psk != NULL || ctx->authInfo->pskId != NULL) {BSL_ERR_PUSH_ERROR(CRYPT_HPKE_ERR_CALL);return CRYPT_HPKE_ERR_CALL;}// psk and pskId must appear togetherif (psk == NULL || pskIdLen == 0 || pskId == NULL || pskLen == 0) {BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);return CRYPT_NULL_INPUT;}ctx->authInfo->psk = BSL_SAL_Dump(psk, pskLen);if (ctx->authInfo->psk == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);return CRYPT_MEM_ALLOC_FAIL;}ctx->authInfo->pskLen = pskLen;ctx->authInfo->pskId = BSL_SAL_Dump(pskId, pskIdLen);if (ctx->authInfo->pskId == NULL) {BSL_SAL_ClearFree(ctx->authInfo->psk, ctx->authInfo->pskLen);ctx->authInfo->psk = NULL;ctx->authInfo->pskLen = 0;BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);return CRYPT_MEM_ALLOC_FAIL;}ctx->authInfo->pskIdLen = pskIdLen;return CRYPT_SUCCESS;
}int32_t CRYPT_EAL_HpkeSetAuthPriKey(CRYPT_EAL_HpkeCtx *ctx, CRYPT_EAL_PkeyCtx *pkey)
{if (ctx == NULL || pkey == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);return CRYPT_NULL_INPUT;}if (ctx->mode != CRYPT_HPKE_MODE_AUTH && ctx->mode != CRYPT_HPKE_MODE_AUTH_PSK) {BSL_ERR_PUSH_ERROR(CRYPT_HPKE_ERR_CALL);return CRYPT_HPKE_ERR_CALL;}if (ctx->role != CRYPT_HPKE_SENDER) {BSL_ERR_PUSH_ERROR(CRYPT_HPKE_ERR_CALL);return CRYPT_HPKE_ERR_CALL;}if (ctx->authInfo == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_HPKE_ERR_CALL);return CRYPT_HPKE_ERR_CALL;}if (ctx->authInfo->authPkey != NULL) {BSL_ERR_PUSH_ERROR(CRYPT_HPKE_ERR_CALL);return CRYPT_HPKE_ERR_CALL;}CRYPT_EAL_PkeyCtx *skS = NULL;
#ifdef HITLS_CRYPTO_PROVIDERskS = CRYPT_EAL_ProviderPkeyNewCtx(ctx->libCtx, g_hpkeKemAlgInfo[ctx->kemIndex].pkeyId,CRYPT_EAL_PKEY_EXCH_OPERATE, ctx->attrName);
#elseskS = CRYPT_EAL_PkeyNewCtx(g_hpkeKemAlgInfo[ctx->kemIndex].pkeyId);
#endifif (skS == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_HPKE_FAILED_FETCH_PKEY);return CRYPT_HPKE_FAILED_FETCH_PKEY;}int32_t ret = CRYPT_EAL_PkeyCopyCtx(skS, pkey);if (ret != CRYPT_SUCCESS) {CRYPT_EAL_PkeyFreeCtx(skS);return ret;}ctx->authInfo->authPkey = skS;return CRYPT_SUCCESS;
}int32_t CRYPT_EAL_HpkeSetAuthPubKey(CRYPT_EAL_HpkeCtx *ctx, uint8_t *pub, uint32_t pubLen)
{if (ctx == NULL || pub == NULL || pubLen == 0) {BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);return CRYPT_NULL_INPUT;}if (ctx->mode != CRYPT_HPKE_MODE_AUTH && ctx->mode != CRYPT_HPKE_MODE_AUTH_PSK) {BSL_ERR_PUSH_ERROR(CRYPT_HPKE_ERR_CALL);return CRYPT_HPKE_ERR_CALL;}if (ctx->role != CRYPT_HPKE_RECIPIENT) {BSL_ERR_PUSH_ERROR(CRYPT_HPKE_ERR_CALL);return CRYPT_HPKE_ERR_CALL;}if (ctx->authInfo == NULL) {BSL_ERR_PUSH_ERROR(CRYPT_HPKE_ERR_CALL);return CRYPT_HPKE_ERR_CALL;}if (ctx->authInfo->authPkey != NULL) {BSL_ERR_PUSH_ERROR(CRYPT_HPKE_ERR_CALL);return CRYPT_HPKE_ERR_CALL;}CRYPT_EAL_PkeyCtx *pkS = NULL;int32_t ret = HpkeCreatePubKey(ctx->kemIndex, pub, pubLen, &pkS, ctx->libCtx, ctx->attrName);if (ret != CRYPT_SUCCESS) {return ret;}ctx->authInfo->authPkey = pkS;return CRYPT_SUCCESS;
}
#endif // HITLS_CRYPTO_HPKE

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/94356.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/94356.shtml
英文地址,請注明出處:http://en.pswp.cn/web/94356.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【鏈表 - LeetCode】206. 反轉鏈表【帶ACM調試】

206. 反轉鏈表 - 力扣&#xff08;LeetCode&#xff09; 題解 迭代版本 一共三個指針&#xff0c;一個是記錄最開始的節點&#xff0c;一個是當前反轉節點&#xff0c;一個是下一個待反轉的節點。 記住這里是反轉&#xff0c;所以&#xff0c;針對節點來看&#xff0c;將當…

langgraph快速搭建agent后端和react前端

官方文檔 一、后端 1.安裝基礎依賴 pip install --upgrade "langgraph-cli[inmem]"2.下載模版項目 在終端運行 langgraph new ./example --template new-langgraph-project-python這里是在當前文件夾下新建文件夾example&#xff0c;里面是下載的langgraph模版項…

第2章:幽靈協議初現

林薇的手指剛觸碰量子控制臺的“時間錨點”按鈕&#xff0c;Elysium的拓撲圖突然炸開一片猩紅。0.000001秒的延遲后&#xff0c;屏幕中央浮現出一個10KB的幽靈協議塊——它不占任何經典內存&#xff0c;卻在量子態中“呼吸”。“它在……重寫協議。”林薇的BCI接口傳來低沉的嗡…

Unity其他--【MMD】如何在Unity中制作MMD

小菲搖之前學習了在Unity中使用動畫狀態機控制人物&#xff0c;以及用Shader去對氛圍圖形進行渲染&#xff0c;然后又刷到一些MMD的視頻&#xff0c;我就想著MMD能做的事情感覺Unity應該也都能做而且更方便的吧&#xff0c;所以就嘗試做了一下。當然這里主要是記錄一下自己是怎…

從技術精英到“芯”途末路:一位工程師的沉淪與救贖

作者&#xff1a;邱戈龍、曾建萍【長昊律所】 專注于商業秘密、軟件著作權的專業型律師事務所&#xff0c;擅長民事、行政、刑事多重救濟途徑&#xff0c;為眾多科學技術領域的商業秘密、軟件著作權類案件提供侵權維權、辯護、司法鑒定、司法審計、調查取證等高品質專項法律服務…

刷題日記0824

兩眼一睜就是刷&#xff01;今日計劃5道3/5昨天遇到了幾件令人心情不好的小事&#xff0c;今天還要處理一下。一早上的好心情被小小的破壞了一下。1056. 易混淆數 簡單有思路&#xff0c;心情好。耶比耶比&#xff0c;算是一遍過&#xff0c;這次考慮很周。寫完了有一種一遍過的…

Qt c++開發中的delete QThread操作需注意

1、析構函數中&#xff0c;不能執行QEventLoop&#xff0c;會造成 重入問題&#xff1a;事件循環可能觸發其他事件&#xff0c;導致已析構的對象被再次訪問信號槽連接&#xff1a;正在析構的對象可能還有未斷開的信號槽連接未定義行為&#xff1a;對象狀態不確定&#xff0c;可…

Seaborn數據可視化實戰:Seaborn圖表定制與數據可視化入門

高級圖表定制 學習目標 通過本課程你將掌握如何使用Seaborn庫進行高級圖表定制&#xff0c;包括圖表的標題、圖例、注釋的添加&#xff0c;以及圖表布局和大小的調整。這些技能將幫助你更有效地展示數據&#xff0c;使你的數據故事更加生動和有說服力。 相關知識點 Seaborn高級…

nano命令使用方法

nano 是 Ubuntu 等 Linux 系統中常用的輕量級文本編輯器&#xff0c;輕量易用&#xff0c;特別適合適合快速編輯配置文件、腳本等。以下是其核心使用方法&#xff1a;一、基本操作&#xff1a;打開 / 創建文件bash# 打開已存在文件&#xff08;若文件不存在則創建&#xff09; …

C#_gRPC

6.3 gRPC&#xff1a;高性能跨語言服務間通信 gRPC是一個高性能、開源、通用的RPC&#xff08;Remote Procedure Call&#xff09;框架&#xff0c;由Google開發并基于其多年的內部使用經驗&#xff08;Stubby&#xff09;。它現在是Cloud Native Computing Foundation&#xf…

Ubuntu 多版本 librealsense 與 realsense_ros 編譯并兼容 L515 等設備

這篇博客用來記錄如何在 Ubuntu 下編譯多個版本的 librealsense 并使用 L515 和 D435i 等設備。核心在于 L515 這款設備已經停止維護&#xff0c;直接安裝的方案不支持這個設備&#xff0c;只支持 D435i 等后期產品。如果想要同時使用新老的 realsense 產品&#xff0c;需要單獨…

Java 泛型 T、E、K、V、?、S、U、V

目錄 一、概述 二、為什么使用泛型 三、常見泛型類型參數的含義與用途 示例一&#xff1a;使用 T 定義泛型類 示例二&#xff1a;使用 E 表示集合元素 示例三&#xff1a;使用 K 和 V 表示鍵值對 示例四&#xff1a;使用 ? 通配符處理未知類型 四、通配符 ? 的擴展用…

1688拍立淘接口數據全面解析詳細說明(item_search_img)

一、接口概述 1688拍立淘接口是阿里巴巴1688平臺提供的基于圖像識別的商品搜索服務&#xff0c;允許開發者通過上傳商品圖片來搜索平臺上的同款或相似商品。該接口的主要功能是接收用戶上傳的圖片&#xff08;或圖片的相關信息&#xff09;&#xff0c;并通過1688平臺的圖像識…

【Docker項目實戰】使用Docker部署輕量級LetsMarkdown文本編輯器

【Docker項目實戰】使用Docker部署輕量級Markdown文本編輯器一、LetsMarkdown介紹1.1 LetsMarkdown簡介1.2 主要特點二、本次實踐介紹2.1 本地環境規劃2.2 本次實踐介紹三、本地環境檢查3.1 檢查Docker服務狀態3.2 檢查Docker版本3.3檢查docker compose 版本四、拉取容器鏡像五…

Node.js自研ORM框架深度解析與實踐

Node.js自研ORM框架深度解析與實踐 前言 在現代Web開發中&#xff0c;對象關系映射&#xff08;ORM&#xff09;框架扮演著至關重要的角色。它們為開發者提供了一層抽象&#xff0c;使得數據庫操作變得更加簡單和直觀。本文將深入解析一個基于Node.js和MySQL的自研ORM框架&…

匯總圖片拖進ps中 photoshop同時打開幾個文件夾

如果你有許多文件夾&#xff0c;你想選中一部分&#xff0c;然后把里面的圖片全部拖進photoshop當中&#xff0c;但是文件夾又不能直接拖進去&#xff0c;那么你可以嘗試使用一下這個工具&#xff0c;首先測試一下直接拖文件夾。選中你要處理的文件夾&#xff0c;直接拖進photo…

mysql 5.7 查詢運行時間較長的sql

開發過程遇到sql 執行時間長&#xff0c;又取消不了的情況 可使用 kill query ID 殺死進程獲取正在運行的sqlSELECT ID, -- 進程ID&#xff1a;MySQL服務器分配給每個連接的唯一標識符&#xff0c;用于區分不同的客戶端連接USER, …

MongoDB 從入門到實踐:全面掌握文檔型 NoSQL 數據庫核心操作

目錄 一、MongoDB 基礎準備 1. 官方資源獲取 2. 安裝步驟解析 二、MongoDB 核心指令詳解 1. 數據庫操作指令 2. 集合操作指令 3. 文檔操作指令 查詢文檔 插入文檔 修改文檔 刪除文檔 三、進階查詢技巧 1. 運算符的靈活運用 比較運算符 邏輯運算符 范圍與成員運算…

CVPR2025丨遙感領域,全模態與秒超高清遙感建模重大突破,性能提升創新點

關注gongzhonghao【CVPR頂會精選】剛入門遙感建模時&#xff0c;總好奇別人為什么總能提出新方法&#xff1f;慢慢摸索后才發現&#xff0c;創新點并不是硬憋出來的&#xff0c;而是要從數據特性、傳感器差異、地物細節以及環境變化中發現機會。不同波段、不同分辨率、不同時相…

HTML5詳篇

前端三劍客 前端三劍客是指HTML、CSS和JavaScript: HTML超文本標記語言(Hyper Text Markup Language):簡單理解描述網頁結構的;用于網頁內容的語言。它通過使用不同的HTML標簽來定義頁面中的各種元素,例如標題、段落、圖像、鏈接等【無羽毛的小鳥模型】 CSS層疊樣式表(…