国密SSL协议之C语言编程

国密SSL协议之C语言编程

背景

OpenSSL支持标准的SSL协议,但并不支持国密SSL协议。本文描述了C语言使用国密版OpenSSL开发一个简单的客户端程序,连接国密Web网站,发送HTTP请求,并接收HTTP应答。

环境
Centos7 X64。
国密OpenSSL。下载参https://www.gmssl.cn/gmssl/index.jsp?go=gmsdk
将国密OpenSSL 展开为/usr/local/gmssl_10
源码
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/gm.h>

#define MAXBUF 4096

int main(int argc, char *argv[])
{
    struct sockaddr_in serveraddr;
    struct hostent *host;
    int sockfd, len;
    SSL *ssl = NULL;
    int bi = 0;

    if (argc < 4) {
        printf("./%s addr port uri sig.pem sig.key enc.pem enc.key\n", argv[0]);
        printf("optional: sig.pem sig.key enc.pem enc.key\n");
        exit(1);
    }

    if (argc == 8)
    {
        bi = 1;
    }

    char *addr = argv[1];
    int port = atoi(argv[2]);
    char *uri = argv[3];
    char *sigCrt = argv[4];
    char *sigKey = argv[5];
    char *encCrt = argv[6];
    char *encKey = argv[7];

    // 国密SSL初始化
    GM_load_library();

    // 国密SSL生成SSL_CTX
    const SSL_METHOD *method = GMv1_1_client_method();
    SSL_CTX *ctx = SSL_CTX_new(method);
    if (!ctx)
    {
        printf("create ctx is failed.\n");
        exit(1);
    }
    // load gm sign keypair
    if(bi)
    {
            if (SSL_CTX_use_certificate_chain_file(ctx, sigCrt) <= 0)
            {
                printf("unable to get certificate from '%s'\n",sigCrt);
                //ERR_print_errors(bio_err);
                exit(1);
            }
            if (SSL_CTX_use_PrivateKey_file(ctx, sigKey, SSL_FILETYPE_PEM) <= 0)
            {
                printf("unable to get private key from '%s'\n",sigKey);
                //ERR_print_errors(bio_err);
                exit(1);
            }
    }
    // load gm enc keypair
    if(bi)
    {
            if (SSL_CTX_use_encrypt_cert_file(ctx, encCrt) <= 0)
            {
                printf("unable to get certificate(enc) from '%s'\n",encCrt);
                //ERR_print_errors(bio_err);
                exit(1);
            }
            if (SSL_CTX_use_encrypt_PrivateKey_file(ctx, encKey, SSL_FILETYPE_PEM) <= 0)
            {
                printf("unable to get private key(enc) from '%s'\n",encKey);
                //ERR_print_errors(bio_err);
                exit(1);
            }
    }

    if((host = gethostbyname(addr))==0)
    {
        printf("Error resolving host %s\n", addr);
        exit(1);
    }

    char *ip = inet_ntoa(*(struct in_addr*)host->h_addr_list[0]);
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    bzero(&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    inet_pton(AF_INET, ip, &serveraddr.sin_addr.s_addr);
    serveraddr.sin_port  = htons(port);
    int ok = connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
    if(ok != 0)
    {
        printf("connnect failed\n");
        exit(0);
    }

    ssl = SSL_new(ctx);
    if (ssl == NULL) {
        printf("SSL_new error.\n");
        exit(0);
    }
    SSL_set_fd(ssl, sockfd);
    if (SSL_connect(ssl) == -1) {
        printf("SSL_connect fail.\n");
        ERR_print_errors_fp(stderr);
        exit(1);
    }
    else 
    {
        printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
    }

    // send http request
    {
        char request[1024] = { 0 };
        sprintf(request, "GET %s HTTP/1.1\r\nAccept: */*\r\nUser-Agent: Mozilla/5.0\r\nHost: %s:%s\r\nConnection: close\r\n\r\n", argv[3], argv[1], argv[2]);
        len = SSL_write(ssl, request, strlen(request));
        if (len < 0)
        {
            printf("send failed\n");
        }
        else
        {
            printf("send OK, %d bytes:\n%s\n", strlen(request), request);
        }
    }

    // read http response
    {
        char buffer[MAXBUF + 1];
        memset(buffer, 0, MAXBUF + 1);
        len = SSL_read(ssl, buffer, MAXBUF);
        if (len > 0) {
            printf("read OK, %d bytes: \n%s\n", len, buffer);
        }
        else
        {
            printf("recv failed\n");
            goto finish;
        }
    }

finish:
    SSL_shutdown(ssl);
    SSL_free(ssl);
    close(sockfd);
    SSL_CTX_free(ctx);

    return 0;
}
测试运行

编译
gcc -o test -ldl -lm test.c /usr/local/gmssl_10/lib/libssl.a /usr/local/gmssl_10/lib/libcrypto.a -I/usr/local/gmssl_10/include
运行
单向国密SSL网站
./test demo.gmssl.cn 443 /
双向国密SSL网站
./test demo.gmssl.cn 444 /cert.jsp sig.crt sig.key enc.crt enc.key

备注

1)搭建单向/双向国密web服务器,可以参见https://www.gmssl.cn,提供nginx/apache/tomcat支持。
2)申请国密双证书,参见https://www.gmssl.cn/gmssl/index.jsp?go=ca
3)https://demo.gmssl.cn是一个单向国密Web网站
4)https://demo.gmssl.cn:444是一个双向国密Web网站

