OpenSSL入门-常用编码

Base64

BIO_new将参数type中各个变量赋值给BIO街头中的method成员:

1
2
3
BIO* BIO_new(
BIO_METHOD* type
);

参数type可由BIO_f_base64返回,写的时候编码,读的时候解码:

1
BIO_METHOD* BIO_f_base64();

其中BIO_METHOD结构为:

1
2
3
4
5
6
7
8
9
10
11
12
typedef struct bio_method_st{
int type; //类型
const char* name; //名字
int (*bwrite)(BIO*,const char*,int); //二进制写回调函数
int (*bread)(BIO*,char*,int); //二进制读回调函数
int (*bputs)(BIO*,const char*); //文本写回调函数
int (*bgets)(BIO*,char*,int); //文本读回调函数
long (*ctrl)(BIO*,int,long,void*); //控制回调函数
int (*create)(BIO*); //生成回调函数
int (*destroy)(BIO*); //销毁回调函数
long (*callback_ctrl)(BIO*,int,bio_info_cb*); //控制回调函数 由调用者实现 用BIO_set_callback设置
}BIO_METHOD;

OpenSSL实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
int base64_encode(char* in_str, int in_len, char* out_str) { //编码
BIO* b64, * bio;
BUF_MEM* bptr = NULL;
size_t size = 0;
if (in_str == NULL || out_str == NULL)
return -1;
b64 = BIO_new(BIO_f_base64());
bio = BIO_new(BIO_s_mem());
bio = BIO_push(b64, bio);
BIO_write(bio, in_str, in_len);
BIO_flush(bio);
BIO_get_mem_ptr(bio, &bptr);
memcpy(out_str, bptr->data, bptr->length);
out_str[bptr->length] = '\0';
size = bptr->length;
BIO_free_all(bio);
return size;
}
int base64_decode(char* in_str, int in_len, char* out_str) {//解码
BIO* b64, * bio;
BUF_MEM* bptr = NULL;
int counts;
int size = 0;
if (in_str == NULL || out_str == NULL)
return -1;
b64 = BIO_new(BIO_f_base64());
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
bio = BIO_new_mem_buf(in_str, in_len);
bio = BIO_push(b64, bio);
size = BIO_read(bio, out_str, in_len);
out_str[size] = '\0';
BIO_free_all(bio);
return size;
}
int main(){
char instr[512] = "";
char outstr1[1024] = { 0 };
puts("enter plain text:");
scanf_s("%s", instr, 512);
base64_encode(instr, strlen(instr), outstr1);
printf("base64:%s", outstr1); //末尾并没有\n,但实际输出回车换行了。
char outstr2[1024] = { 0 };
base64_decode(outstr1, strlen(outstr1), outstr2);
printf("base64 -d:%s\n", outstr2);
return 0;
}

PEM文件

1
openssl genrsa -out RSA私钥文件名.pem 1024 #密钥长度1024

ASN.1

下载ASN1C编译器并安装:http://lionet.info/asn1c/download.html 。新建.asn1文件:

1
2
3
4
5
6
RetangleTest DEFINITIONS::=BEGIN
Rectangle::=SEQUENCE{
height INTEGER, --Height of the rectangle
width INTEGER --Width of the rectangle
}
END

生成:

1
asn1c -S skeletons -fskeletons-copy -fnative-types try.asn1

之后会生成一堆文件。在Visual Studio工程目录下新建inc文件夹并添加到附加包含目录中,把生成的.h文件复制进去,再把生成的.c文件复制到工程目录下,删除converter-sample.c。

Windows上的编译器最新的只有2006年的,只支持x86下编译。代码实现为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <stdio.h>
#include <sys/types.h>
#include <Rectangle.h>
char tab[8];
static int decode_callback(const void* buffer, size_t size, void* app_key) {
static int i = 0;
memcpy(&tab[i], buffer, size);
i += size;
return 0;
}
int main() {
Rectangle_t* rectangle; /* Type to encode */
asn_enc_rval_t ec; /* Encoder return value */
/* Allocate the Rectangle_t */
rectangle = (Rectangle_t*)calloc(1, sizeof(Rectangle_t)); /* not */
if (!rectangle) {
perror("calloc() failed");
exit(71); /* better, EX_OSERR */
}
/* Initialize the Rectangle members */
rectangle->height = 42; /* any random value */
rectangle->width = 23; /* any random value */
/* Encode the Rectangle type as BER (DER) */
ec = der_encode(&asn_DEF_Rectangle, rectangle, decode_callback, tab);
if (ec.encoded == -1) {
fprintf(stderr, "Could not encode Rectangle (at %s)\n", ec.failed_type ? ec.failed_type->name : "unknown");
exit(65); /* better, EX_DATAERR */
}
else
fprintf(stderr, "Created %s with BER encoded Rectangle\n", "");
/* Also print the constructed Rectangle XER encoded (XML) */
xer_fprint(stdout, &asn_DEF_Rectangle, rectangle);
return 0;
}