OpenSSL初步学习

当涉及到网络通信和数据传输的安全性时,OpenSSL是一个非常重要的工具和库。它是一个开源软件包,提供了广泛的加密和安全功能。

OpenSSL概念

OpenSSL是一种开源的、安全的套接字层(SSL)和传输层安全性(TLS)协议的实现。它是一个用于安全通信的强大工具,可在计算机网络上提供加密、身份验证和数据完整性。OpenSSL可以用于开发安全的网络通信应用程序,例如Web服务器、邮件服务器和虚拟专用网络(VPN)。

OpenSSL提供了多种密码学算法,包括对称加密、非对称加密和哈希函数。它还支持各种数字证书格式,包括X.509证书和PKCS#7数字签名标准。OpenSSL可以在多个操作系统上运行,包括Linux、Windows和Mac OS X。

OpenSSL原理

OpenSSL的原理主要涉及SSL/TLS协议、密码学算法和数字证书等方面。

SSL/TLS协议是一种基于公开密钥加密的协议,用于在网络上进行安全通信。SSL/TLS协议的主要功能包括身份验证、数据机密性、数据完整性和会话保持。在SSL/TLS协议中,客户端和服务器之间会进行握手过程以协商加密算法、密钥交换方式和证书验证等信息,以确保通信双方身份的正确性和数据的安全性。

OpenSSL提供了多种密码学算法,包括对称加密算法、非对称加密算法和哈希函数。对称加密算法主要用于加密数据,常用的算法包括`AES`和`DES`等;非对称加密算法主要用于密钥交换和数字签名,常用的算法包括`RSA`和`ECC`等;哈希函数主要用于生成摘要值,常用的算法包括`SHA-1`和`SHA-256`等。

数字证书是证明身份和验证数据完整性的一种手段。OpenSSL支持多种数字证书格式,包括X.509证书和PKCS#7数字签名标准。数字证书中包含了证书持有者的公钥、证书持有者的信息、证书颁发机构的信息以及数字签名等信息,这些信息可以用于验证证书持有者的身份和数据的完整性。

在使用OpenSSL进行安全通信时,通常需要进行以下步骤:

  1. 生成公钥和私钥对;
  2. 使用证书颁发机构的私钥对公钥进行签名,生成数字证书;
  3. 在通信双方之间进行握手,协商加密算法和密钥交换方式;
  4. 使用对称加密算法加密数据,并使用数字证书进行身份验证和数据完整性验证;
  5. 在通信结束时,释放密钥并关闭连接。

通过这些步骤,OpenSSL可以实现安全的通信,保障数据的安全性和完整性。

OpenSSL使用场景

OpenSSL是一种开源的、安全的套接字层(SSL)和传输层安全性(TLS)协议的实现,适用于以下几个应用场景:

  1. Web服务器:OpenSSL可以用于保护Web服务器中的数据传输和用户隐私。例如,Apache等主流Web服务器均支持OpenSSL模块,以提供加密、身份验证和数据完整性。

  2. 邮件服务器:OpenSSL可以用于在邮件服务器中加密传输的邮件,以保护邮件的隐私和安全。

  3. 虚拟专用网络(VPN):OpenSSL可以用于构建安全的VPN通道,以保障远程访问的数据传输安全性。

  4. 数字签名:OpenSSL可以用于生成和验证数字签名,以保证数字文件的完整性和身份认证。

  5. 证书颁发机构(CA):OpenSSL可以用于搭建私有的证书颁发机构,为组织内部或特定用户颁发数字证书,以提供身份验证和数据安全性。

OpenSSL基础知识

对称算法

对称算法使用一个密钥。给定一个明文和一个密钥,加密产生密文,其长度和明文大致相同。解密时,使用读密钥与加密密钥相同。

对称算法主要有四种加密模式:

电子密码本模式        Electronic Code Book

这种模式是最早采用和最简单的模式,它将加密的数据分成若干组,每组的大小跟加密密钥长度相同,然后每组都用相同的密钥进行加密。

其缺点是:电子编码薄模式用一个密钥加密消息的所有块,如果原消息中重复明文块,则加密消息中的相应密文块也会重复,因此,电子编码薄模式适于加密小消息。

