OpenSSL中提供的base64编解码函数

(本文内容针对 1.0.1c 版本的OpenSSL,尽管该版本的OpenSSL存在Heartbleed漏洞,但是Heartbleed漏洞与base64编解码的实现无关)

        对于 base64 编码,OpenSSL在 evp.h 中声明了相关函数,在 encode.c 中给出了实现。有两种方法:
1. 调用 EVP_EncodeBlock() 函数;用这种方法生成的编码需要解码时,应该调用 EVP_DecodeBlock()。
2. 依次调用 EVP_EncodeInit(), EVP_EncodeUpdate(), EVP_EncodeFinal()函数。EVP_EncodeUpdate(), EVP_EncodeFinal()中调用了 EVP_EncodeBlock()。
用这种方法生成的编码需要解码时,应该依次调用 EVP_DecodeInit(), EVP_DecodeUpdate(), EVP_DecodeFinal()。EVP_DecodeUpdate(), EVP_DecodeFinal()中调用了 EVP_DecodeBlock()。
        上面两种方法会在编码末尾添加一个字符串结束符'\0',但是解码时不会在解码输出字符串的末尾添加'\0'。

        RFC 2045中规定在 Multipurpose Internet Mail Extensions (MIME) 中使用 base64 编码时,生成的编码一行字符数上限为76。也就是说,最多在每 76 个 base64 编码字符后就要插入换行。
        上面第 1 种编码方法一次性地对所有输入数据进行编码,不会插入换行。
        如果编码结果要用于 MIME,必须考虑换行,这时应采用上面第 2 中编码方法。但 OpenSSL 不是每 76 个字符才换行,而是每 64 个字符就换行了,因为 76 是上限,只要不超过 76 就行,所以这样做也符合规范的要求。
        换行有两种:Unix 及 Linux 下的换行是 0x0A;Windows 下的换行是 0x0D 0x0A(回车符和换行符)。OpenSSL 插入的换行是 0x0A。

        base64 编码将 3 字节输入编码生成 4 字节输出,如果输入字符串长度不是 3 的整数倍,在编码时会进行填充。
        解码时,调用 EVP_DecodeBlock() 获得的解码长度中包括了编码时填充的字符个数。用户为了获得精确长度,需要手动去掉了编码时填充的字符个数。
        去除的方法也很简单:使用一个初值为 0 的计数器,查看 base64 编码的倒数第一个字符,如果是 = 将计数器值加 1,再查看倒数第二个字符是否是 = ,如果是 = 再将计数器的值加 1。由于 base64 编码的末尾最多会有两个 =,所以不用再往前查看了。用 EVP_DecodeBlock() 的返回值(表示未去除填充的解码结果字符串长度)减去计数器的值,就是编码前的原始数据的精确长度了。
        而依次调用 EVP_DecodeInit(), EVP_DecodeUpdate(), EVP_DecodeFinal() 获得的解码结果长度中不包括编码时填充的字符个数。用户不需要手动去掉填充字符个数。

        在测试程序时有一个发现:依次调用 EVP_DecodeInit(), EVP_DecodeUpdate(), EVP_DecodeFinal() 时,EVP_DecodeFinal() 只执行了一条 return(1); 语句,在 EVP_DecodeUpdate() 执行完毕后其实就完成了全部的解码操作,所以其后可以不必再调用 EVP_DecodeFinal(),只要依次调用 EVP_DecodeInit(), EVP_DecodeUpdate() 就够了。

        OpenSSL编解码的两种实现方式有没有可能统一成一种呢?
        为了试着做到这一点,我在 EVP_EncodeBlock() 和 EVP_DecodeBlock() 的基础上写了 EncodeBase64() 和 DecodeBase64() 两个函数,通过给 EncodeBase64() 的输入参数设置不同的值,可以得到不同的编码结果:不插入换行、插入换行、插入回车换行。还可以通过给 EncodeBase64() 的输入参数设置不同的值决定一行编码中的字符个数(例如 76 或 64)。 不管编码过程中有没有插入换行,插入何种换行, DecodeBase64() 都可以解码,因为它会忽略编码中所有的 0x0D 和 0x0A。

        最后附上代码,相关函数能独立使用,在编译时不需要包含 OpenSSL 的头文件,也不用链接到 OpenSSL 的库。分为三个文件:

