天天看点

鸿蒙源码分析(三十四)本篇主要分析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算法。

继续阅读