天天看點

鴻蒙源碼分析(三十四)本篇主要分析hks_mbedtls_ecc.c代碼

本篇主要分析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;
}

           

感謝閱讀和點贊,下一篇簡單介紹ecc算法。

繼續閱讀