使用c/c++ Openssl库,建立安全连接流程?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用c/c++ Openssl库,建立安全连接流程?相关的知识,希望对你有一定的参考价值。

现有证书a.p12和b.cer文件;
a.p12 -- 含义公钥和私鈅;
b.cer -- 证书文件.

使用C/C++ 和OpenSSL的库函数,创建一个使用以上证书文件的实例怎么写。
还请给出代码流程和使用OpenSSL的函数.谢谢。
郁闷很,没人回答。

参考技术A 建议看这本书《Network Security with OpenSSL》O'Reilly 2002.7出版的,网上有电子版,在这本书的第五章有客户端和服务器端的实例代码,并有详细的说明。
服务器端主要流程为:
1. 加载SSL库
SSL_load_error_strings();
SSLeay_add_ssl_algorithms();
2. 加载CA证书和私钥文件
SSL_CTX* ctx = SSL_CTX_new(SSLv23_server_method());
SSL_CTX_use_certificate_file(ctx, CA_CERT, SSL_FILETYPE_PEM)
SSL_CTX_set_default_passwd_cb_userdata(ctx, PASSWORD)
SSL_CTX_use_PrivateKey_file(ctx, PRVTKEY, SSL_FILETYPE_PEM)
SSL_CTX_check_private_key(ctx)
3. 建立TCP连接并监听

4. 接收客户端请求并建立SSL连接
SSL*ssl = SSL_new(ctx);
SSL_set_fd(ssl, fd_accept)
SSL_accept(ssl)
5. 获取客户端证书信息
SSL_get_peer_certificate(ssl)
X509_NAME_oneline(X509_get_subject_name(cli_cert), NULL, 0)
X509_NAME_oneline(X509_get_issuer_name(cli_cert), NULL, 0)
X509_free(cli_cert)
6. 接收和发送数据
SSL_write
SSL_read
7. 释放套接字和SSL
SSL_CTX_free(ctx)
SSL_free(ssl)
客户端主要流程:
1. 加载SSL库
SSL_load_error_strings();
SSLeay_add_ssl_algorithms();
2. 如果需要验证服务器端的信息的话步骤同服务器的步骤2一样
3. 创建套接字连接到服务器
4. 创建SSL连接
SSL_CTX* ctx = SSL_CTX_new(SSLv23_client_method());
5. 基于套接字建立SSL连接
SSL* ssl = SSL_new(ctx);
SSL_set_fd(ssl, fd_connect);
SSL_connect(ssl)
6. 收发数据
SSL_write
SSL_read
7. 释放连接和SSL
SSL_CTX_free(ctx)
SSL_free(ssl)本回答被提问者采纳
参考技术B 不会

OpenSSL库开发:命令行使用

1、简介

OpenSSL 是用于传输层安全 (TLS) 协议(以前称为安全套接字层 (SSL) 协议)的强大、商业级、功能齐全的开源工具包。协议实现基于全强度通用密码库,也可以单独使用。

  • OpenSSL 源自 Eric A. Young 和 Tim J. Hudson 开发的 SSLeay 库。
  • OpenSSL 项目的官方主页是www.openssl.org。
  • OpenSSL(密码学和 SSL/TLS 工具包) 项目开发和维护 OpenSSL 软件——一个强大的、商业级的、功能齐全的工具包,用于通用加密和安全通信。
  • OpenSSL采用C语言作为开发语言,这使得OpenSSL具有优秀的跨平台性能。OpenSSL支持Linux、Windows、BSD、Mac、VMS等平台,这使得OpenSSL具有广泛的适用性。

2、使用openssl(命令行openssl.exe)

2.1 私钥公钥生成

这两者的工作机制是,通过公钥加密的数据只能通过对应的私钥才能解密查看。而通过私钥加密的数据如果能被对应的公钥解开则可断定数据由该私钥的所有者发送。 前一个机制可以用于加密消息的传递,后一个则可以用于身份的确认,凡事通过公钥A能解密的数据一定是私钥A的所有者发送的数据。

默认情况下,openssl 输出格式为 PKCS#1-PEM

  • 生成RSA私钥(无加密)
openssl genrsa -out rsa_private.key 256
  • 生成RSA公钥
