Crypto Lab
首页
openHiTLS教程
技术分享
首页
openHiTLS教程
技术分享
  • openHiTLS教程

    • 一. 下载并构建OpenHiTLS
    • 二. 测试指南
    • 三. 在C/C++应用项目中调用openHiTLS
    • 四. 为openHiTLS社区做贡献

三. 在C/C++应用项目中调用openHiTLS

在本章节中将以对称加密和TLS两个示例演示如何在您的项目代码中调用openHiTLS提供的接口。

1. SM4加密实现示例

创建SM4_CBC.c,代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "crypt_eal_cipher.h" // 对称加解密接口头文件
#include "bsl_sal.h"
#include "bsl_err.h"
#include "crypt_algid.h" // 算法id列表
#include "crypt_errno.h" // 错误码列表

void *StdMalloc(uint32_t len) {
    return malloc((size_t)len);
}

void PrintLastError(void) {
    const char *file = NULL;
    uint32_t line = 0;
    BSL_ERR_GetLastErrorFileLine(&file, &line); // 获取错误发生的文件名和行数
    printf("failed at file %s at line %d\n", file, line);
}

int main(void)
{
    uint8_t data[10] = {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x1c, 0x14};
    uint8_t iv[16] = {0};
    uint8_t key[16] = {0};
    uint32_t dataLen = sizeof(data);
    uint8_t cipherText[100];
    uint8_t plainText[100];
    uint32_t outTotalLen = 0;
    uint32_t outLen = sizeof(cipherText);
    uint32_t cipherTextLen;
    int32_t ret;

    printf("plain text to be encrypted: "); // 输出明文
    for (uint32_t i = 0; i < dataLen; i++) {
        printf("%02x", data[i]);
    }
    printf("\n");

    // 初始化错误码模块
    BSL_ERR_Init();

    // BSL_SAL_CallBack_Ctrl
    // 如果未注册并且默认能力没有被裁剪,使用默认linux实现
    BSL_SAL_CallBack_Ctrl(BSL_SAL_MEM_MALLOC_CB_FUNC, StdMalloc);
    BSL_SAL_CallBack_Ctrl(BSL_SAL_MEM_FREE_CB_FUNC, free);

    // 创建上下文
    CRYPT_EAL_CipherCtx *ctx = CRYPT_EAL_CipherNewCtx(CRYPT_CIPHER_SM4_CBC);
    if (ctx == NULL) {
        PrintLastError();
        BSL_ERR_DeInit();
        return 1;
    }
    // 初始化, 最后入参true为加密,false为解密
    ret = CRYPT_EAL_CipherInit(ctx, key, sizeof(key), iv, sizeof(iv), true);
    if (ret != CRYPT_SUCCESS) {
        printf("error code is %x\n", ret); // 输出错误码,可借助错误码在crypt_errno.h中找到对应的错误信息
        PrintLastError();
        goto exit;
    }
    // 设置填充模式。
    ret = CRYPT_EAL_CipherSetPadding(ctx, CRYPT_PADDING_PKCS7);
    if (ret != CRYPT_SUCCESS) {
        printf("error code is %x\n", ret);
        PrintLastError();
        goto exit;
    }

    // 输入待计算数据,该接口可以调用多次。此处outLen输入为cipherText长度,输出为处理的数据量
    ret = CRYPT_EAL_CipherUpdate(ctx, data, dataLen, cipherText, &outLen);
    if (ret != CRYPT_SUCCESS) {
        printf("error code is %x\n", ret);
        PrintLastError();
        goto exit;
    }

    outTotalLen += outLen;                     // 目前已处理数据量
    outLen = sizeof(cipherText) - outTotalLen; // cipherText剩余空间

    // 填充并处理最后一段数据
    ret = CRYPT_EAL_CipherFinal(ctx, cipherText + outTotalLen, &outLen);
    if (ret != CRYPT_SUCCESS) {
        printf("error code is %x\n", ret);
        PrintLastError();
        goto exit;
    }

    outTotalLen += outLen;
    printf("cipher text value is: "); // 输出密文

    for (uint32_t i = 0; i < outTotalLen; i++) {
        printf("%02x", cipherText[i]);
    }
    printf("\n");

    // 开始解密流程
    cipherTextLen = outTotalLen;
    outTotalLen = 0;
    outLen = sizeof(plainText);

    // 初始化, 设置为解密
    ret = CRYPT_EAL_CipherInit(ctx, key, sizeof(key), iv, sizeof(iv), false);
    if (ret != CRYPT_SUCCESS) {
        printf("error code is %x\n", ret); // 输出错误码,可借助错误码在crypt_errno.h中找到对应的错误信息
        PrintLastError();
        goto exit;
    }

    // 设置填充模式,填充模式必须和加密的填充模式相同
    ret = CRYPT_EAL_CipherSetPadding(ctx, CRYPT_PADDING_PKCS7);
    if (ret != CRYPT_SUCCESS) {
        printf("error code is %x\n", ret);
        PrintLastError();
        goto exit;
    }

    // 输入密文数据
    ret = CRYPT_EAL_CipherUpdate(ctx, cipherText, cipherTextLen, plainText, &outLen);
    if (ret != CRYPT_SUCCESS) {
        printf("error code is %x\n", ret);
        PrintLastError();
        goto exit;
    }
    outTotalLen += outLen;                    // 目前已处理数据量
    outLen = sizeof(plainText) - outTotalLen; // buffer剩余空间

    // 解密最后一段数据并去填充
    ret = CRYPT_EAL_CipherFinal(ctx, plainText + outTotalLen, &outLen);
    if (ret != CRYPT_SUCCESS) {
        printf("error code is %x\n", ret);
        PrintLastError();
        goto exit;
    }

    outTotalLen += outLen;

    printf("decrypted plain text value is: "); // 输出明文
    for (uint32_t i = 0; i < outTotalLen; i++) {
        printf("%02x", plainText[i]);
    }
    printf("\n");

    if (outTotalLen != dataLen || memcmp(plainText, data, dataLen) != 0) {
        printf("plaintext comparison failed\n");
        goto exit;
    }
    printf("pass \n");

exit:
    // 释放上下文内存
    CRYPT_EAL_CipherFreeCtx(ctx);
    BSL_ERR_DeInit();
    return ret;
}