第1个文件

/**************************************************
* File name: base64.h
* Author: HAN Wei
* Author's blog: http://blog.csdn.net/henter/
* Date: Oct 31th, 2013
* Description: declare base64 encode and decode functions
               When encoding is needed, EncodeBase64() function is invoked.  
               The user can decide the count of characters in a full line (the max 
	           count is set to 76 in RFC 2045). 
               The user can decide to insert 0x0A (line feed) or 0x0D (carriage return) 
	           0x0A into the end of each full line, and can also choose insert nothing. 
               When decoding is needed, DecodeBase64() function is invoked. 0x0A or  
               0x0D 0x0A in base64 codes will be ignored.

* Note: EncodeBase64() and DecodeBase64() are derived from EVP_EncodeBlock() and 
        EVP_DecodeBlock() in encode.c of OpenSSL 1.0.1c.
  OpenSSL web site: http://www.openssl.org/
**************************************************/

#ifndef BASE64_ENCODE_AND_DECODE_H
  #define BASE64_ENCODE_AND_DECODE_H

#ifdef  __cplusplus
extern "C" {
#endif

/************************************************** 
*函数名称:CalcBase64EncodeBufLen
*功能:  在使用Base64编码函数EncodeBase64()之前,该函数可以为函数调用者预先算出
        存放编码结果的缓冲区大小
*参数:
raw_data_len[in]    等待编码的原始数据长度,以字节为单位
line_feed_flag[in]  为0表示编码时不插入换行符,
                    为1表示编码时在换行处插入Unix或Linux下的换行0x0A
                    为2表示编码时在换行处插入Windows下的换行0x0D,0x0A
characters_count_per_base64_codes_line[in]  一行中能容纳的base64编码字符个数上限,
                                            line_feed_flag值为0时该参数被忽略,
					                        可设为任意值,因为此时base64编码不分行。
                                            line_feed_flag值为1或2时,该参数才有意义。
                                            根据RFC 2045的规定,该值最大可以设为76。
                                            要得到与OpenSSL中依次调用EVP_EncodeInit(),
					                        EVP_EncodeUpdate(),EVP_EncodeFinal()函数后
					                        生成的编码结果相同的编码时,将此值设为64,
					                        因为EVP_EncodeUpdate()中将一行能容纳的
					                        base64编码字符个数上限设为64
*返回值: 所需存放base64编码结果的缓冲区大小,以字节为单位。当返回值为 -1 时表示出错
**************************************************/
unsigned int CalcBase64EncodeBufLen(unsigned int raw_data_len,
	                                int line_feed_flag,
	                                unsigned int characters_count_per_base64_codes_line);

/************************************************** 
*函数名称:CalcBase64DecodeBufLen
*功能:     在使用Base64解码函数DecodeBase64()之前,该函数可以为函数调用者预先算出
           存放解码结果的缓冲区大小
*参数:
base64_codes[in]      指向待解码的base64字符串首地址的指针
base64_codes_Len[in]  等待解码的base64字符串长度,以字节为单位。当base64字符串以'\0'结尾时,该输入参数表示的字符串长度不包含'\0'所占的1个字节,仅为base64字符的总数(如果其中有回车或换行,在统计base64字符总数时要把回车及换行也计入)
*返回值: 存放base64解码结果的缓冲区大小,以字节为单位
**************************************************/
unsigned int CalcBase64DecodeBufLen(unsigned char *base64_codes, 
	                                unsigned int base64_codes_Len);

/************************************************** 
*函数名称:EncodeBase64
*功能:  base64编码函数
*参数:
t[out]  指向输出缓冲区首地址的指针
f[in]   指向输入缓冲区首地址的指针
n[in]   待编码的字符串长度,如果该字符串以'\0'结尾,统计该长度时不计入'\0'
line_feed_flag[in]  是否插入换行的标志,为0表示编码时不插入换行,
		            为1表示在一行编码字符末尾插入Unix或Linux下的换行0x0A,
		            为2表示在一行编码字符末尾插入Windows下的换行0x0D 0x0A
characters_count_per_base64_codes_line[in]  一行中能容纳的base64编码字符个数上限,
                                            line_feed_flag值为0时该参数可设为任意值,
					                        因为此时base64编码不分行。
					                        line_feed_flag值为1或2时,该参数才有意义,
					                        根据RFC 2045的规定,该值最大可以设为76。
					                        要得到与OpenSSL中依次调用EVP_EncodeInit(),EVP_EncodeUpdate(),EVP_EncodeFinal()
 生成的编码结果相同的编码时,应将此值设为64
*返回值: base64编码结果字符串长度,以字节为单位。。当返回值为 -1 时表示出错。
        如果在编码过程中插入了换行,那么像回车0x0D, 换行0x0A这样的符号的个数也计入长度,
        该函数会在编码结果字符串末尾加上一个'\0',但在计算返回值时,即统计编码字符串
        长度时不计入'\0'
**************************************************/
int EncodeBase64(unsigned char *t, 
	             unsigned char *f,
	             int n,
	             int line_feed_flag,
	             unsigned int characters_count_per_base64_codes_line);

/**************************************************
*函数名称:DecodeBase64
*功能:  base64解码函数
*参数:
t  指向输出缓冲区首地址的指针
f  指向输入缓冲区首地址的指针
n  待解码的base64字符串长度,统计该长度时如果字符串以'\0'结尾,不计入'\0',但是
   回车0x0D, 换行0x0A符号的个数也要计入长度,它们不会影响解码
注意:
  对于编码时在一行末尾插入的换行可能有两种:Windows下的换行符0x0D 0x0A,或Unix
  (及Linux)下的换行符0x0A。这两种换行该函数都能正确解码,因为该函数会忽略这些符号
*返回值: 存放base64解码结果字符串长度,即未编码的字符串长度。
         如果编码时进行过填充,填充的字符个数不被计入,用户无需再手动去除填充字符个数
**************************************************/
int DecodeBase64(unsigned char *t, unsigned char *f, int n);

#ifdef  __cplusplus
}
#endif