openssl rsa -in rsa_private.key -pubout -out rsa_public.key
  • 生成RSA私钥(使用aes256加密)
openssl genrsa -aes256 -passout pass:123456 -out rsa_aes_private.key 256
  • 生成公钥(需提供密码)
openssl rsa -in rsa_aes_private.key -passin pass:123456 -pubout -out rsa_public.key
  • 私钥转非加密
openssl rsa -in rsa_aes_private.key -passin pass:123456 -out rsa_private.key
  • 私钥转加密
openssl rsa -in rsa_private.key -aes256 -passout pass:123456 -out rsa_aes_private.key
  • 查看私钥明细(使用-pubin参数可查看公钥明细)
openssl rsa -in rsa_private.key -noout -text

2.2 自签名证书生成

  • 生成 RSA 私钥和自签名证书 <font color=blue>req是证书请求的子命令,-newkey rsa:256 -keyout private_key.pem 表示生成私钥(PKCS8格式),-nodes 表示私钥不加密,若不带参数将提示输入密码;-x509表示输出证书,-days365 为有效期,此后根据提示输入证书拥有者信息;若执行自动输入,可使用-subj选项。
openssl req -newkey rsa:256 -nodes -keyout rsa_private.key -x509 -days 365 -out cert.crt
或
openssl req -newkey rsa:256 -nodes -keyout rsa_private.key -x509 -days 365 -out cert.crt -subj "/C=CN/ST=GD/L=SZ/O=xx/OU=dev/CN=yyy.com/emailAddress=xx@yyy.com"
  • 使用 已有RSA 私钥生成自签名证书
openssl req -new -x509 -days 365 -key rsa_private.key -out cert.crt

<font color=blue>-new 指生成证书请求,加上-x509 表示直接输出证书,-key 指定私钥文件。

  • 查看证书细节
openssl x509 -in cert.crt -noout -text
  • 另外,openssl命令方式生成公钥、私钥、证书汇总如下:
#1.生成私钥文件
openssl genrsa -des3 -out privkey.pem 256
# or 无密码
openssl genrsa -out privkey.pem 256

#2.生成证书请求文件和证书文件
openssl req -new -key privkey.pem -out cert.csr
openssl req -new -x509 -key privkey.pem -out cacert.pem -days 3650

#3.生成公钥文件
openssl rsa -in privkey.pem -inform pem -pubout -out pubkey.pem

#4.查看密钥信息
openssl rsa -noout -text -in privkey.pem
  • 另外,服务器客户端证书生成的命令汇总如下:
#生成服务端证书
#使用openssl工具生成一个RSA私钥
openssl genrsa -des3 -out server.key 256
#查看生成的私钥
openssl rsa -text -in server.key
#创建证书签名请求CSR文件
openssl req -new -key server.key -out server.csr
#查看csr文件
openssl req -text -in server.csr -noout
#生成CA证书
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

#生成客户端证书
#先要生成私钥
openssl genrsa -out client.key 2048
#生成请求文件
openssl req -new -key client.key -out client.csr
#签名
openssl x509 -req -days 365 -in client.csr -signkey client.key -out client.crt

2.3 加密文件

  • 生成私钥
openssl genrsa -out Key.pem -f4 2048

  • 从私钥导出公钥
openssl rsa -in Key.pem -pubout -out Key_pub.pem

  • 将字符串”Hello World, 爱看书的小沐!”存放到文件msg.bin作为测试文件
echo "Hello World, 爱看书的小沐!" > msg.bin

  • 查看文件内容(以十六进制)
hexdump -Cv msg.bin

  • 使用公钥Key_pub.pem对测试数据msg.bin进行加密生成msg.bin.enc
openssl rsautl -in msg.bin -out msg.bin.enc -inkey Key_pub.pem -pubin -encrypt -pkcs

  • 查看加密后的数据
hexdump -Cv msg.bin.enc

  • 使用私钥Key.pem对加密后的数据msg.bin.enc进行解密,并将结果存放到msg.bin.dec文件中
openssl rsautl -in msg.bin.enc -out msg.bin.dec -inkey Key.pem -decrypt -pkcs

  • 查看解密的内容
hexdump -Cv msg.bin.dec

