16.1 简介
数据压缩是将原有数据通过某种压缩算法计算得到相对数据量小的过程。这种过程是可逆的,即能通过压缩后的数据恢复出原数据。数据压缩能够节省存储空间,减轻网络负载。
在即需要加密又需要压缩的情况下,必须先压缩再加密,次序不能颠倒。因为加密后的数据是一个无序的数据,对它进行数据压缩,效果不大。
SSL协议本身支持压缩算法,Openssl实现也支持压缩算法。它实现了一个空的压缩算法(crypto/comp/c_rle.c)并支持zlib压缩算法(crypto/comp/ c_zlib.c)。openssl中用户可实现自己的压缩算法。
当openssl在有zlib库的平台下安装时,需要有zlib 或者zlib-dynamic选项。比如:
./config zlib
./config zlib-dynamic
16.2 数据结构
Openssl通过函数地址来抽象数据压缩。主要数据结构如下:
1) COMP_METHOD
该数据结构定义了具体压缩/解压函数,这些函数可由用户自己实现。
typedef struct comp_method_st
{
int type;
const char *name;
int (*init)(COMP_CTX *ctx);
void (*finish)(COMP_CTX *ctx);
int (*compress)(COMP_CTX *ctx,unsigned char *out, unsigned int olen, unsigned char *in, unsigned int ilen);
int (*expand)(COMP_CTX *ctx,unsigned char *out, unsigned int olen, unsigned char *in, unsigned int ilen);
long (*ctrl)(void);
long (*callback_ctrl)(void);
} COMP_METHOD;
各项意义如下:
type:压缩算法的nid;
name:压缩算法的名字;
init:初始化函数;
finish:结束操作;
commpress:具体的压缩算法,本函数必须实现;
expand:具体的解压算法,本函数必须实现;
ctrl和callback_ctrl:控制函数与回调控制函数,用于内部控制。
通过COMP_METHOD,Openssl能调用用户自己实现的压缩算法。只要用户实现了COMP_METHOD中的各个函数(主要是compress和expand函数)。
Openssl压缩源码位于crypto/comp目录下。它实现了一个空压缩算法和zlib压缩算法。其中空压缩算法由openssl自己实现,只是简单的拷贝数据。而zlib算法,openssl实现了基于其接口的COMP_METHOD,需要zlib库支持(/usr/lib/libz.a,/usr/lib/libz.so)。
2) comp_ctx
该结构用于存放压缩/解压中的上下文数据,主要供crypto/comp/comp_lib.c使用。
struct comp_ctx_st
{
COMP_METHOD *meth;
unsigned long compress_in;
unsigned long compress_out;
unsigned long expand_in;
unsigned long expand_out;
CRYPTO_EX_DATA ex_data;
};
各项意义如下:
meth:COMP_METHOD结构,一个comp_ctx通过它指明了一种具体的压缩算法;
compress_in:被压缩数据总字节数;
compress_out:压缩数据(结果)总字节数;
expand_in:被解压数据总字节数;
expand_out:解压数据(结果)总字节数;
ex_data:供用户使用的扩展数据,用于存放用户自定义的信息。
16.3 函数说明
1) COMP_rle
返回openssl实现的空压缩算法,返回值为一个COMP_METHOD。
2) COMP_zlib
返回基于zlib库的COMP_METHOD。
3) COMP_CTX_new
初始化上下文,输入参数为COMP_METHOD。
4) COMP_compress_block
压缩计算。
5) COMP_expand_block
解压计算。
16.4 openssl中压缩算法协商
Openssl中的压缩算法的协商与加密套件一样,都是由客户端在client hello消息中指定一个算法列表,而由服务端决定选取其中的一种,并通过server hello消息来通知客户端。
16.5 编程示例
#include <string.h>
#include <openssl/comp.h>
int main()
{
COMP_CTX *ctx;
int len,olen=100,ilen=50,i,total=0;
unsigned char in[50],out[100];
unsigned char expend[200];
#ifdef _WIN32
ctx=COMP_CTX_new(COMP_rle());
#else
/* for linux */
ctx=COMP_CTX_new(COMP_zlib());
#endif
for(i=0;i<50;i++)
memset(&in[i],i,1);
total=COMP_compress_block(ctx,out,olen,in,50);
len=COMP_expand_block(ctx,expend,200,out,total);
COMP_CTX_free(ctx);
return 0;
}