在同目录下创建Makefile文件,内容如下:

OPEN_PATH=openhitls
USER=lab-422
BUILD=build
LINK_FLAGS=-pthread -lhitls_tls -lhitls_pki -lhitls_crypto -lhitls_bsl -lboundscheck -lsctp
LIB=-L /home/$(USER)/$(OPEN_PATH)/$(BUILD) -Wl,-rpath,/home/$(USER)/$(OPEN_PATH)/$(BUILD) -Wl,-rpath,/usr/local/lib/
HEADER=-I/home/$(USER)/$(OPEN_PATH)/include/crypto -I/home/$(USER)/$(OPEN_PATH)/include/bsl -I/home/$(USER)/$(OPEN_PATH)/include/tls -I/home/$(USER)/$(OPEN_PATH)/include/pki -I/home/$(USER)/$(OPEN_PATH)/platform/Secure_C/include

all:sm4

sm4:
	gcc $(HEADER) SM4_CBC.c -g -o sm4cbc $(LINK_FLAGS) $(LIB)

clean:
	rm sm4cbc

注意把USER字段改成自己系统的用户名,确定头文件路径和链接库路径正确。 编译生成可执行文件sm4cbc并运行

make
./sm4cbc

示例运行成功

2. TLS实现示例

由于TLS需要同时运行server和client两个程序,而openEuler没有图形化操作界面操作不便,现介绍用PowerShell实现打开多个终端界面。 首先在openEuler系统中查看ip

ifconfig

可以看到ip地址为192.168.119.131

在windows中打开PowerShell,输入以下命令,然后输入密码