#endif /* end of BASE64_ENCODE_AND_DECODE_H */

 第2个文件

/**************************************************
* File name: base64.c
* Author: HAN Wei
* Author's blog: http://blog.csdn.net/henter/
* Date: Oct 31th, 2013
* Description: implement base64 encode and decode functions

* Note: EncodeBase64() and DecodeBase64() are derived from EVP_EncodeBlock() and 
        EVP_DecodeBlock() in encode.c of OpenSSL 1.0.1c.
  OpenSSL web site: http://www.openssl.org/
**************************************************/

#include "base64.h"
#include <stdio.h>

#define conv_bin2ascii(a)	(data_bin2ascii[(a)&0x3f])
#define conv_ascii2bin(a)	(data_ascii2bin[(a)&0x7f])
#define B64_EOLN		    0xF0
#define B64_CR			    0xF1
#define B64_EOF			    0xF2
#define B64_WS			    0xE0
#define B64_ERROR           0xFF
#define B64_NOT_BASE64(a)	(((a)|0x13) == 0xF3)

static const unsigned char data_bin2ascii[65]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

static const unsigned char data_ascii2bin[128]={
	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
	0xFF,0xE0,0xF0,0xFF,0xFF,0xF1,0xFF,0xFF,
	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
	0xE0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
	0xFF,0xFF,0xFF,0x3E,0xFF,0xF2,0xFF,0x3F,
	0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,
	0x3C,0x3D,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,
	0xFF,0x00,0x01,0x02,0x03,0x04,0x05,0x06,
	0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,
	0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,
	0x17,0x18,0x19,0xFF,0xFF,0xFF,0xFF,0xFF,
	0xFF,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,
	0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,
	0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,
	0x31,0x32,0x33,0xFF,0xFF,0xFF,0xFF,0xFF,
};

