产生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 ** public , int *public_len, unsigned char ** private , int *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