security_huks/services/huks_service/core/hks_client_service_adapter解读

知识分享

这里简单总结一下代码中出现的openSSL的功能函数

  • i2d_PUBKEY:
  • d2i_PUBKEY:使用SubjectPublicKeyInfo格式对EVP_PKEY结构进行解码和编码
  • RSA_new:初始化内存分配
  • BN_bin2bn:字符串ASCII编码转二进制大端表示的数
  • RSA_set0_key:RSA密钥参数设置
  • EVP_PKEY_new:RSA密钥内存分配
  • EVP_PKEY_set1_RSA:RSA密钥生成
  • EC_KEY_new_by_curve_name:根据算法名调用对应椭圆曲线加密算法生成密钥参数
  • EC_KEY_set_public_key_affine_coordinates:设置基准坐标点
  • EC_KEY_set_conv_form:进行密钥参数格式的规范
  • EVP_PKEY_set1_EC_KEY:进行ECC密钥的生成
  • EVP_PKEY_get1_RSA:密钥的类型转换(EVP_PKEY->RSA)

总体概述

1.client_service_adapter.c模块是一个密钥生成和类型格式转换模块——对应adapter适配的意思

2.不同于lite轻量级的部署,这里使用了openSSL框架下的若干函数,对三种:RSA ECC CRUVE25519的密钥生成和转换均有互逆函数(即两种类型相互转换的函数)

代码解读

由于大部分功能在上一篇lite版本中介绍过这里仅仅简单提一下openSSL框架特有的一些函数的运用和功能实现

1.EvpKeyToX509Format

函数功能:跟lite功能基本一致,将EvpKey转换为X509标准下的密钥得到X509Key

函数实现:借助openSSL框架中的函数进行密钥的提取

d2i_PUBKEY()和i2d_PUBKEY()使用SubjectPublicKeyInfo格式对EVP_PKEY结构进行解码和编码

2.RsaToX509PublicKey

函数功能:封装一层内存分配和编码转换再调用EvpKeyToX509Format进行格式转换

函数实现:在第一个函数的基础上调用openSSL框架中的功能函数完成N和E的提取以及密钥内存的分配

整个过程大致如此:初始化内存分配---->对传入的参数进行解析提取---->密钥参数的设置---->密钥内存的分配---->密钥生成---->对生成的pKey转换为X509格式

#ifdef HKS_SUPPORT_RSA_C
//封装一层内存分配和编码转换再调用EvpKeyToX509Format进行格式转换
static int32_t RsaToX509PublicKey(const struct HksBlob *mod, const struct HksBlob *e, struct HksBlob *x509Key)
{
    RSA *rsa = NULL;
    BIGNUM *rsaN = NULL;
    BIGNUM *rsaE = NULL;
    EVP_PKEY *pkey = NULL;
    int32_t result;

    do {
        result = HKS_ERROR_CRYPTO_ENGINE_ERROR;
        //初始化内存分配
        rsa = RSA_new();
        if (rsa == NULL) {
            HKS_LOG_E("rsa is null");
            break;
        }
        //字符串ASCII编码转二进制大端表示的数
        rsaN = BN_bin2bn(mod->data, mod->size, NULL);
        rsaE = BN_bin2bn(e->data, e->size, NULL);
        if (rsaN == NULL || rsaE == NULL) {
            HKS_LOG_E("BN_bin2bn error %s", ERR_reason_error_string(ERR_get_error()));
            break;
        }
        //密钥参数设置
        if (RSA_set0_key(rsa, rsaN, rsaE, NULL) == 0) {
            HKS_LOG_E("RSA_set0_key error %s", ERR_reason_error_string(ERR_get_error()));
            break;
        }
        //密钥内存分配
        pkey = EVP_PKEY_new();
        if (pkey == NULL) {
            HKS_LOG_E("pkey is null");
            break;
        }
        //密钥生成
        if (EVP_PKEY_set1_RSA(pkey, rsa) == 0) {
            HKS_LOG_E("EVP_PKEY_set1_RSA error %s", ERR_reason_error_string(ERR_get_error()));
            break;
        }
        /* rsa need to be set to null to prevent Double-Free */
        rsa = NULL;
        //对生成的pkey进行转换
        result = EvpKeyToX509Format(pkey, x509Key);
    } while (0);

    //对临时指针空间的释放
    SELF_FREE_PTR(rsa, RSA_free);
    SELF_FREE_PTR(rsaN, BN_free);
    SELF_FREE_PTR(rsaE, BN_free);
    SELF_FREE_PTR(pkey, EVP_PKEY_free);
    return result;
}
#endif