unsigned int CalcBase64EncodeBufLen(unsigned int raw_data_len, 
	                                int line_feed_flag, 
	                                unsigned int characters_count_per_base64_codes_line)
{
  unsigned int pure_base64_encode_len, pem_len, total=0;

  pure_base64_encode_len = (raw_data_len + 2) / 3 * 4;
  if (pure_base64_encode_len % characters_count_per_base64_codes_line == 0)
    pem_len = pure_base64_encode_len / characters_count_per_base64_codes_line;
  else
    pem_len = pure_base64_encode_len / characters_count_per_base64_codes_line + 1;
  switch (line_feed_flag)
  {
    case 0:
      total = pure_base64_encode_len+1;
	  break;
    case 1:
	  total = pure_base64_encode_len+pem_len+1;
	  break;
    case 2:
	  total = pure_base64_encode_len+pem_len*2 + 1;
	  break;
    default:
	  printf("invalid input parameter line_feed_flag=%d at %s, line %d!\n", line_feed_flag, __FILE__, __LINE__);
	  return (-1);
    }
  return total; 
}

unsigned int CalcBase64DecodeBufLen(unsigned char *base64_codes, 
	                                unsigned int base64_codes_Len)

{
  unsigned int i, line_feed_count=0, carriage_return_count=0, buffer_len=0;
  unsigned char *p;

  p=base64_codes;
  for (i=0; i<base64_codes_Len; i++)
  {
    if (p[i]==0x0D)
      carriage_return_count++;
	else
      if (p[i]==0x0A)
	    line_feed_count++;
  }
  buffer_len = (base64_codes_Len - carriage_return_count-line_feed_count) / 4 * 3;
  return buffer_len;
}

int EncodeBase64(unsigned char *t, 
	             unsigned char *f,
	             int n,
	             int line_feed_flag,
	             unsigned int characters_count_per_base64_codes_line)
{
  int i, ret=0, counter=0;
  unsigned long l;
  int characters_count_per_raw_data_line, pure_base64_encode_len;

  characters_count_per_raw_data_line = characters_count_per_base64_codes_line / 4 * 3;
  pure_base64_encode_len = (n+2)/3*4;

  for (i=n; i>0; i-=3)
  {
    if (i >= 3)
    {
	  l = ( ( (unsigned long)f[0] ) << 16L ) | ( ( (unsigned long)f[1] ) << 8L) | f[2];
	  *(t++)=conv_bin2ascii(l>>18L);
	  *(t++)=conv_bin2ascii(l>>12L);
	  *(t++)=conv_bin2ascii(l>> 6L);
	  *(t++)=conv_bin2ascii(l     );
    }
    else
    {
	  l=((unsigned long)f[0])<<16L;
	  if (i == 2) 
	    l|=((unsigned long)f[1]<<8L);

	  *(t++)=conv_bin2ascii(l>>18L);
	  *(t++)=conv_bin2ascii(l>>12L);
	  *(t++)=(i == 1)?'=':conv_bin2ascii(l>> 6L);
	  *(t++)='=';
    }
    f+=3;
    ret+=4;
    counter+=3;
    if (line_feed_flag)
    {
	  if (counter % characters_count_per_raw_data_line == 0)
	  {
	    switch (line_feed_flag)
	    {
	      case 1:
		    *t=0x0a;
	        t++;
		    ret++;
		    break;
	      case 2:
		    *t=0x0D;
		    t++;
		    *t=0x0a;
		    t++;
		    ret+=2;
		    break;
	      default:
	        printf("invalid input parameter line_feed_flag=%d at %s, line %d!\n", line_feed_flag, __FILE__, __LINE__);
	        return (-1);
	    }
	  }
    }
  }
  if (line_feed_flag)
  {
    if (pure_base64_encode_len % characters_count_per_base64_codes_line != 0)
    {
      switch (line_feed_flag)
      {
	    case 1:
	      *t=0x0a;
	      t++;
	      ret++;
	      break;
	    case 2:
	      *t=0x0D;
	      t++;
	      *t=0x0a;
	      t++;
	      ret+=2;
	      break;
	    default:
	      printf("invalid input parameter line_feed_flag=%d at %s, line %d!\n", line_feed_flag, __FILE__, __LINE__);
	      return (-1);
      }
    }
  }
  *t='\0';
  return(ret);
}