3、个人测试

3.1 软件License许可证文件实现(C++)

如何保护软件版权,最常用的办法就是设计一套license验证框架。 这里基于OpenSSL库的加密功能,使用C++编写逻辑代码,WTL编写界面代码,实现一个简单的许可证应用小程序(包括许可申请,许可生成,许可验证等功能)。

  • 申请界面(客户端) 此处省略。
  • 生成界面(管理端)
  • 生成的许可证文件内容如下:

3.2 批量加密图片文件(python)

openssl genrsa -out rsa_private.key 2048
openssl rsa -in rsa_private.key -pubout -out rsa_public.key
openssl rsa -in rsa_public.key -noout -text -pubin

  • 加密前:

  • 加密后:

  • 相关代码如下:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @File    : 批量加密图片v2.py
# @Time    : 2022-8-10
# @Author  : 爱看书的小沐
# @blog    : https://blog.csdn.net/hhy321
# @Language: python3.9, win10 x64
# @Version : 2.0
# @Desc    : 批量加密和解密图片文件

import os
import random

def generate_random_str(randomlength=16):
    """
    生成一个指定长度的随机字符串(使用指定的字符集合填充)
    """
    random_str =
    base_str =ABCDEFGHIGKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789
    length =len(base_str) -1
    for i in range(randomlength):
        random_str +=base_str[random.randint(0, length)]
    return random_str

def generate_random_int(randomlength=16):
    """
    生成一个指定长度的随机数字串(使用随机的0~254数字填充)
    """
    random_int = []
    for i in range(randomlength):
        random_int.append(random.randint(25, 254))
    return random_int

def generate_random_int(randomlength=16, filldata = [], addToENd = False):
    """
    生成一个指定长度的随机数字串(使用固定字符集合填充)
    """
    fill_len = len(filldata)
    random_int = []
    if randomlength < fill_len:
        return generate_random_int(randomlength)

    for i in range(randomlength):
        if addToENd == False:
            if i < fill_len:
                random_int.append(filldata[i])
            else:
                random_int.append(random.randint(25, 254))
        else:
            if i < randomlength - fill_len:
                random_int.append(random.randint(25, 254))
            else:
                random_int.append(filldata[i - (randomlength - fill_len)])
    return random_int

def getXor(text, key):
    """
    字符串异或计算
    """
    text_bytes = []
    for i in range(0, len(text)):
        text_bytes.append((text[i] ^ ord(key[i % len(key)])))
    return text_bytes

def encrypt_image(image_file, encrypt_file):
    """
    加密图片文件
    """
    f = open(image_file, rb)
    fw = open(encrypt_file, wb)
    data = f.read()

    ## 原始的文件头128(异或运算)
    header_old = data[0:128]
    key = 123456
    header_old_xor = getXor(header_old, key)
    header_old_xor = bytes(bytearray(header_old_xor))
    print(type(header_old_xor), header_old_xor)

    ## 新的文件头128(随机数填充)
    header_new = generate_random_int(128)
    header_tag = "FXIMAGEv100"
    for c in range(len(header_tag)):
        header_new[c] = ord (header_tag[c])
    header_new = bytes(bytearray(header_new))

    ## 读取openssl公钥文件512
    public_key = open(r"d:\\rsa_public.key", rb).read()
    rand_data = generate_random_int(512, public_key, True)
    rand_data = bytes(bytearray(rand_data))

    ## 生成加密后的新图片文件
    fw.write(header_new)
    fw.write(data[128:])
    fw.write(header_old_xor)
    fw.write(rand_data)
    fw.close()
    f.close()
    
def findAllFile(base):
    for root, ds, fs in os.walk(base):
        for f in fs:
            fullname = os.path.join(root, f)
            yield fullname

def main():
    src_dir = D:\\Image
    dest_dir = D:\\Image2
    if not os.path.exists(dest_dir):
        os.makedirs(dest_dir)

    for f in findAllFile(src_dir):
        print(f)
        dirname, filename = os.path.split(f)
        dirname_encrypt = dirname.replace(src_dir, dest_dir)
        if not os.path.exists(dirname_encrypt):
            os.makedirs(dirname_encrypt)
        filename_encrypt = os.path.splitext(filename)[0] + r".fximage"
        encrypt_image(f, dirname_encrypt + "\\\\" + filename_encrypt )

    print("ok")
    