3.GetEccNid

函数功能:通过keySize的匹配到对应的nid
在这里插入图片描述

4.EccToX509PublicKey

函数功能:调用openSSL框架中的ECC相关函数生成密钥并转换为X509格式

函数流程:首先调用GetEccNid获取nid---->然后根据nid选择对应的椭圆曲线加密算法生成密钥参数---->对参数所给的XY进行数据类型转换提取---->设置基准点坐标---->进行密钥参数格式的调整设置---->调用EVP_PKEY_set1_EC_KEY进行ECC密钥的生成---->使用SELF_FREE_PTR对中间变量进行释放

//调用openSSL框架中的ECC相关函数生成密钥并转换为X509格式
static int32_t EccToX509PublicKey(uint32_t keySize, const struct HksBlob *x, const struct HksBlob *y,
    struct HksBlob *x509Key)
{
    int32_t nid;
    //根据keySize获取nid
    int32_t ret = GetEccNid(keySize, &nid);
    if (ret != HKS_SUCCESS) {
        HKS_LOG_E("GetNidFromKeySize fail");
        return ret;
    }

    EC_KEY *ecKey = NULL;
    BIGNUM *ecX = NULL;
    BIGNUM *ecY = NULL;
    EVP_PKEY *pkey = NULL;
    ret = HKS_ERROR_CRYPTO_ENGINE_ERROR;
    do {
        //根据nid调用对应的椭圆曲线加密算法生成密钥参数
        ecKey = EC_KEY_new_by_curve_name(nid);
        if (ecKey == NULL) {
            HKS_LOG_E("EC_KEY_new_by_curve_name error %s", ERR_reason_error_string(ERR_get_error()));
            break;
        }
        //类型转换
        ecX = BN_bin2bn(x->data, x->size, NULL);
        ecY = BN_bin2bn(y->data, y->size, NULL);
        if (ecX == NULL || ecY == NULL) {
            HKS_LOG_E("x y point is null");
            break;
        }

        //设置基准坐标点
        if (EC_KEY_set_public_key_affine_coordinates(ecKey, ecX, ecY) == 0) {
            HKS_LOG_E("EC_KEY_set_public_key_affine_coordinates error %s", ERR_reason_error_string(ERR_get_error()));
            break;
        }

        //进行格式的设置
        EC_KEY_set_conv_form(ecKey, POINT_CONVERSION_UNCOMPRESSED);
        pkey = EVP_PKEY_new();
        if (pkey == NULL) {
            HKS_LOG_E("pkey is null");
            break;
        }

        //进行ECC密钥的生成
        if (EVP_PKEY_set1_EC_KEY(pkey, ecKey) == 0) {
            HKS_LOG_E("EVP_PKEY_set1_EC_KEY error %s", ERR_reason_error_string(ERR_get_error()));
            break;
        }

        /* ecKey need to be set to null to prevent Double-Free */
        ecKey = NULL;
        //转换为X509标准
        ret = EvpKeyToX509Format(pkey, x509Key);
    } while (0);

    SELF_FREE_PTR(ecKey, EC_KEY_free);
    SELF_FREE_PTR(ecX, BN_free);
    SELF_FREE_PTR(ecY, BN_free);
    SELF_FREE_PTR(pkey, EVP_PKEY_free);
    return ret;
}
#endif

5.Curve25519ToX509PublicKey

函数功能:curve25519密钥转换为X509格式

函数实现:通过简单的内存分配——>内存拷贝的方式进行格式的转换

6.TranslateToX509PublicKey

函数功能:将上述三种类型的算法进行一个封装:根据publicKeyInfo->keyAlg的内容选择不同的算法进行密钥的生成和转换(为X509格式)