int DecodeBase64(unsigned char *t, unsigned char *f, int n)
{
  int i, ret=0, a, b, c, d;
  unsigned long l;
  unsigned char *p, *encode_buf=f;
  int pad_count=0;

/* trim white space from the start of the input buffer. */
  while ((conv_ascii2bin(*f) == B64_WS) && (n > 0))
  {
    f++;
    n--;
  }
/* trim B64_WS, B64_EOLN, B64_CR, B64_EOF at the end of the input buffer */
  while ((n > 3) && (B64_NOT_BASE64(conv_ascii2bin(f[n-1]))))
    n--;
  if (n<4) return (-1);

/* count the padding */
  p=&encode_buf[n-1];
  for (i=0; i<2; i++)
  {
    if (*p == '=')
    {
      pad_count++;
      p--;
    }
  }
#ifdef _DEBUG
  printf("pad_count=%d\n", pad_count);
#endif

/* base64 decoding */
  for (i=0; i<n; i+=4)
  {
    a=conv_ascii2bin(*(f++));
    b=conv_ascii2bin(*(f++));
    c=conv_ascii2bin(*(f++));
    d=conv_ascii2bin(*(f++));
    if ((a & 0x80) || (b & 0x80) || (c & 0x80) || (d & 0x80))
      return(-1);
    l=(	(((unsigned long)a)<<18L) | (((unsigned long)b)<<12L) | (((unsigned long)c)<< 6L) | (((unsigned long)d)) );
    *(t++)=(unsigned char)(l>>16L)&0xff;
    *(t++)=(unsigned char)(l>> 8L)&0xff;
    *(t++)=(unsigned char)(l     )&0xff;
    ret+=3;
/* ignore CR (0x0D) and LF (0x0A) */
    if (*f == 0x0D)
    {
      f++;
      n--;
    }
    if (*f == 0x0A)
    {
      f++;
      n--;
    }
  }
  ret-=pad_count;
  return(ret);
}

第3个文件

/**************************************************
* File name: sample.c 
* Author: HAN Wei  
* Author's blog: http://blog.csdn.net/henter/  
* Date: Mar 5th, 2013  
* Description: This program demostrates how to perform base64 encoding and decoding. 
**************************************************/

#include "base64.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MY_TEST_INPUT_DATA_LENGTH (unsigned int)(1024)

/* 这是一个演示程序,先对一个字符数组中的全部元素进行base64编码,再解码
   最后比较解码出来的结果是否与编码前的原始数据一致  */