ssh lab-422@192.168.119.131

连接成功

接下来开始实现tls示例。 创建tlss.c和tlsc.c,代码如下,注意修改CERT_PATH的路径:

// 基于证书认证的TLS客户端
#include <stdio.h> 
#include <stdlib.h> 
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include "bsl_sal.h" 
#include "bsl_err.h" 
#include "hitls_error.h" 
#include "hitls_config.h" 
#include "hitls.h" 
// #include "hitls_x509.h"
#include "hitls_cert.h"
#include "hitls_cert_init.h"

#include "hitls_crypt_init.h"

#include "crypt_eal_rand.h"
#include "crypt_eal_encode.h"

#define HTTP_BUF_MAXLEN (18 * 1024)  /* 18KB */ 
#define CERT_PATH "/home/lab-422/openhitls/testcode/testdata/tls/certificate/der/rsa_sha256/"

int TCP_Connect(const char* ip, const char* port, struct sockaddr_in* sockAddr) {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket");
        return -1;
    }

    memset(sockAddr, 0, sizeof(struct sockaddr_in));
    sockAddr->sin_family = AF_INET;
    sockAddr->sin_port = htons(atoi(port));
    if (inet_pton(AF_INET, ip, &(sockAddr->sin_addr)) <= 0) {
        perror("inet_pton");
        close(sockfd);
        return -1;
    }

    if (connect(sockfd, (struct sockaddr*)sockAddr, sizeof(struct sockaddr_in)) == -1) {
        perror("connect");
        close(sockfd);
        return -1;
    }

    return sockfd;
}

void TCP_Close(int fd) {
    close(fd);
}