//将上述三种类型的算法进行一个封装:根据publicKeyInfo->keyAlg的内容选择不同的算法进行密钥的生成和转换(为X509格式)
int32_t TranslateToX509PublicKey(const struct HksBlob *publicKey, struct HksBlob *x509Key)
{
    //一系列size和非空检查
    if ((publicKey == NULL) || (publicKey->data == NULL) || (publicKey->size == 0) || (x509Key == NULL)) {
        HKS_LOG_E("translate to x509 public key invalid args");
        return HKS_ERROR_INVALID_ARGUMENT;
    }

    if (publicKey->size < sizeof(struct HksPubKeyInfo)) {
        HKS_LOG_E("translate to x509 public key invalid publicKey size");
        return HKS_ERROR_INVALID_ARGUMENT;
    }

    struct HksPubKeyInfo *publicKeyInfo = (struct HksPubKeyInfo *)publicKey->data;
    uint32_t offset = sizeof(struct HksPubKeyInfo);
    if ((publicKey->size - offset) < publicKeyInfo->nOrXSize) {
        HKS_LOG_E("translate to x509 public key invalid nOrXSize size");
        return HKS_ERROR_INVALID_ARGUMENT;
    }

    struct HksBlob material1 = { publicKeyInfo->nOrXSize, publicKey->data + offset };
    offset += publicKeyInfo->nOrXSize;
    if ((publicKey->size - offset) < publicKeyInfo->eOrYSize) {
        HKS_LOG_E("translate to x509 public key invalid eOrYSize size");
        return HKS_ERROR_INVALID_ARGUMENT;
    }

    struct HksBlob material2 = { publicKeyInfo->eOrYSize, publicKey->data + offset };
    //三选一进行密钥的生成
    switch (publicKeyInfo->keyAlg) {
#ifdef HKS_SUPPORT_RSA_C
        case HKS_ALG_RSA:
            return RsaToX509PublicKey(&material1, &material2, x509Key);
#endif
#ifdef HKS_SUPPORT_ECC_C
        case HKS_ALG_ECC:
            return EccToX509PublicKey(publicKeyInfo->keySize, &material1, &material2, x509Key);
#endif
#if defined(HKS_SUPPORT_X25519_C) || defined(HKS_SUPPORT_ED25519_C)
        case HKS_ALG_X25519:
        case HKS_ALG_ED25519:
            return Curve25519ToX509PublicKey(&material1, x509Key);
#endif
        default:
            HKS_LOG_E("Unsupport alg type! type = 0x%X", publicKeyInfo->keyAlg);
            return HKS_ERROR_INVALID_ARGUMENT;
    }
}

7.X509PublicKeyToRsa

函数功能:从函数名显然可以知道——将EVP_PKEY(X509格式)转换为rsaPublicKey

#ifdef HKS_SUPPORT_RSA_C
static int32_t X509PublicKeyToRsa(EVP_PKEY *pkey, struct HksBlob *rsaPublicKey)
{
    //密钥的类型转换(EVP_PKEY->RSA)
    RSA *rsa = EVP_PKEY_get1_RSA(pkey);
    if (rsa == NULL) {
        HKS_LOG_E("EVP_PKEY_get1_RSA error %s", ERR_reason_error_string(ERR_get_error()));
        return HKS_ERROR_NULL_POINTER;
    }
    //获取N E参数的大小
    int32_t nSize = BN_num_bytes(RSA_get0_n(rsa));
    int32_t eSize = BN_num_bytes(RSA_get0_e(rsa));
    if (nSize <= 0 || eSize <= 0) {
        HKS_LOG_E("X509PublicKeyToRsa BN_num_bytes failed");
        return HKS_ERROR_INTERNAL_ERROR;
    }

    //不用考虑溢出,根据size进行空间分配
    /* n and e in RSA algorithm is small, will never overflow. */
    uint32_t totalSize = nSize + eSize + sizeof(struct  HksPubKeyInfo);
    uint8_t *keyBuffer = HksMalloc(totalSize);
    if (keyBuffer == NULL) {
        HKS_LOG_E("X509PublicKeyToRsa keyBuffer failed");
        return HKS_ERROR_MALLOC_FAIL;
    }

    //构建rsaPublicKey
    struct HksPubKeyInfo *pubKeyInfo = (struct HksPubKeyInfo *)keyBuffer;
    pubKeyInfo->keyAlg = HKS_ALG_RSA;
    pubKeyInfo->keySize = RSA_size(rsa);
    pubKeyInfo->nOrXSize = nSize;
    pubKeyInfo->eOrYSize = eSize;
    if (BN_bn2bin(RSA_get0_n(rsa), keyBuffer + sizeof(struct HksPubKeyInfo)) == 0 ||
        BN_bn2bin(RSA_get0_e(rsa), keyBuffer + sizeof(struct HksPubKeyInfo) + nSize) == 0) {
        HKS_LOG_E("BN_bn2bin error %s", ERR_reason_error_string(ERR_get_error()));
        HKS_FREE_PTR(keyBuffer);
        return HKS_ERROR_INTERNAL_ERROR;
    }

    rsaPublicKey->data = keyBuffer;
    rsaPublicKey->size = totalSize;
    return HKS_SUCCESS;
}
#endif

8.EcKeyToPublicKey

函数功能:将EC_KEY中的信息提取封装到eccPublicKey中

