ILD

使用libgcrypt产生rsa key
作者:Yuan Jianpeng 邮箱:yuanjp89@163.com
发布时间:2019-6-9 站点:Inside Linux Development

产生key的接口函数为:

gcry_error_t gcry_pk_genkey (gcry_sexp_t * r_key, gcry_sexp_t parms)

生成的key存放在r_key中,生成key的参数为parms。非对称加密使用S-expressions,典型的参数为:

(genkey (rsa (nbits 4:2048)))


首先需要构造parms,使用下列接口:

gcry_error_t gcry_sexp_new (gcry_sexp_t * r_sexp, const void * buffer , size_t length , int autodetect )

结果存储到r_sexp,buffer是s表达式的字符串表示,length是字符串的长度,如果字符串是null-terminated的,则长度可以为0,autodetect为0,则buffer的格式为canonized format;为1,则自动识别。


生成的key包含public-key和private-key,通过下列结果可以分别提取出来:

gcry_sexp_t gcry_sexp_find_token (const gcry_sexp_t list , const char * token , size_t toklen )

token是token的名字,toklen不是0,则是token的长度,为0表示是null-terminated字符串。


为了存储key,还需要通过下列接口将gcry_sexp_t类型的key转换为字符串或二进制数据:

size_t gcry_sexp_sprint (gcry_sexp_t sexp , int mode , char * buffer , size t maxlength )

mode主要有:

GCRYSEXP_FMT_CANON,二进制数据格式,适合存储到文件。

GCRYSEXP_FMT_ADVANCED,文本格式。

如果buffer为NULL,则返回是存储sexp需要的长度。如果buffer不是NULL,则返回成功存储到buffer的长度,如果buffer太短,则返回0。


产生key的时候,会读取/dev/random,为等待熵的产生,这通常需要等待等久,可以通过(flags transient-key)参数来设置不使用/dev/random,但安全性会降低。


示例函数:

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <gcrypt.h>
 
enum
{
    RSA_KEY_LEN_1024 = 1024,
    RSA_KEY_LEN_2048 = 2048,
    RSA_KEY_lEN_4096 = 4096,
};
 
enum
{
    RSA_KEY_FMT_CANON = GCRYSEXP_FMT_CANON,
    RSA_KEY_FMT_ADVANCED = GCRYSEXP_FMT_ADVANCED,
};
 
int gcrypt_gen_rsa_key(int key_len, int transient, int format,
    unsigned char **publicint *public_len,
    unsigned char **privateint *private_len)
{
    gcry_sexp_t key_spec = NULL,
                key = NULL, 
                pubkey = NULL, 
                seckey = NULL ;
 
    char key_exp_str[256];
    int ret = 1;
 
    switch (key_len) {
    case RSA_KEY_LEN_1024:
    case RSA_KEY_LEN_2048:
    case RSA_KEY_lEN_4096:
        break;
    default:
        return 1;
    };
 
    switch (format) {
    case RSA_KEY_FMT_CANON:
    case RSA_KEY_FMT_ADVANCED:
        break;
    default:
        return 1;
    };
 
    if (sizeof(key_exp_str) == 
        snprintf(key_exp_str, sizeof(key_exp_str), "(genkey (rsa %s(nbits 4:%d)))",
        transient ? "(flags transient-key) " "",
        key_len)) 
    {
        fprintf(stderr, "bufoverflow\n");
        return 1;
    }
 
    if (gcry_sexp_new(&key_spec, key_exp_str, 0, 1)){
        fprintf(stderr, "new S-expression failed\n");
        return 1;
    }
 
    if (gcry_pk_genkey(&key, key_spec)) {
        fprintf(stderr, "genkey failed\n");
        goto error;
 
    }
 
    pubkey = gcry_sexp_find_token(key, "public-key", 0);
    if (pubkey == NULL) {
        fprintf(stderr, "no public-key found\n");
        goto error;
    }
 
    seckey = gcry_sexp_find_token(key, "private-key", 0);
    if (seckey == NULL) {
        fprintf(stderr, "no private-key found\n");
        goto error;
    }
     
    *public_len = gcry_sexp_sprint(pubkey, format, NULL, 0);
    *public malloc(*public_len);
    if (*public == NULL) {
        fprintf(stderr, "malloc public key failed\n");
        goto error;
    }
    gcry_sexp_sprint(pubkey, format, *public, *public_len);
 
    *private_len = gcry_sexp_sprint(seckey, format, NULL, 0);
    *private malloc(*private_len);
    if (*private == NULL) {
        fprintf(stderr, "malloc private key failed\n");
        goto error;
    }
    gcry_sexp_sprint(seckey, format, *private, *private_len);
 
    ret = 0;
 
error:
    if (key_spec)
        gcry_sexp_release(key_spec);
    if (key)
        gcry_sexp_release(key);
    if (pubkey)
        gcry_sexp_release(pubkey);
    if (seckey)
        gcry_sexp_release(seckey);
 
    return ret;
}


参考:

https://stackoverflow.com/questions/39335323/gcry-pk-genkey-function-is-extremely-slow-in-libgcrypt


Copyright © linuxdev.cc 2017-2024. Some Rights Reserved.