int main(int32_t argc, char *argv[]) 
{ 
    int32_t exitValue = -1; 
    int32_t ret = 0; 
    HITLS_Config *config = NULL; 
    HITLS_Ctx *ctx = NULL; 
    BSL_UIO *uio = NULL; 

    /* 注册BSL内存能力、仅供参考 */ 
    BSL_SAL_CallBack_Ctrl(BSL_SAL_MEM_MALLOC_CB_FUNC, malloc);
    BSL_SAL_CallBack_Ctrl(BSL_SAL_MEM_FREE_CB_FUNC, free);
    BSL_ERR_Init();

    HITLS_CertMethodInit();
    CRYPT_EAL_RandInit(CRYPT_RAND_SHA256, NULL, NULL, NULL, 0);
    HITLS_CryptMethodInit();

    /* TCP链接需用户实现能力 */
    struct sockaddr_in sockAddr; 
    int fd = TCP_Connect("127.0.0.1", "12345", &sockAddr); 
    if (fd < 0) { 
        printf("SCTP_Connect failed.\n"); 
        return -1; 
    } 

    config = HITLS_CFG_NewTLSConfig(); 
    if (config == NULL) { 
        printf("HITLS_CFG_NewTLS12Config failed.\n"); 
        return -1; 
    } 
    HITLS_CFG_SetCheckKeyUsage(config,false);
    HITLS_CFG_SetFlightTransmitSwitch(config,true);
    /* 加载证书:需要用户实现 */ 
    int r=0;
    HITLS_CERT_X509 *ca_cert = NULL;
    r = HITLS_X509_CertParseFile(TLS_PARSE_FORMAT_PEM,
                                CERT_PATH"ca.der",
                                &ca_cert);
    printf("ca parse r=0x%x\n", r);
    r = HITLS_CFG_AddCertToStore(config, ca_cert, TLS_CERT_STORE_TYPE_DEFAULT,
                                false);
    printf("add ca cert r=0x%x\n", r);

    HITLS_CERT_X509 *inter_cert = NULL;
    r = HITLS_X509_CertParseFile(TLS_PARSE_FORMAT_PEM,
                                CERT_PATH"inter.der",
                                &inter_cert);
    printf("inter parse r=0x%x\n", r);
    r = HITLS_CFG_AddCertToStore(config, inter_cert, TLS_CERT_STORE_TYPE_DEFAULT,
                                false);
    printf("add inter cert r=0x%x\n", r);
    // r=HITLS_CFG_LoadCertFile(config, "/home/ling/ca_server.crt", TLS_CERT_STORE_TYPE_DEFAULT);
    // printf("add encCert r=0x%x\n", r);
    /* 新建openHiTLS上下文 */ 
    ctx = HITLS_New(config); 
    if (ctx == NULL) { 
        printf("HITLS_New failed.\n"); 
        goto exit; 
    } 

    /* 用户可按需实现method */ 
    uio = BSL_UIO_New(BSL_UIO_TcpMethod()); 
    if (uio == NULL) { 
        printf("BSL_UIO_New failed.\n"); 
        goto exit; 
    } 

    ret = BSL_UIO_Ctrl(uio, BSL_UIO_SET_FD, (int32_t)sizeof(fd), &fd); 
    if (ret != HITLS_SUCCESS) { 
        BSL_UIO_Free(uio); 
        printf("BSL_UIO_SET_FD failed, fd = %u.\n", fd); 
        goto exit; 
    } 

    ret = HITLS_SetUio(ctx, uio); 
    if (ret != HITLS_SUCCESS) { 
        BSL_UIO_Free(uio); 
        printf("HITLS_SetUio failed. ret = 0x%x.\n", ret); 
        goto exit; 
    } 

    /* 进行TLS连接、用户需按实际场景考虑返回值 */ 
    ret = HITLS_Connect(ctx); 
    if (ret != HITLS_SUCCESS) { 
        printf("HITLS_Connect failed, ret = 0x%x.\n", ret); 
        goto exit; 
    } 

    /* 向对端发送报文、用户需按实际场景考虑返回值 */ 
    const uint8_t sndBuf[] = "Hi, this is client\n"; 
    ret = HITLS_Write(ctx, sndBuf, sizeof(sndBuf), &ret); 
    if (ret != HITLS_SUCCESS) { 
        printf("HITLS_Write error:error code:%d\n", ret); 
        goto exit; 
    } 

    /* 读取对端报文、用户需按实际场景考虑返回值 */ 
    uint8_t readBuf[HTTP_BUF_MAXLEN + 1] = {0}; 
    uint32_t readLen = 0; 
    ret = HITLS_Read(ctx, readBuf, HTTP_BUF_MAXLEN, &readLen); 
    if (ret != HITLS_SUCCESS) { 
        printf("HITLS_Read failed, ret = 0x%x.\n", ret); 
        goto exit; 
    } 

    printf("get from server size:%u :%s\n", readLen, readBuf); 

    exitValue = 0; 
exit: 
    HITLS_Close(ctx); 
    HITLS_Free(ctx); 
    HITLS_CFG_FreeConfig(config); 
    TCP_Close(fd); 
    return exitValue; 
}

//基于证书认证的TLS服务端
#define HITLS_CRYPTO_EAL
#define HITLS_CRYPTO_CIPHER
#include <stdio.h> 
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h> 
#include <arpa/inet.h>
#include "bsl_sal.h" 
#include "bsl_err.h" 
#include "hitls_error.h" 
#include "hitls_config.h" 
#include "hitls.h" 
// #include "hitls_x509.h"
#include "hitls_cert.h"
#include "hitls_cert_init.h"

#include "hitls_crypt_init.h"

#include "crypt_eal_rand.h"
#include "crypt_eal_encode.h"

#define HTTP_BUF_MAXLEN (18 * 1024)  /* 18KB */ 
#define CERT_PATH "/home/lab-422/openhitls/testcode/testdata/tls/certificate/der/rsa_sha256/"
int TCP_Bind(const char* port) {
    int sockfd;
    struct sockaddr_in serverAddr;

    // 创建套接字
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket creation failed");
        return -1;
    }

    // 设置服务器地址信息
    memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = INADDR_ANY;
    serverAddr.sin_port = htons(atoi(port));

    // 绑定套接字到指定端口
    if (bind(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1) {
        perror("bind failed");
        close(sockfd);
        return -1;
    }

    // 开始监听连接请求
    if (listen(sockfd, 10) == -1) {
        perror("listen failed");
        close(sockfd);
        return -1;
    }

    return sockfd;
}