if __name__ == __main__:
    main()    

3.3 图片Arnold置乱算法(python)

  • (1)Arnold置乱算法

这个算法可以让一张图片从有序变成无序,逆变换可以让他从无序变成有序,同时他还具有一定的周期性,一直正向变化也可以从有序->无序->有序,但由于加密密钥方式很多,置乱的周期也可能不一样。

图像变换(加密过程): 其中x和y表示坐标,new表示变换以后的坐标,ori表示原始的坐标,a和b是两个可选的参数,mod为求余数操作,N是图像的长或者宽,这里只考虑长度和宽度相等的图像,上式表示的就是“图像的坐标变换”。 或

对应的逆变换(解密过程):

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @File    : test_arnold.py
# @Time    : 2022-8-14
# @Author  : 爱看书的小沐
# @blog    : https://blog.csdn.net/hhy321
# @Language: python3.9, win10 x64
# @Version : 1.0
# @Desc    : 图片Arnold置乱算法
## pip install opencv-python

import numpy as np
import cv2

def arnold_encode(image, shuffle_times, a, b):
    """ 
    Arnold shuffle for rgb image
    """
    # 1:创建新图像
    [ROW, COL, COMP] = img.shape
    arnold_image = np.zeros(shape=image.shape, dtype=uint8)

    # 2:遍历像素坐标变换
    for time in range(shuffle_times):
        for ori_x in range(ROW):
            for ori_y in range(COL):
                new_x = (1*ori_x + b*ori_y) % ROW
                new_y = (a*ori_x + (a*b+1)*ori_y) % COL
                arnold_image[new_x, new_y, :] = image[ori_x, ori_y, :]
                
    return arnold_image

def arnold_decode(image, shuffle_times, a, b):
    """ 
    Dearnold shuffle for rgb image
    """
    # 1:创建新图像
    [ROW, COL, COMP] = img.shape
    arnold_image = np.zeros(shape=image.shape, dtype=uint8)
    
    # 2:遍历像素坐标变换
    for time in range(shuffle_times):
        for ori_x in range(ROW):
            for ori_y in range(COL):
                new_x = ((a*b+1)*ori_x - b*ori_y) % ROW
                new_y = (-a*ori_x + 1*ori_y) % COL
                arnold_image[new_x, new_y, :] = image[ori_x, ori_y, :]

    return arnold_image

if __name__ == __main__: 
    img = cv2.imread(d:/test.jpg, cv2.IMREAD_UNCHANGED)
    a = 1
    b = 1
    T = 1 #迭代次数

    cv2.imshow(origin image, img)

    img_arnold = arnold_encode(img, T, a, b)
    cv2.imshow(arnold image, img_arnold)

    img_dearnold = arnold_decode(img_arnold, T, a, b)
    cv2.imshow(dearnold image, img_dearnold)

    cv2.waitKey()
    cv2.destroyAllWindows()

运行结果如下:(原始图片,加密图片,解密图片, a=1,b=1,T=1) 运行结果如下:(原始图片,加密图片,解密图片, a=5,b=3,T=2)

结语

如果您觉得该方法或代码有一点点用处,可以给作者点个赞,或打赏杯咖啡;╮( ̄▽ ̄)╭ 如果您感觉方法或代码不咋地//(ㄒoㄒ)//,就在评论处留言,作者继续改进;o_O??? 如果您需要相关功能的代码定制化开发,可以留言私信作者;(✿◡‿◡) 感谢各位大佬童鞋们的支持!( ´ ▽´ )ノ ( ´ ▽´)っ!!!

以上是关于使用c/c++ Openssl库,建立安全连接流程?的主要内容,如果未能解决你的问题,请参考以下文章

CertPathValidation OpenSSL C API

开源加密解密库比较

使用 OpenSSL API 建立安全连接 - 双向认证(精讲)

新手:Linux下使用第三方C库(openssl),是调用.so文件还是直接调用.h文件?

C语言安全编码

基于 OpenSSL 的简单 C/S 通信 C 程序设计使用函数文档