小结

通过使用国密OpenSSL,C语言很容易编程来使用国密SSL连接国密Web网站。www.gmssl.cn提供了全部免费的测试组件,并且支持双向国密SSL,可供学习和测试。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 国密数字信封解析是使用C语言实现的一种解密算法。国密是中国自主研发的密码技术标准,国密数字信封是一种基于非对称加密的保护数据机制。 在C语言中实现国密数字信封解析,可以借助现有的密码学库,比如OpenSSL。首先,需要引入密码学库的头文件,并进行相应的初始化工作。 然后,需要提供解密所需的私钥和密文数据。私钥通常存储在文件中,可以通过读取文件的方式获取私钥信息。密文数据是使用公钥加密后的数据。 接下来,通过调用密码学库提供的函数,使用私钥对密文进行解密操作。解密过程首先要解析密文,获取其中的加密算法和加密参数等信息。然后使用私钥解密得到明文数据。 最后,对得到的明文数据进行相应的处理,比如输出到文件,或者进一步处理。 需要注意的是,在使用C语言实现国密数字信封解析时,需要熟悉国密算法和相应的密码学知识。同时,保证程序的安全性,防止密钥信息泄露和数据篡改等风险。 ### 回答2: 国密数字信封解析是一个使用C语言编写的程序,用于解析和处理国密数字信封的相关操作。国密数字信封是一种加密技术,用于在网络传输中保护数据的安全性和完整性。 该程序的实现主要包括以下几个步骤:首先,需要读取国密数字信封的相关信息,包括加密的数据、密钥、解密算法等。然后,通过调用相关的C语言库函数,对密文进行解密操作,恢复原始的明文数据。在解密过程中,还需要验证密文的完整性,确保数据没有被篡改。 在解密过程中,需要使用到国密算法中的相关函数和数据结构,例如SM4算法、GCM模式等。C语言提供了丰富的库函数和数据类型,可以方便地进行对这些算法的调用和处理。通过合理的编程和算法设计,可以提高解密的效率和安全性。 除此之外,国密数字信封解析程序还可以包括一些其他功能,例如密钥管理、用户身份验证等。这些功能可以通过C语言的指针、结构体和文件操作等特性来实现。 总之,国密数字信封解析程序的目的是通过C语言编写的程序,来实现对国密数字信封的解析和处理操作。通过合理地使用C语言的库函数和数据类型,可以高效地处理和保护数据的安全性和完整性。 ### 回答3: 国密数字信封解析是指在使用国密算法进行加密和解密的过程中,对数字信封进行解析的操作。 国密算法是中国自主研发的一种密码算法体系,包括对称加密算法、非对称加密算法、杂凑算法等。在使用国密算法对信息进行加密时,通常会使用数字信封的方式,即将对称密钥使用非对称加密算法进行加密,然后将加密后的密钥和加密后的信息一起发送或存储起来。 数字信封解析的过程主要包括以下几个步骤: 1. 获取加密的对称密钥和加密后的信息。 2. 使用私钥进行解密,获取解密后的对称密钥。 3. 使用解密后的对称密钥对加密后的信息进行解密,获得原始的明文信息。 在C语言中,可以使用国密算法的相关库函数进行数字信封解析的实现。例如,可以使用OpenSSL库提供的函数来实现RSA私钥解密、AES对称密钥解密等操作。具体实现的步骤如下: 1. 使用OpenSSL函数读取私钥文件,并使用私钥初始化RSA结构体。 2. 使用RSA私钥解密函数,将加密后的对称密钥解密得到原始的对称密钥。 3. 使用原始的对称密钥和国密算法加密函数,对加密后的信息进行解密操作,得到明文信息。 需要注意的是,在进行数字信封解析时,需要保证所使用的私钥和加密算法与加密时使用的公钥和算法一致,以确保解密的正确性。 总之,国密数字信封解析是使用国密算法对加密后的信息进行解密的过程,在C语言中可以使用相关库函数实现解析操作,包括私钥解密和对称密钥解密等步骤。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值