加密块链模式        Cipher Block Chaining

CBC模式的加密首先也是将明文分成固定长度的块,然后将前面一个加密块输出的密文与下一个要加密的明文块进行异或操作,将计算结果再用密钥进行加密得到密文。第一明文块加密的时候,因为前面没有加密的密文,所以需要一个初始化向量。跟ECB方式不一样,通过连接关系,使得密文跟明文不再是一一对应的关系,破解起来更困难,而且克服了只要简单调换密文块可能达到目的的攻击。

加密反馈模式        Cipher Feedback Mode

面向字符的应用程序的加密要使用流加密法,可以使用加密反馈模式。在此模式下,数据用更小的单元加密,如可以是8位,这个长度小于定义的块长(通常是64位)。其加密步骤是:

  1. 使用64位的初始化向量。初始化向量放在移位寄存器中,在第一步加密,产生相应的64位初始化密文;
  2. 始化向量最左边的8位与明文前8位进行异或运算,产生密文第一部分(假设为c),然后将c传输到接收方;
  3. 向量的位(即初始化向量所在的移位寄存器内容)左移8位,使移位寄存器最右边的8位为不可预测的数据,在其中填入c的内容;
  4. 第1-3步,直到加密所有的明文单元。

解密过程相反

输出反馈模式        Output Feedback Mode

输出反馈模式与CFB相似,唯一差别,CFB中密文填入加密过程下一阶段,而在OFB中,初始化向量加密过程的输入填入加密过程下一阶段。

摘要算法

 摘要算法是一种能产生特殊输出格式的算法,这种算法的特点是:无论用户输入什么长度的原始数据,经过计算后输出的密文都是固定长度的,这种算法的原理是根据一定的运算规则对原数据进行某种形式的提取,这种提取就是摘要,被摘要的数据内容与原数据有密切联系,只要原数据稍有改变,输出的“摘要”便完全不同,因此,基于这种原理的算法便能对数据完整性提供较为健全的保障。但是,由于输出的密文是提取原数据经过处理的定长值,所以它已经不能还原为原数据,即消息摘要算法是不可逆的,理论上无法通过反向运算取得原数据内容,因此它通常只能被用来做数据完整性验证。

如今常用的“消息摘要”算法经历了多年验证发展而保留下来的算法已经不多,这其中包括MD2MD4MD5SHASHA-1/256/383/512等。

常用的摘要算法主要有MD5SHA1。D5的输出结果为16字节,sha1的输出结果为20字节。

公钥算法

在公钥密码系统中,加密和解密使用的是不同的密钥,这两个密钥之间存在着相互依存关系:即用其中任一个密钥加密的信息只能用另一个密钥进行解密。这使得通信双方无需事先交换密钥就可进行保密通信。其中加密密钥和算法是对外公开的,人人都可以通过这个密钥加密文件然后发给收信者,这个加密密钥又称为公钥;而收信者收到加密文件后,它可以使用他的解密密钥解密,这个密钥是由他自己私人掌管的,并不需要分发,因此又成称为私钥,这就解决了密钥分发的问题。

主要的公钥算法有:RSADSADHECC

RSA算法

RSA系统是公钥系统的最具有典型意义的方法,大多数使用公钥密码进行加密和数字签名的产品和标准使用的都是RSA算法。

RSA算法是第一个既能用于数据加密也能用于数字签名的算法,因此它为公用网络上信息的加密和鉴别提供了一种基本的方法。它通常是先生成一对RSA 密钥,其中之一是保密密钥,由用户保存;另一个为公开密钥,可对外公开,甚至可在网络服务器中注册,人们用公钥加密文件发送给个人,个人就可以用私钥解密接受。为提高保密强度,RSA密钥至少为500位长,一般推荐使用1024位。

DSA算法

DSA,它是另一种公开密钥算法,它不能用作加密,只用作数字签名。DSA使用公开密钥,为接受者验证数据的完整性和数据发送者的身份。它也可用于由第三方去确定签名和所签数据的真实性。DSA算法的安全性基于解离散对数的困难性,这类签字标准具有较大的兼容性和适用性,成为网络安全体系的基本构件之一。 

Diffie-Hellman密钥交换

