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