int main(void)
{
  unsigned char input[MY_TEST_INPUT_DATA_LENGTH];
  unsigned char *encode_buffer=NULL, *decode_buffer=NULL;
  int i, input_len;
  int encode_buf_len, encode_len=0, decode_buf_len, decode_len=0;
  int my_line_feed_flag; 
/*  变量 my_line_feed_flag 值为0时,编码时不插入换行符;
                          值为1时,编码时插入Unix下的换行0x0A;
	                  值为2时,编码时插入Windows下的回车换行0x0D 0x0A  */
  int max_value_per_base64_codes_line;

  my_line_feed_flag=2;
  max_value_per_base64_codes_line=76;
/* 可以修改上面两个变量的值,分别将my_line_feed_flag的值设为0,1,2,再分别将
   max_value_per_base64_codes_line的值设为64和76,看看base64编码结果有何区别 */
 
  for (i=0; i<MY_TEST_INPUT_DATA_LENGTH; i++)
    memset(&input[i], i, 1);
  input_len=sizeof(input);
  printf("input data length is %d bytes.\n", input_len);
  printf("input data:\n");
  for (i=0; i<MY_TEST_INPUT_DATA_LENGTH; i++)
    printf("0x%x  ", input[i]);
  printf("\n");

// get the encode buffer length
  encode_buf_len=CalcBase64EncodeBufLen(input_len, my_line_feed_flag, max_value_per_base64_codes_line);
  printf("the encode buffer size is %d bytes.\n", encode_buf_len);
  if ( !(encode_buffer=(unsigned char *)malloc(encode_buf_len)) )
  {
    printf("malloc function failed at %s, line %d!\n", __FILE__, __LINE__);
#if defined(_WIN32) || defined(_WIN64)
    system("pause");
#endif
    return (-1);
  }

  encode_len=EncodeBase64(encode_buffer, input, input_len, my_line_feed_flag, max_value_per_base64_codes_line);
  printf("base64 codes length is %d bytes.\n", encode_len);
  printf("base64 codes:\n");
  printf("%s\n", encode_buffer);

  // get the decode buffer length
  decode_buf_len = CalcBase64DecodeBufLen(encode_buffer, encode_len);
  printf("\nthe decode buffer size is %d bytes\n", decode_buf_len);
  if ( !(decode_buffer=(unsigned char *)malloc(decode_buf_len)) )
  {
    printf("malloc function failed at %s, line %d!\n", __FILE__, __LINE__);
    free(encode_buffer);
#if defined(_WIN32) || defined(_WIN64)
    system("pause");
#endif
    return (-1);
  }

// base64 decoding
  if ( (decode_len=DecodeBase64(decode_buffer, encode_buffer, encode_len)) == -1 )
  {
    printf("my_decode_base64 function failed!\n");
    free(encode_buffer);
    free(decode_buffer);
#if defined(_WIN32) || defined(_WIN64)
    system("pause");
#endif
    return (-1);
  }
  printf("decode result length is %d bytes.\n", decode_len);
  printf("decode result:\n");
  for (i=0; i<decode_len; i++)
    printf("0x%x  ", decode_buffer[i]);
  printf("\n");

// compare the decoding result with input
  if (decode_len != input_len)
  {
    printf("decode result length does not match input length at %s, line %d!\n", __FILE__, __LINE__);
    free(encode_buffer);
    free(decode_buffer);
#if defined(_WIN32) || defined(_WIN64)
    system("pause");
#endif
    return (-1);
  }
  if ( memcmp(input, decode_buffer, input_len) )
  {
    printf("decode result does not match input data at %s, line %d!\n", __FILE__, __LINE__);
    free(encode_buffer);
    free(decode_buffer);
#if defined(_WIN32) || defined(_WIN64)
    system("pause");
#endif
    return (-1);
  }

  printf("base64 encoding and decoding succeed!\n");
  free(encode_buffer);	
  free(decode_buffer);
#if defined(_WIN32) || defined(_WIN64)
    system("pause");
#endif
  return 0;
}

 

提醒:

      如果base64编码是存放在一个文件中,当编码中包含换行或回车时,一定要用二进制方式打开文件,再用fread( )之类的函数将文件内容读入内存,再进行解码。

      在Windows平台上试验后发现:如果使用文本方式打开文件,使用fread( )函数时会自动忽略0x0D,只读入0x0A,这就会导致解码失败。

 

      如果要把base64编码写入到一个文件中去,当编码中包含换行或回车时,一定要用二进制方式打开文件,再用fwrite( )之类的函数将编码写入文件。

      在Windows平台上试验后发现:如果用文本方式打开文件,当要写入的base64编码只使用0x0A作为换行符时,使用fwrite( )函数时会自动在0x0A前面插入一个0x0D,导致实际写入的编码与期望不符。

 

    如果要把base64解码结果写入到一个文件中去,一定要用二进制方式打开文件,再用fwrite( )之类的函数将解码结果写入文件。

    在Windows平台上试验后发现:如果用文本方式打开文件,当解码结果中包含0x0A时,使用fwrite( )函数时会自动在0x0A前面插入一个0x0D,导致写入到文件中的解码结果出错。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
