本篇主要分析hks_mbedtls_ecc.c代碼
主要是ecc算法在鴻蒙系統中的代碼實作,以及相關知識點注意事項
檔案路徑(security_huks\frameworks\huks_standard\main\crypto_engine\mbedtls\src\hks_mbedtls_ecc.c)
一、背景知識
ecc算法介紹傳送門
二、代碼分析
密鑰size檢查函數
#define HKS_ECC_KEYPAIR_CNT 3
//檢查密鑰size是否為256和384
static int32_t HksMbedtlsEccCheckKeySize(const uint32_t keySize)
{
if ((keySize != HKS_ECC_KEY_SIZE_256) && (keySize != HKS_ECC_KEY_SIZE_384)) {
HKS_LOG_E("Invalid ecc keySize! keySize = 0x%X", keySize);
return HKS_ERROR_INVALID_KEY_SIZE;
}
return HKS_SUCCESS;
}
曲線群id的擷取
該函數通過傳入的keylen,得到不通的grpid。
參數介紹
- keylen:存放密鑰長度
- groid:存放最後的id資訊
//擷取曲線群的id資訊
int32_t GetEccGroupId(const uint32_t keyLen, mbedtls_ecp_group_id *grpId)
{
switch (keyLen) {
//通過不同的keylen就可以判斷出曲線的不同分支
case HKS_ECC_KEY_SIZE_256:
*grpId = MBEDTLS_ECP_DP_SECP256R1;
//256長度的對應MBEDTLS_ECP_DP_SECP256R1
break;
case HKS_ECC_KEY_SIZE_384:
*grpId = MBEDTLS_ECP_DP_SECP384R1;
//384長度的對應MBEDTLS_ECP_DP_SECP384R1
break;
default:
HKS_LOG_E("Unsupported key length! keyLen: 0x%X", keyLen);
return HKS_ERROR_INVALID_KEY_SIZE;
}
return HKS_SUCCESS;
}
檢查密鑰材料三個次元的size資訊
static int32_t EccKeyMaterialXyzSizeCheck(const struct KeyMaterialEcc *keyMaterial)
{
const uint32_t maxKeyByteLen = HKS_ECC_KEY_SIZE_384 / HKS_BITS_PER_BYTE; //計算密鑰最大位數
//計算位數方式密鑰最大長度除以每位對應的位元組數
if ((keyMaterial->xSize > maxKeyByteLen) ||
(keyMaterial->ySize > maxKeyByteLen) || (keyMaterial->zSize > maxKeyByteLen)) {
HKS_LOG_E("Invalid ecc keyMaterial! xSize = 0x%X, ySize = 0x%X, zSize = 0x%X",
keyMaterial->xSize, keyMaterial->ySize, keyMaterial->zSize);
return HKS_ERROR_INVALID_ARGUMENT;
}
//密鑰材料的三個次元xyz隻要有一個的長度大于計算得到的maxKeyByteLen,函數就傳回錯誤值
return HKS_SUCCESS;
}
根據密鑰材料資訊來計算密鑰資訊并實作參數的檢查
//檢查ecc密鑰
int32_t EccKeyCheck(const struct HksBlob *key)
{
const struct KeyMaterialEcc *keyMaterial = (struct KeyMaterialEcc *)(key->data);
int32_t ret = HksMbedtlsEccCheckKeySize(keyMaterial->keySize);
//先檢查keyMaterial->keySize的大小
if (ret != HKS_SUCCESS) {
return ret;
}
ret = EccKeyMaterialXyzSizeCheck(keyMaterial);
//檢查密鑰材料三個次元的大小
if (ret != HKS_SUCCESS) {
return ret;
}
if (key->size < (sizeof(struct KeyMaterialEcc) + keyMaterial->xSize + keyMaterial->ySize + keyMaterial->zSize)) {
HKS_LOG_E("Ecc key size too small! key size = 0x%X", key->size);
return HKS_ERROR_INVALID_KEY_INFO;
}
//檢查key->size大小,如果小于密鑰材料的三個次元的size大小之和就傳回錯誤值
return HKS_SUCCESS;
}
擷取密鑰的曲線nist資訊
//擷取密鑰曲線nist
int32_t HksMbedtlsEccGetKeyCurveNist(const struct KeyMaterialEcc *keyMaterial, mbedtls_ecp_group_id *curve)
{
if ((keyMaterial->keyAlg != HKS_ALG_ECC) && (keyMaterial->keyAlg != HKS_ALG_ECDH)) {
HKS_LOG_E("Invalid param key! key mode = 0x%X", keyMaterial->keyAlg);
return HKS_ERROR_INVALID_ARGUMENT;
}
//檢查算法是否是ecc或者ecdh當中過的一個
return GetEccGroupId(keyMaterial->keySize, curve);
//将曲線群的id寫進curve
}
公鑰轉換
//将ecc密鑰材料轉換為公鑰
int32_t HksEccKeyMaterialToPub(const struct HksBlob *key, mbedtls_ecp_point *pub)
{
const struct KeyMaterialEcc *keyMaterial = (struct KeyMaterialEcc *)(key->data);
uint32_t offset = sizeof(*keyMaterial);//定義偏置
int32_t ret = mbedtls_mpi_read_binary(&(pub->X), key->data + offset, keyMaterial->xSize);
//從二進制讀取資訊,寫進pub->X
if (ret != HKS_MBEDTLS_SUCCESS) {
HKS_LOG_E("Ecc keyMaterial to public key read X failed! mbedtls ret = 0x%X", ret);
return ret;
}
offset = offset + keyMaterial->xSize;
//更新偏置資訊
ret = mbedtls_mpi_read_binary(&(pub->Y), key->data + offset, keyMaterial->ySize);
//将材料中y次元的資料讀進公鑰的Y部分
if (ret != HKS_MBEDTLS_SUCCESS) {
HKS_LOG_E("Ecc keyMaterial to public key read Y failed! mbedtls ret = 0x%X", ret);
return ret;
}
/* Z = 1, X and Y are its standard (affine) coordinates */
ret = mbedtls_mpi_lset(&(pub->Z), 1);
//初始化公鑰的Z次元為1
if (ret != HKS_MBEDTLS_SUCCESS) {
HKS_LOG_E("Ecc keyMaterial to public key set Z failed! mbedtls ret = 0x%X", ret);
return ret;
}
return HKS_SUCCESS;
}
私鑰轉換
//将密鑰材料轉換為私鑰
int32_t HksEccKeyMaterialToPri(const struct HksBlob *key, mbedtls_mpi *pri)
{
const struct KeyMaterialEcc *keyMaterial = (struct KeyMaterialEcc *)(key->data);
uint32_t offset = sizeof(*keyMaterial) + keyMaterial->xSize + keyMaterial->ySize;
//定義偏置offset為x次元和y次元長度加keyMaterial所占長度
int32_t ret = mbedtls_mpi_read_binary(pri, key->data + offset, keyMaterial->zSize);
//将結果寫進pri私鑰
if (ret != HKS_MBEDTLS_SUCCESS) {
HKS_LOG_E("Ecc keyMaterial to private key read Z failed! mbedtls ret = 0x%X", ret);
return ret;
}
return HKS_SUCCESS;
}
#endif /* HKS_SUPPORT_ECDH_C or HKS_SUPPORT_ECDSA_C */
密鑰參數的儲存
#ifdef HKS_SUPPORT_ECC_GENERATE_KEY
static int32_t EccSaveKeyMaterial(const mbedtls_ecp_keypair *ecp,
const uint32_t keySize, struct HksBlob *key)
{
/* public exponent x and y, and private exponent, so need size is: key_size / 8 * 3 */
//x和y為公共參數
const uint32_t keyByteLen = keySize / HKS_BITS_PER_BYTE;
//計算密鑰位元組數
const uint32_t rawMaterialLen = sizeof(struct KeyMaterialEcc) + keyByteLen * HKS_ECC_KEYPAIR_CNT;
//定義長度用來申請記憶體
uint8_t *rawMaterial = (uint8_t *)HksMalloc(rawMaterialLen);
//申請記憶體空間,大小rawMaterialLen
if (rawMaterial == NULL) {
return HKS_ERROR_MALLOC_FAIL;
}
(void)memset_s(rawMaterial, rawMaterialLen, 0, rawMaterialLen);
//初始化剛剛申請的空間
/* ECC key data internel struct: struct KeyMaterialEcc + pubXData + pubYData + priData */
struct KeyMaterialEcc *keyMaterial = (struct KeyMaterialEcc *)rawMaterial;
keyMaterial->keyAlg = HKS_ALG_ECC;
keyMaterial->keySize = keySize;
keyMaterial->xSize = keyByteLen;
keyMaterial->ySize = keyByteLen;
keyMaterial->zSize = keyByteLen;
//對keyMaterial的各個屬性進行指派
int32_t ret;
do {
uint32_t offset = sizeof(struct KeyMaterialEcc);
//定義偏置變量
ret = mbedtls_mpi_write_binary(&(ecp->Q.X), rawMaterial + offset, keyMaterial->xSize);
//從rawMaterial以指定偏置和長度讀取資訊進ecp->Q.X
if (ret != HKS_MBEDTLS_SUCCESS) {
HKS_LOG_E("Save ecc keyMaterial write X failed! mbedtls ret = 0x%X", ret);
break;
}
offset = offset + keyMaterial->xSize;
//更新偏置
ret = mbedtls_mpi_write_binary(&(ecp->Q.Y), rawMaterial + offset, keyMaterial->ySize);
//從rawMaterial以指定偏置和長度讀取資訊進ecp->Q.Y
if (ret != HKS_MBEDTLS_SUCCESS) {
HKS_LOG_E("Save ecc keyMaterial write Y failed! mbedtls ret = 0x%X", ret);
break;
}
offset = offset + keyMaterial->ySize;
//更新偏置
ret = mbedtls_mpi_write_binary(&(ecp->d), rawMaterial + offset, keyMaterial->zSize);
//從rawMaterial以指定偏置和長度讀取資訊進ecp->Q.Z
if (ret != HKS_MBEDTLS_SUCCESS) {
HKS_LOG_E("Save ecc keyMaterial write D failed! mbedtls ret = 0x%X", ret);
break;
}
key->data = rawMaterial;
key->size = rawMaterialLen;
//最後将最終結果寫進key中
} while (0);
if (ret != HKS_MBEDTLS_SUCCESS) {
(void)memset_s(rawMaterial, rawMaterialLen, 0, rawMaterialLen);
HKS_FREE_PTR(rawMaterial);
}
return ret;
}
生成ecc中的密鑰
//生成ecc密鑰
int32_t HksMbedtlsEccGenerateKey(const struct HksKeySpec *spec, struct HksBlob *key)
{
mbedtls_ecp_group_id grpId;//定義曲線群
int32_t ret = GetEccGroupId(spec->keyLen, &grpId);
//擷取算法對應曲線群id
if (ret != HKS_SUCCESS) {
return ret;
}
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctrDrbg;
ret = HksCtrDrbgSeed(&ctrDrbg, &entropy);
//僞随機數的生成
if (ret != HKS_SUCCESS) {
return ret;
}
mbedtls_ecp_keypair ecp;
mbedtls_ecp_keypair_init(&ecp);
//定義初始化一對密鑰(公鑰加私鑰)
do {
ret = mbedtls_ecp_gen_key(grpId, &ecp, mbedtls_ctr_drbg_random, &ctrDrbg);
//生成密鑰資訊,在ecp中
if (ret != HKS_MBEDTLS_SUCCESS) {
HKS_LOG_E("Mbedtls ecc generate key failed! ret = 0x%X", ret);
break;
}
ret = EccSaveKeyMaterial(&ecp, spec->keyLen, key);
//儲存密鑰資訊在ecp中
} while (0);
mbedtls_ctr_drbg_free(&ctrDrbg);
mbedtls_entropy_free(&entropy);
mbedtls_ecp_keypair_free(&ecp);
//釋放相關空間
return ret;
}
下面主要是參數的檢查的密鑰的擷取
//擷取公鑰并檢查參數(size)
static int32_t GetEccPubKeyCheckParams(const struct HksBlob *keyIn, const struct HksBlob *keyOut)
{
int32_t ret = EccKeyCheck(keyIn);
if (ret != HKS_SUCCESS) {
return ret;
}
/* check keyOut size */
const struct KeyMaterialEcc *keyMaterial = (struct KeyMaterialEcc *)(keyIn->data);
if (keyOut->size < (sizeof(struct KeyMaterialEcc) + keyMaterial->xSize + keyMaterial->ySize)) {
HKS_LOG_E("Ecc public keyOut size too small! keyOut size = 0x%X", keyOut->size);
return HKS_ERROR_BUFFER_TOO_SMALL;
}
//如果keyOut->size小于sizeof(struct KeyMaterialEcc)+xsize+ysize函數就傳回報錯
return HKS_SUCCESS;
}
//擷取公鑰資訊
int32_t HksMbedtlsGetEccPubKey(const struct HksBlob *keyIn, struct HksBlob *keyOut)
{
int32_t ret = GetEccPubKeyCheckParams(keyIn, keyOut);
//檢查keyin的參數
if (ret != HKS_SUCCESS) {
return ret;
}
/* x + y, so need size is: sizeof(struct HksPubKeyInfo) + xSize + ySize */
const struct KeyMaterialEcc *keyMaterial = (struct KeyMaterialEcc *)(keyIn->data);
uint32_t outLen = sizeof(struct KeyMaterialEcc) + keyMaterial->xSize + keyMaterial->ySize;
//定義outlen = sizeof(struct HksPubKeyInfo) + xSize + ySize
if (memcpy_s(keyOut->data, keyOut->size, (void *)keyMaterial, outLen) != EOK) {
//初始化keyOut->data中的内容為keyMaterial
HKS_LOG_E("Memcpy ecc public key fail!");
(void)memset_s(keyOut->data, keyOut->size, 0, keyOut->size);
return HKS_ERROR_BAD_STATE;
}
((struct KeyMaterialEcc *)(keyOut->data))->zSize = 0;
//将材料z次元初始化為全0
keyOut->size = outLen;
return HKS_SUCCESS;
}