此算法是最早的公钥算法。它实质是一个通信双方进行密钥协定的协议:两个实体中的任何一个使用自己的私钥和另一实体的公钥,得到一个对称密钥,这一对称密钥其它实体都计算不出来。DH算法的安全性基于有限域上计算离散对数的困难性。离散对数的研究现状表明:所使用的DH密钥至少需要1024位,才能保证有足够的中、长期安全。

椭圆曲线密码体制(ECC)

其依据就是定义在椭圆曲线点群上的离散对数问题的难解性。为了用椭圆曲线构造密码系统,首先需要找到一个单向陷门函数,椭圆曲线上的数量乘就是这样的单向陷门函数。

回调函数

Openssl中大量用到了回调函数。回调函数一般定义在数据结构中,是一个函数指针。通过回调函数,客户可以自行编写函数,让openssl函数来调用它,即用户调用openssl提供的函数,openssl函数再回调用户提供的函数。这样方便了用户对openssl函数操作的控制。在openssl实现函数中,它一般会实现一个默认的函数来进行处理,如果用户不设置回调函数,则采用它默认的函数。

回调函数举例:

头文件:

#ifndef RANDOM_H

#define RANDOM_H 1

typedef int *callback_random(char *random,int len);

void    set_callback(callback_random *cb);

int     genrate_random(char *random,int len);

#endif

源代码:

#include "random.h"

#include <stdio.h>

callback_random *cb_rand=NULL;