int TCP_Accept(int listenFd, struct sockaddr_in* clientAddr) {
    int clientFd;
    socklen_t clientAddrLen;
    struct sockaddr_in addr;

    // 等待客户端连接请求
    clientAddrLen = sizeof(struct sockaddr_in);
    clientFd = accept(listenFd, (struct sockaddr*)&addr, &clientAddrLen);
    if (clientFd == -1) {
        perror("accept failed");
        return -1;
    }

    // 将客户端地址信息保存到clientAddr中
    memcpy(clientAddr, &addr, sizeof(struct sockaddr_in));

    return clientFd;
}

void TCP_Close(int fd) {
    close(fd);
}

int main(int32_t argc, char *argv[]) 
{ 
    int32_t exitValue = -1; 
    int32_t ret = 0; 
    HITLS_Config *config = NULL; 
    HITLS_Ctx *ctx = NULL; 
    BSL_UIO *uio = NULL; 

    /* 注册BSL内存能力、仅供参考 */ 
    BSL_SAL_CallBack_Ctrl(BSL_SAL_MEM_MALLOC_CB_FUNC, malloc);
    BSL_SAL_CallBack_Ctrl(BSL_SAL_MEM_FREE_CB_FUNC, free);
    BSL_ERR_Init();

    HITLS_CertMethodInit();
    CRYPT_EAL_RandInit(CRYPT_RAND_SHA256, NULL, NULL, NULL, 0);
    HITLS_CryptMethodInit();
    /* TCP链接需用户实现能力 */
    int listenFd = TCP_Bind("12345");  
    struct sockaddr_in sockAddr;  
    int fd = TCP_Accept(listenFd, &sockAddr);  
    if (fd < 0) {  
        printf("TCP_Accept failed.\n");  
        return -1;  
    }

    config = HITLS_CFG_NewTLSConfig(); 
    if (config == NULL) { 
        printf("HITLS_CFG_NewTLS12Config failed.\n"); 
        return -1; 
    } 
    HITLS_CFG_SetCheckKeyUsage(config,false);
    HITLS_CFG_SetFlightTransmitSwitch(config,true);
    /* 加载证书:需要用户实现 */ 
    int r=0;
    HITLS_CERT_X509 *ca_cert = NULL;
    r = HITLS_X509_CertParseFile(TLS_PARSE_FORMAT_PEM,
                                CERT_PATH"ca.der",
                                // "/home/ling/ca_server.crt"
                                &ca_cert);
    printf("ca parse r=0x%x\n", r);
    r = HITLS_CFG_AddCertToStore(config, ca_cert, TLS_CERT_STORE_TYPE_DEFAULT,
                                false);
    printf("add ca cert r=0x%x\n", r);

    HITLS_CERT_X509 *inter_cert = NULL;
    r = HITLS_X509_CertParseFile(TLS_PARSE_FORMAT_PEM,
                                CERT_PATH"inter.der",
                                &inter_cert);
    printf("inter parse r=0x%x\n", r);
    r = HITLS_CFG_AddCertToStore(config, inter_cert, TLS_CERT_STORE_TYPE_DEFAULT,
                                false);
    printf("add inter cert r=0x%x\n", r);

    // 从文件中加载加密证书和私钥    
    r=HITLS_CFG_LoadCertFile(config, CERT_PATH"server.der", TLS_PARSE_FORMAT_ASN1);
    printf("add encCert r=0x%x\n", r);
    r=HITLS_CFG_LoadKeyFile(config, CERT_PATH"server.key.der", TLS_PARSE_FORMAT_ASN1);
    printf("add encKey r=0x%x\n", r);
    
    /* 新建openHiTLS上下文 */ 
    ctx = HITLS_New(config); 
    if (ctx == NULL) { 
        printf("HITLS_New failed.\n"); 
        goto exit; 
    } 

    /* 用户可按需实现method */ 
    uio = BSL_UIO_New(BSL_UIO_TcpMethod()); 
    if (uio == NULL) { 
        printf("BSL_UIO_New failed.\n"); 
        goto exit; 
    } 

    ret = BSL_UIO_Ctrl(uio, BSL_UIO_SET_FD, (int32_t)sizeof(fd), &fd); 
    if (ret != HITLS_SUCCESS) { 
        BSL_UIO_Free(uio); 
        printf("BSL_UIO_SET_FD failed, fd = %u.\n", fd); 
        goto exit; 
    } 

    ret = HITLS_SetUio(ctx, uio); 
    if (ret != HITLS_SUCCESS) { 
        BSL_UIO_Free(uio); 
        printf("HITLS_SetUio failed. ret = 0x%x.\n", ret); 
        goto exit; 
    } 

    /* 进行TLS连接、用户需按实际场景考虑返回值 */ 
    ret = HITLS_Accept(ctx); 
    if (ret != HITLS_SUCCESS) { 
        printf("HITLS_Accept failed, ret = 0x%x.\n", ret); 
        goto exit; 
    } 

    /* 读取对端报文、用户需按实际场景考虑返回值 */ 
    uint8_t readBuf[HTTP_BUF_MAXLEN + 1] = {0}; 
    uint32_t readLen = 0; 
    ret = HITLS_Read(ctx, readBuf, HTTP_BUF_MAXLEN, &readLen); 
    if (ret != HITLS_SUCCESS) { 
        printf("HITLS_Read failed, ret = 0x%x.\n", ret); 
        goto exit; 
    } 
    printf("get from client size:%u :%s\n", readLen, readBuf); 

    /* 向对端发送报文、用户需按实际场景考虑返回值 */ 
    const uint8_t sndBuf[] = "Hi, this is server\n"; 
    ret = HITLS_Write(ctx, sndBuf, sizeof(sndBuf), &ret); 
    if (ret != HITLS_SUCCESS) { 
        printf("HITLS_Write error:error code:%d\n", ret); 
        goto exit; 
    }
    exitValue = 0; 
exit: 
    HITLS_Close(ctx); 
    HITLS_Free(ctx); 
    HITLS_CFG_FreeConfig(config); 
    TCP_Close(fd); 
    return exitValue; 
}