#ifdef HKS_SUPPORT_ECC_C
static int32_t EcKeyToPublicKey(EC_KEY *ecKey, struct HksBlob *eccPublicKey)
{
    //两个大数坐标
    BIGNUM *x = BN_new();
    BIGNUM *y = BN_new();
    int32_t ret;
    do {
        ret = HKS_ERROR_CRYPTO_ENGINE_ERROR;
        if (x == NULL || y == NULL) {
            HKS_LOG_E("X509PublicKeyToEcc BN_new failed");
            break;
        }
        //根据基准点获取XY
        if (EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ecKey),
            EC_KEY_get0_public_key(ecKey), x, y, NULL) == 0) {
            HKS_LOG_E("EC_POINT_get_affine_coordinates_GFp error %s", ERR_reason_error_string(ERR_get_error()));
            break;
        }

        //size获取
        int32_t xSize = BN_num_bytes(x);
        int32_t ySize = BN_num_bytes(y);
        if (xSize <= 0 || ySize <= 0) {
            HKS_LOG_E("X509PublicKeyToEcc get x or y size failed");
            break;
        }

        /* x and y in ECC algorithm is small, will never overflow. */
        uint32_t totalSize = xSize + ySize + sizeof(struct HksPubKeyInfo);
        uint8_t *keyBuffer = HksMalloc(totalSize);
        if (keyBuffer == NULL) {
            HKS_LOG_E("X509PublicKeyToRsa keyBuffer failed");
            break;
        }

        //构造eccPublicKey
        struct HksPubKeyInfo *pubKeyInfo = (struct HksPubKeyInfo *)keyBuffer;
        pubKeyInfo->keyAlg = HKS_ALG_ECC;
        pubKeyInfo->keySize = EC_GROUP_order_bits(EC_KEY_get0_group(ecKey));
        pubKeyInfo->nOrXSize = xSize;
        pubKeyInfo->eOrYSize = ySize;
        if (BN_bn2bin(x, keyBuffer + sizeof(struct HksPubKeyInfo)) == 0 ||
            BN_bn2bin(y, keyBuffer + sizeof(struct HksPubKeyInfo) + xSize) == 0) {
            HKS_LOG_E("BN_bn2bin error %s", ERR_reason_error_string(ERR_get_error()));
            HKS_FREE_PTR(keyBuffer);
            break;
        }

        ret = HKS_SUCCESS;
        eccPublicKey->data = keyBuffer;
        eccPublicKey->size = totalSize;
    } while (0);

    SELF_FREE_PTR(x, BN_free);
    SELF_FREE_PTR(y, BN_free);
    return ret;
}

9.TranslateFromX509PublicKey

函数功能:将上述三种类型的转换封装,从X509标准密钥转换为各个算法产出需要的密钥

//从X509标准密钥转换为各个算法产出需要的密钥
int32_t TranslateFromX509PublicKey(const struct HksBlob *x509Key, struct HksBlob *publicKey)
{
    if (x509Key == NULL || x509Key->data == NULL || x509Key->size == 0 || publicKey == NULL) {
        HKS_LOG_E("TranslateFromX509PublicKey invalid args");
        return HKS_ERROR_INVALID_ARGUMENT;
    }
    //解码x509Key
    EVP_PKEY *pkey = d2i_PUBKEY(NULL, (const unsigned char **)&x509Key->data, x509Key->size);
    if (pkey == NULL) {
        return HKS_ERROR_INVALID_ARGUMENT;
    }

    int32_t ret;
    //得到对应的算法alg
    int32_t keyType = EVP_PKEY_base_id(pkey);
    if (keyType == EVP_PKEY_RSA) {
#ifdef HKS_SUPPORT_RSA_C
        ret = X509PublicKeyToRsa(pkey, publicKey);
#else
        ret = HKS_ERROR_INVALID_ALGORITHM;
#endif
    } else if (keyType == EVP_PKEY_EC) {
#ifdef HKS_SUPPORT_ECC_C
        ret = X509PublicKeyToEcc(pkey, publicKey);
#else
        ret = HKS_ERROR_INVALID_ALGORITHM;
#endif
    } else {
        HKS_LOG_E("Unsupport alg type!");
        ret = HKS_ERROR_INVALID_ARGUMENT;
    }

    SELF_FREE_PTR(pkey, EVP_PKEY_free);
    return ret;
}

10. 两个格式转换函数

TranslateToInnerCurve25519Format
TranslateToInnerAesFormat

第一个将buffer和key中的信息整合封装到publicKey中得到curve25519需要的格式

第二个将key进行一层封装得到outKey——AES需要的格式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

国家一级假勤奋研究牲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值