static int default_random(char *random,int len

{

        memset(random,0x01,len);

        return 0;
}

void    set_callback(callback_random *cb)

{

        cb_rand=cb;

}

int     genrate_random(char *random,int len)
{

        if(cb_rand==NULL)

                return default_random(random,len);

        else

                return cb_rand(random,len);

        return 0;

}

测试代码:

#include "random.h"

static int my_rand(char *rand,int len)

{

        memset(rand,0x02,len);

        return 0;

}

int     main()

{

        char    random[10];

        int     ret;

set_callback(my_rand);

        ret=genrate_random(random,10);

        return 0;

}

本例子用来生产简单的随机数,如果用户提供了生成随机数回调函数,则生成随机数采用用户的方法,否则采用默认的方法。

OpenSSL源代码

OpenSSL源代码主要由eay库、ssl库、工具源码、范例源码以及测试源码组成。

eay库是基础的库函数,提供了很多功能。源代码放在crypto目录下。包括如下内容:

  1.  asn.1 DER编码解码(crypto/asn1目录),它包含了基本asn1对象的编解码以及数字证书请求、数字证书、CRL撤销列表以及PKCS8等最基本的编解码函数。这些函数主要通过宏来实现。
  2. 抽象IO(BIO,crypto/bio目录),本目录下的函数对各种输入输出进行抽象,包括文件、内存、标准输入输出、socket和SSL协议等。
  3.  大数运算(crypto/bn目录),本目录下的文件实现了各种大数运算。这些大数运算主要用于非对称算法中密钥生成以及各种加解密操作。另外还为用户提供了大量辅助函数,比如内存与大数之间的相互转换。
  4. 字符缓存操作(crypto/buffer目录)。
  5.  配置文件读取(crypto/conf目录),openssl主要的配置文件为openssl.cnf。本目录下的函数实现了对这种格式配置文件的读取操作。
  6. DSO(动态共享对象,crypto/dso目录),本目录下的文件主要抽象了各种平台的动态库加载函数,为用户提供统一接口。
  7. 硬件引擎(crypto/engine目录),硬件引擎接口。用户如果要写自己的硬件引擎,必须实现它所规定的接口。
  8. 错误处理(crypto/err目录),当程序出现错误时,openssl能以堆栈的形式显示各个错误。本目录下只有基本的错误处理接口,具体的的错误信息由各个模块提供。各个模块专门用于错误处理的文件一般为*_err..c文件。
  9. 对称算法、非对称算法及摘要算法封装(crypto/evp目录)。
  10. HMAC(crypto/hmac目录),实现了基于对称算法的MAC。
  11. hash表(crypto/lhash目录),实现了散列表数据结构。openssl中很多数据结构都是以散列表来存放的。比如配置信息、ssl session和asn.1对象信息等。
  12. 数字证书在线认证(crypto/ocsp目录),实现了ocsp协议的编解码以及证书有效性计算等功能。
  13. PEM文件格式处理(crypto/pem),用于生成和读取各种PEM格式文件,包括各种密钥、数字证书请求、数字证书、PKCS7消息和PKCS8消息等。
  14. pkcs7消息语法(crypto/pkcs7目录),主要实现了构造和解析PKCS7消息;
  15. pkcs12个人证书格式(crypto/pckcs12目录),主要实现了pkcs12证书的构造和解析。
  16. 队列(crypto/pqueue目录),实现了队列数据结构,主要用于DTLS。
  17. 随机数(crypto/rand目录),实现了伪随机数生成,支持用户自定义随机数生成。
  18. 堆栈(crypto/stack目录),实现了堆栈数据结构。
  19. 线程支持(crypto/threads),openssl支持多线程,但是用户必须实现相关接口。
  20. 文本数据库(crypto/txt_db目录)。
  21. x509数字证书(crypto/x509目录和crypto/x509v3),包括数字证书申请、数字证书和CRL的构造、解析和签名验证等功能了;
  22. 对称算法(crypto/aes、crypto/bf、crypto/cast、ccrypto/omp和crypto/des等目录)。
  23. 非对称算法(crypto/dh、crypto/dsa、crypto/ec和crypto/ecdh)。
  24. 摘要算法(crypto/md2、crypto/md4、crypto/md5和crypto/sha)以及密钥交换/认证算法(crypto/dh 和crypto/krb5)。

ssl库所有源代码在ssl目录下,包括了sslv2、sslv3、tlsv1和DTLS的源代码。

工具源码主要在crypto/apps目录下,默认编译时只编译成openssl(windows下为openssl.exe)可执行文件。该命令包含了各种命令工具。此目录下的各个源码可以单独进行编译。

范例源码在demo目录下,另外engines目录给出了openssl支持的几种硬件的engines源码,也可以作为engine编写参考。

测试源码主要在test目录下。

堆栈

堆栈是一种先进后出的数据结构。openssl大量采用堆栈来存放数据。它实现了一个通用的堆栈,可以方便的存储任意数据。它实现了许多基本的堆栈操作.

源码

openssl堆栈实现源码位于crypto/stack目录下。下面分析了部分函数。

  • sk_set_cmp_func

此函数用于设置堆栈存放数据的比较函数。由于堆栈不知道用户存放的是什么数据,所以,比较函数必须由用户自己实现。

  • sk_find

根据数据地址来查找它在堆栈中的位置。当堆栈设置了比较函数时,它首先对堆栈进行排序,然后通过二分法进行查找。如果堆栈没有设置比较函数,它只是简单的比较数据地址来查找.

  • sk_sort

本函数对堆栈数据排序。它首先根据sorted来判断是否已经排序,如果未排序则调用了标准C函数qsort进行快速排序。

  • sk_pop_free

本函数用于释放堆栈内存放的数据以及堆栈本身,它需要一个由用户指定的针对具体数据的释放函数。如果用户仅调用sk_free函数,则只会释放堆栈本身所用的内存,而不会释放数据内存。

哈希表

在一般的数据结构如线性表和树中,记录在结构中的相对位置是与记录的关键字之间不存在确定的关系,在结构中查找记录时需进行一系列的关键字比较。这一类查找方法建立在“比较”的基础上,查找的效率与比较次数密切相关。理想的情况是能直接找到需要的记录,因此必须在记录的存储位置和它的关键字之间建立确定的对应关系,使每个关键字和结构中一个唯一的存储位置相对应。在查找时,只需根据这个对应关系找到给定值。这种对应关系既是哈希函数,按这个思想建立的表为哈希表。

哈希表存在冲突现象:不同的关键字可能得到同一哈希地址。在建造哈希表时不仅要设定一个好的哈希函数,而且要设定一种处理冲突的方法。

函数说明

 LHASH *lh_new(LHASH_HASH_FN_TYPE h, LHASH_COMP_FN_TYPE c)

功能:生成哈希表

源文件:lhash.c

说明:输入参数h为哈希函数,c为比较函数。这两个函数都是回调函数。 因为哈希表用于存放任意的数据结构,哈希表存放、查询、删除等操作都需要比较数据和进行哈希运算,而哈希表不知道用户数据如何进行比较,也不知道用户数据结构中需要对哪些关键项进行散列运算。所以,用户必须提供这两个回调函数。

 

void *lh_delete(LHASH *lh, const void *data)

源文件:lhash.c

功能:删除散列表中的一个数据

说明:data为数据结构指针。

 

void lh_doall(LHASH *lh, LHASH_DOALL_FN_TYPE func)

源文件:lhash.c

功能:处理哈希表中的所有数据

说明:func为外部提供的回调函数,本函数遍历所有存储在哈希表中的数据,每个数据被func处理。

 

void lh_doall_arg(LHASH *lh, LHASH_DOALL_ARG_FN_TYPE func, void *arg)

源文件:lhash.c

功能:处理哈希表中所有数据

说明:此参数类似于lh_doall 函数,func为外部提供的回调函数,arg为传递给func函数的参数。本函数遍历所有存储在哈希表中的数据,每个数据被func处理。

 

void lh_free(LHASH *lh)

源文件:lhash.c

功能:释放哈希表。

 

void *lh_insert(LHASH *lh, void *data)

源文件:lhash.c

功能:往哈希表中添加数据。

说明:data为需要添加数据结构的指针地址。

 

void *lh_retrieve(LHASH *lh, const void *data)

源文件:lhash.c

功能:查询数据。

说明:从哈希表中查询数据,data为数据结构地址,此数据结构中必须提供关键项(这些关键项对应于用户提供的哈希函数和比较函数)以供查询,如果查询成功,返回数据结构的地址,否则返回NULL。

 

void lh_node_stats_bio(const LHASH *lh, BIO *out)

源文件:lh_stats.c

功能:将哈希表中每个链表下的数据状态输出到BIO中。

 

void lh_node_stats(const LHASH *lh, FILE *fp)

源文件:lh_stats.c

功能:将哈希表中每个链表下数据到个数输出到FILE中。

说明:此函数调用了lh_node_stats_bio函数。

 

void lh_node_usage_stats_bio(const LHASH *lh, BIO *out)

源文件:lh_stats.c

功能:将哈希表的使用状态输出到BIO中。

 

void lh_node_usage_stats(const LHASH *lh, FILE *fp)

源文件:lh_stats.c

功能:将哈希表的使用状态输出到FILE中

说明:此函数调用了lh_node_usage_stats_bio函数。

 

unsigned long lh_num_items(const LHASH *lh)

源文件:lhash.c

功能:获取哈希表中元素的个数。

 

void lh_stats_bio(const LHASH *lh, BIO *out)

源文件:lh_stats.c

功能:输出哈希表统计信息到BIO中。

 

void lh_stats(const LHASH *lh, FILE *fp)

源文件:lh_stats.c

功能:打印哈希表的统计信息,此函数调用了lh_stats_bio。

 

unsigned long lh_strhash(const char *c)

源文件:lhash.c

功能:计算文本字符串到哈希值。

 

OpenSSL内存分配

用户在使用内存时,容易犯的错误就是内存泄露。当用户调用内存分配和释放函数时,查找内存泄露比较麻烦。openssl提供了内置的内存分配和释放函数。如果用户完全调用openssl的内存分配和释放函数,可以方便的找到内存泄露点。openssl分配内存时,在其内部维护一个内存分配哈希表,用于存放已经分配但未释放的内存信息。当用户申请内存分配时,在哈希表中添加此项信息,内存释放时删除该信息。当用户通过openssl函数查找内存泄露点时,只需查询该哈希表即可。用户通过openssl回调函数还能处理那些泄露的内存。

主要函数

CRYPTO_mem_ctrl

本函数主要用于控制内存分配时,是否记录内存信息。如果不记录内存信息,将不能查找内存泄露。

 

CRYPTO_is_mem_check_on

查询内存记录标记是否开启。

 

CRYPTO_dbg_malloc

本函数用于分配内存空间,如果内存记录标记开启,则记录用户申请的内存。当需要记录内存信息时,该函数本身也需要申请内存插入哈希表,为了防止递归申请错误,它申请内存记录信息前必须暂时关闭内存记录标记,申请完毕再放开。

 

CRYPTO_dbg_free

释放内存,如果内存记录标记开启,还需要删除哈希表中对应的记录。

 

CRYPTO_mem_leaks

将内存泄露输出到BIO中。

 

CRYPTO_mem_leaks_fp

将内存泄露输出到FILE中(文件或者标准输出),该函数调用了CRYPTO_mem_leaks。

 

CRYPTO_mem_leaks_cb

处理内存泄露,输入参数为用户自己实现的处理内存泄露的函数地址。该函数只需要处理一个内存泄露,openssl通过lh_doall_arg调用用户函数来处理所有记录(泄露的内存)。

动态库加载

动态库加载函数能让用户在程序中加载所需要的模块,各个平台下的加载函数是不一样的。动态加载函数一般有如下功能:

  • 加载动态库

windows下的函数LoadLibraryA , Linux下的函数dlopen。这些函数一般需要动态库的名字作为参数。

  • 获取函数地址

windows下的函数GetProcAddress,Linux下的函数dlsym。这些函数一般需要函数名作为参数,返回函数地址。

  • 卸载动态库

windows下的函数FreeLibrary,Linux下的函数dlclose

DSO概述

DSO可以让用户动态加载动态库来进行函数调用。各个平台下加载动态库的函数是不一样的,openssl的DSO对各个平台下的动态库加载函数进行了封装,增加了源码的可移植性。openssl的DSO功能主要用于动态加载压缩函数(ssl协议)和engine(硬件加速引擎)。OpenSSL的DSO功能除了封装基本的功能外还有其他辅助函数,主要用于解决不同系统下路径不同的表达方式以及动态库全名不一样的问题。比如windows系统下路径可以用 “\\” 和  “/” 表示,而linux下只能用 “/”

windows下动态库的后缀为.dll 而linux下动态库名字一般为 libxxx.so

openssl抽象IO

openssl抽象IO(I/O abstraction,即BIO)是openssl对于io类型的抽象封装,包括:内存、文件、日志、标准输入输出、socket(TCP/UDP)、加/解密、摘要和ssl通道等。Openssl BIO通过回调函数为用户隐藏了底层实现细节,所有类型的bio的调用大体上是类似的。Bio中的数据能从一个BIO传送到另外一个BIO或者是应用程序。

BIO函数

BIO各个函数定义在crypto/bio.h中。所有的函数都由BIO_METHOD中的回调函数来实现。函数主要分为几类:

  • 具体BIO相关函数

BIO_new_file(生成新文件) 和   BIO_get_fd(设置网络链接)   ......

  • 通用抽象函数

BIO_read  和 BIO_write   ......

另外,还有很多函数时由宏定义通过控制函数BIO_ctrl实现,比如BIO_set_nbio、BIO_get_fd、BIO_eof

※配置文件

概述

OpenSSL采用自定义的配置文件来获取配置信息。OpenSSL的配置文件主要有如下内容组成:

注释信息:注释信息由#开头。

段信息:段信息由[xxx]来表示,其中xxx为段标识。

属性-值信息:表示方法为a=b,这种信息可以在一个段内也可以不属于任何段。

典型配置文件为 apps/openssl.cnf (同时该文件也是openssl最主要的配置文件)。

OpenSSL配置文件读取

Openssl读取配置文件的实现源码在crypto/conf中,主要函数定义在conf.h中。函数一般以CONF或NCONF(new conf,新函数)开头。本文主要介绍了新的conf函数的使用方。主要的数据结构在crypto/conf.h中定义如下:

typedef struct

{

    char *section;
    
    char *name;

    char *value;

} CONF_VALUE;

 section表明配置文件的段,name表示这个段中的一个属性,value则是这个属性的值。Openssl采用哈希表来存放这些信息,便于快速查找。

主要函数

NCONF_new

生成一个CONF结构。

 

CONF_free

释放空间,以及释放存储在散列表中的数据

 

CONF_load

函数定义:LHASH *CONF_load(LHASH *conf, const char *file, long *eline),该函数根据输入配置文件名,读取信息存入散列表,如果有错,eline为错误行。

 

CONF_load_bio/ CONF_load_fp

根据bio或者文件句柄读取配置信息并存入散列表。

 

CONF_get_section

给定段信息,得到散列表中的所有对应值。用于获取配置文件中指定某个段下的所有信息,这些信息存放在CONF_VALUE的堆栈中。

 

CONF_get_string

给定段以及属性值,得到对应的字符串信息。

 

CONF_get_number

给定段和属性值,获取对应的数值信息。

 

CONF_get1_default_config_file

获取默认的配置文件名,比如openssl.cnf

※BASE64编解码

介绍

BASE64编码是一种常用的将十六进制数据转换为可见字符的编码。与ASCII码相比,它占用的空间较小。BASE64编码在rfc3548中定义。

主要函数

OpenSSL中用于base64编解码的函数主要有:

  • 编码函数

Ø         EVP_EncodeInit

                     编码前初始化上下文。

Ø         EVP_EncodeUpdate

                     进行BASE64编码,本函数可多次调用。

Ø         EVP_EncodeFinal

                     进行BASE64编码,并输出结果。

Ø         EVP_EncodeBlock

                      进行BASE64编码。

  • 解码函数

Ø         EVP_DecodeInit

                        解码前初始化上下文。

Ø         EVP_DecodeUpdate

                        BASE64解码,本函数可多次调用。

Ø         EVP_DecodeFinal

                        BASE64解码,并输出结果。

Ø         EVP_DecodeBlock

                        BASE64解码,可单独调用。

NSA1库

 ASN.1,是一套灵活的标记语言,它允许定义多种数据类型,从integer、bit string 一类的简单类型到结构化类型,如set 和sequence,并且可以使用这些类型构建复杂类型。

 DER编码是ANS.1定义的将对象描述数据编码成八位串值的编码规则,它给出了对ANS.1值(对象的类型和值)的唯一编码规则。在ANS.1中,一个类型是一组值,对于某些类型,值的个数是已知的,而有些类型中值的个数是不固定的。ANS.1中有四种类型:

  1. 简单类型
  2. 结构类型
  3. 带标记类型
  4. 其他类型

DER编码

DER给出了一种将ASN.1值表示为8位串的方法。DER编码包含三个部分:

标识:定义值的类和标记码,指出是原始编码还是结构化编码。

长度:对于定长编码,指出内容中8位串的个数;对于不定长编码,指出长度是不定的。

内容:对于原始定长编码,给出真实值;对于结构化编码,给出各组件BER编码的按位串联结果。

内容结束:对于结构化不定长编码,标识内容结束;对于其它编码,无此项。

PEM格式

Openssl使用PEM格式来存放各种信息,它是openssl默认采用的信息存放方式。openssl中的PEM文件一般包含如下信息:

内容类型:

表明本文件存放的是什么信息内容,它的形式为“-------BEGIN XXXX ------”,与结尾的“------END XXXX------”对应。

头信息:

表明数据是如果被处理后存放,openssl中用的最多的是加密信息,比如加密算法以及初始化向量iv。

信息体:

为BASE64编码的数据。

证书申请

生成X509数字证书前,一般先由用户提交证书申请文件,然后由CA来签发证书。大致过程如下:

  1. 用户生成自己的公私钥对;
  2. 构造自己的证书申请文件,符合PKCS#10标准。该文件主要包括了用户信息、公钥以及一些可选的属性信息,并用自己的私钥给该内容签名;
  3.  用户将证书申请文件提交给CA;
  4.  CA验证签名,提取用户信息,并加上其他信息(比如颁发者等信息),用CA的私钥签发数字证书;

X509证书申请的格式标准为pkcs#10和rfc2314。

SSL实现

SSL协议最先由netscape公司提出,包括sslv2和sslv3两个版本。当前形成标准的为了tls协议(rfc2246规范)和DTLS(rfc4347,用于支持UDP协议)。sslv3和tls协议大致一样,只是有一些细微的差别。实际应用中,用的最多的为sslv3。

SSL协议能够保证通信双方的信道安全。它能提供数据加密、身份认证以及消息完整性保护,另外SSL协议还支持数据压缩。

SSL协议通过客户端和服务端握手来协商各种算法和密钥。

openssl实现

SSL协议源码位于ssl目录下。它实现了sslv2、sslv3、TLS以及DTLS(Datagram TLS,基于UDP的TLS实现)。ssl实现中,对于每个协议,都有客户端实现(XXX_clnt.c)、服务端实现(XXX_srvr.c)、加密实现(XXX_enc.c)、记录协议实现(XXX_pkt.c)、METHOD方法(XXX_meth.c)、客户端服务端都用到的握手方法实现(XXX_both.c),以及对外提供的函数实现(XXX_lib.c),比较有规律。

建立SSL测试环境

为了对SSL协议有大致的了解,我们可以通过openssl命令来建立一个SSL测试环境。

  • 建立自己的CA

在openssl安装目录的misc目录下(或者在apps目录下),运行脚本:./CA.sh -newca(Windows环境下运行:perl ca.pl –newca),出现提示符时,直接回车。  运行完毕后会生成一个demonCA的目录,里面包含了ca证书及其私钥。

  • 生成客户端和服务端证书申请
openssl req -newkey rsa:1024 -out req1.pem -keyout sslclientkey.pem

openssl req -newkey rsa:1024 -out req2.pem -keyout sslserverkey.pem
  • 签发客户端和服务端证书
openssl ca -in req1.pem -out  sslclientcert.pem

openssl ca -in req2.pem -out  sslservercert.pem
  • 运行ssl服务端和客户端
openssl s_server -cert sslservercert.pem -key sslserverkey.pem -CAfile demoCA/cacert.pem -ssl3

openssl s_client -ssl3 -CAfile demoCA/cacert.pem

运行客户端程序后,如果正确,会打印类似如下内容:

SSL-Session:

   Protocol  : SSLv3

Cipher    : DHE-RSA-AES256-SHA

    Session-ID: A729F5845CBFFBA68B27F701A6BD9D411627FA5BDC780264131EE966D1DFD6F5

    Session-ID-ctx:

    Master-Key: B00EEBD68165197BF033605F348A91676E872EB48487990D8BC77022578EECC0A9789CD1F929E6A9EA259F9F9F3F9DFA

    Key-Arg   : None

    Start Time: 1164077175

    Timeout   : 7200 (sec)

    Verify return code: 0 (ok)

此时,输入数据然后回车,服务端会显示出来。

命令的其他选项:

验证客户端证书

openssl s_server -cert sslservercert.pem -key sslserverkey.pem -CAfile demoCA/cacert.pem -ssl3 -Verify 1

openssl s_client -ssl3 -CAfile demoCA/cacert.pem -cert sslclientcert.pem -key sslclientkey.pem

指定加密套件

openssl s_server -cert sslservercert.pem -key sslserverkey.pem -CAfile demoCA/cacert.pem -ssl3 -Verify 1

openssl s_client -ssl3 -CAfile demoCA/cacert.pem -cert sslclientcert.pem -key sslclientkey.pem -cipher AES256-SHA

其中AES256-SHA可用根据openssl ciphers命令获取,s_server也可用指明加密套件:

openssl s_server -cert sslservercert.pem -key sslserverkey.pem -CAfile demoCA/cacert.pem -ssl3 -Verify 1 -cipher AES256-SHA

指定私钥加密口令

openssl s_server -cert sslservercert.pem -key sslserverkey.pem -CAfile demoCA/cacert.pem -ssl3 -Verify 3 -cipher AES256-SHA -pass pass:123456

openssl s_client -ssl3 -CAfile demoCA/cacert.pem -cert sslclientcert.pem -key sslclientkey.pem -pass pass:123456

用参数pass给出私钥保护口令来源:

-pass file:1.txt   (1.txt的内容为加密口令123456);

-pass env:envname (环境变量);

-pass fd:fdname ;

-pass stdin。

比如:

openssl s_client -ssl3 -CAfile demoCA/cacert.pem -cert sslclientcert.pem -key sslclientkey.pem -pass stdin

然后输入口令123456即可。

※OpenSSL命令

Openssl命令源码位于apps目录下,编译的最终结果为openssl(windows下为openssl.exe)。用户可用运行openssl命令来进行各种操作。

更多命令操作指南:OpenSSL的各种命令参考

 

 

 

 

 

 

  • 28
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值