在同目录下创建Makefile文件,内容如下:

OPEN_PATH=openhitls
BUILD=build
USER=lab-422
LINK_FLAGS=-pthread -lhitls_tls -lhitls_pki -lhitls_crypto -lhitls_bsl -lboundscheck -lsctp
LIB=-L /home/$(USER)/$(OPEN_PATH)/$(BUILD) -Wl,-rpath,/home/$(USER)/$(OPEN_PATH)/$(BUILD) -Wl,-rpath,/usr/local/lib/
HEADER=-I/home/$(USER)/$(OPEN_PATH)/include/crypto -I/home/$(USER)/$(OPEN_PATH)/include/bsl -I/home/$(USER)/$(OPEN_PATH)/include/tls -I/home/$(USER)/$(OPEN_PATH)/include/pki -I/home/$(USER)/$(OPEN_PATH)/platform/Secure_C/include

all:tls

tls:
	gcc $(HEADER) tlss.c -g -o tlss $(LINK_FLAGS) $(LIB)
	gcc $(HEADER) tlsc.c -g -o tlsc $(LINK_FLAGS) $(LIB)

clean:
	rm tlss tlsc

输入make,并运行tls服务端

make
./tlss

启动一个新的PowerShell窗口,ssh连接到openEuler系统,运行tls服务端

./tlsc

可以看到两个窗口都有输出,示例运行成功

Last Updated:
Contributors: WXF334
Prev
二. 测试指南
Next
四. 为openHiTLS社区做贡献