第一章 基础知识 8 1.1 对称算法 8 1.2 摘要算法 9 1.3 公钥算法 9 1.4 回调函数 11 第二章 openssl简介 13 2.1 openssl简介 13 2.2 openssl安装 13 2.2.1 linux下的安装 13 2.2.2 windows编译与安装 14 2.3 openssl源代码 14 2.4 openssl学习方法 16 第三章 堆栈 17 3.1 openssl堆栈 17 3.2 数据结构 17 3.3 源码 18 3.4 定义用户自己的堆栈函数 18 3.5 编程示例 19 第四章 哈希表 21 4.1 哈希表 21 4.2 哈希表数据结构 21 4.3 函数说明 23 4.4 编程示例 25 第五章 内存分配 27 5.1 openssl内存分配 27 5.2 内存数据结构 27 5.3 主要函数 28 5.4 编程示例 29 第六章 动态模块加载 30 6.1 动态库加载 30 6.2 DSO概述 30 6.3 数据结构 31 6.4 编程示例 32 第七章 抽象IO 34 7.1 openssl抽象IO 34 7.2 数据结构 34 7.3 BIO 函数 36 7.4 编程示例 36 7.4.1 mem bio 36 7.4.2 file bio 37 7.4.3 socket bio 38 7.4.4 md BIO 39 7.4.5 cipher BIO 40 7.4.6 ssl BIO 41 7.4.7 其他示例 42 第八章 配置文件 43 8.1 概述 43 8.2 openssl配置文件读取 43 8.3 主要函数 44 8.4 编程示例 44 第九章 随机数 46 9.1 随机数 46 9.2 openssl随机数数据结构与源码 46 9.3 主要函数 48 9.4 编程示例 48 第十章 文本数据库 50 10.1 概述 50 10.2 数据结构 51 10.3 函数说明 51 10.4 编程示例 52 第十一章 大数 54 11.1 介绍 54 11.2 openssl大数表示 54 11.3 大数函数 55 11.4 使用示例 58 第十二章 BASE64编解码 64 12.1 BASE64编码介绍 64 12.2 BASE64编解码原理 64 12.3 主要函数 65 12.4 编程示例 66 第十三章 ASN1库 68 13.1 ASN1简介 68 13.2 DER编码 70 13.3 ASN1基本类型示例 70 13.4 openssl 的ASN.1库 73 13.5 用openssl的ASN.1库DER编解码 74 13.6 Openssl的ASN.1宏 74 13.7 ASN1常用函数 75 13.8 属性证书编码 89 第十四章 错误处理 93 14.1 概述 93 14.2 数据结构 93 14.3 主要函数 95 14.4 编程示例 97 第十五章 摘要与HMAC 100 15.1 概述 100 15.2 openssl摘要实现 100 15.3 函数说明 101 15.4 编程示例 101 15.5 HMAC 103 第十六章 数据压缩 104 16.1 简介 104 16.2 数据结构 104 16.3 函数说明 105 16.4 openssl压缩算法协商 106 16.5 编程示例 106 第十七章 RSA 107 17.1 RSA介绍 107 17.2 openssl的RSA实现 107 17.3 RSA签名与验证过程 108 17.4 数据结构 109 17.4.1 RSA_METHOD 109 17.4.2 RSA 110 17.5 主要函数 110 17.6编程示例 112 17.6.1密钥生成 112 17.6.2 RSA加解密运算 113 17.6.3签名与验证 116 第十八章 DSA 119 18.1 DSA简介 119 18.2 openssl的DSA实现 120 18.3 DSA数据结构 120 18.4 主要函数 121 18.5 编程示例 122 18.5.1密钥生成 122 18.5.2签名与验证 124 第十九章DH 126 19.1 DH算法介绍 126 19.2 openssl的DH实现 127 19.3数据结构 127 19.4 主要函数 128 19.5 编程示例 129 第二十章 椭圆曲线 132 20.1 ECC介绍 132 20.2 openssl的ECC实现 133 20.3 主要函数 135 20.3.1参数设置 135 20.3.2参数获取 136 20.3.3转化函数 137 20.3.4其他函数 137 20.4 编程示例 139 第二十一章 EVP 143 21.1 EVP简介 143 21.2 数据结构 143 21.2.1 EVP_PKEY 144 21.2.2 EVP_MD 144 21.2.3 EVP_CIPHER 145 21.2.4 EVP_CIPHER_CTX 146 21.3 源码结构 147 21.4 摘要函数 147 21.5 对称加解密函数 148 21.6 非对称函数 149 21.7 BASE64编解码函数 149 21.8其他函数 150 21.9 对称加密过程 152 21.10 编程示例 152 第二十二章 PEM格式 159 22.1 PEM概述 159 22.2 openssl的PEM实现 160 22.3 PEM函数 161 22.4 编程示例 161 第二十三章 Engine 165 23.1 Engine概述 165 23.2 Engine支持的原理 165 23.3 Engine数据结构 166 23.4 openssl 的Engine源码 167 23.5 Engine函数 167 23.6 实现Engine示例 169 第二十四章 通用数据结构 182 24.1通用数据结构 182 24.2 X509_ALGOR 182 24.3 X509_VAL 184 24.4 X509_SIG 185 24.5 X509_NAME_ENTRY 186 24.6 X509_NAME 187 24.7 X509_EXTENSION 193 24.8 X509_ATTRIBUTE 199 24.9 GENERAL_NAME 200 第二十五章 证书申请 203 25.1 证书申请介绍 203 25.2 数据结构 203 25.3 主要函数 204 25.4 编程示例 206 25.4.1生成证书请求文件 206 25.4.2 解码证书请求文件 208 第二十六章 X509数字证书 210 26.1 X509数字证书 210 26.2 opessl实现 210 26.3 X509数据结构 210 26.4 X509_TRUST与X509_CERT_AUX 214 26.5 X509_PURPOSE 215 26.6 主要函数 218 26.7 证书验证 221 26.7.1证书验证项 221 26.7.2 Openssl的证书验证 221 第二十七章 OCSP 222 27.1 概述 222 27.2 openssl实现 222 27.3 主要函数 222 27.4编程示例 227 第二十八章 CRL 228 28.1 CRL介绍 228 28.2 数据结构 228 28.3 CRL函数 230 28.4 编程示例 231 第二十九章 PKCS7 233 29.1概述 233 29.2 数据结构 233 29.3 函数 234 29.4 消息编解码 235 29.4.1 data 235 29.4.2 signed data 236 29.4.3 enveloped 237 29.4.4 signed_and_enveloped 238 29.4.5 digest 238 29.4.6 encrypted 239 29.4.7 读取PEM 239 29.4.8 解码pkcs7 240 第三十章 PKCS12 241 30.1 概述 241 30.2 openss实现 241 30.3数据结构 242 30.4函数 243 30.5 编程示例 245 第三十一章 SSL实现 254 31.1概述 254 31.2 openssl实现 254 31.3 建立SSL测试环境 254 31.4 数据结构 256 31.5 加密套件 256 31.6 密钥信息 257 31.7 SESSION 258 31.8 多线程支持 258 31.9 编程示例 259 31.10 函数 270 第三十二章 Openssl命令 272 32.1概述 272 32.2 asn1parse 272 32.3 dgst 274 32.4 gendh 275 32.5 passwd 276 32.6 rand 276 32.7 genrsa 277 32.8 req 278 32.9 x509 280 32.10 version 283 32.11 speed 283 32.12 sess_id 284 32.13 s_server 284 32.14 s_client 286 32.15 rsa 288 32.16 pkcs7 289 32.17 dsaparam 290 32.18 gendsa 291 32.19 enc 291 32.20 ciphers 292 32.21 CA 293 32.22 verify 296 32.23 rsatul 297 32.24 crl 299 32.25 crl2pkcs7 300 32.26 errstr 300 32.27 ocsp 301 32.28 pkcs12 304 32.29 pkcs8 306 32.30 s_time 307 32.31 dhparam和dh 308 32.32 ecparam 309 32.33 ec 310 32.34 dsa 311 32.35 nseq 312 32.36 prime 313 32.37 smime 313

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值