summaryrefslogtreecommitdiffabout
path: root/pwmanager/libcrypt/cipher/elgamal.c
Unidiff
Diffstat (limited to 'pwmanager/libcrypt/cipher/elgamal.c') (more/less context) (ignore whitespace changes)
-rw-r--r--pwmanager/libcrypt/cipher/elgamal.c682
1 files changed, 682 insertions, 0 deletions
diff --git a/pwmanager/libcrypt/cipher/elgamal.c b/pwmanager/libcrypt/cipher/elgamal.c
new file mode 100644
index 0000000..e62b1e5
--- a/dev/null
+++ b/pwmanager/libcrypt/cipher/elgamal.c
@@ -0,0 +1,682 @@
1/* Elgamal.c - ElGamal Public Key encryption
2 * Copyright (C) 1998, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
3 *
4 * This file is part of Libgcrypt.
5 *
6 * Libgcrypt is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser general Public License as
8 * published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
10 *
11 * Libgcrypt is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 *
20 * For a description of the algorithm, see:
21 * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
22 * ISBN 0-471-11709-9. Pages 476 ff.
23 */
24
25#include <config.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include "g10lib.h"
30#include "mpi.h"
31#include "cipher.h"
32
33typedef struct
34{
35 gcry_mpi_t p; /* prime */
36 gcry_mpi_t g; /* group generator */
37 gcry_mpi_t y; /* g^x mod p */
38} ELG_public_key;
39
40
41typedef struct
42{
43 gcry_mpi_t p; /* prime */
44 gcry_mpi_t g; /* group generator */
45 gcry_mpi_t y; /* g^x mod p */
46 gcry_mpi_t x; /* secret exponent */
47} ELG_secret_key;
48
49
50static void test_keys (ELG_secret_key *sk, unsigned nbits);
51static gcry_mpi_t gen_k (gcry_mpi_t p, int small_k);
52static void generate (ELG_secret_key *sk, unsigned nbits, gcry_mpi_t **factors);
53static int check_secret_key (ELG_secret_key *sk);
54static void do_encrypt (gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input,
55 ELG_public_key *pkey);
56static void decrypt (gcry_mpi_t output, gcry_mpi_t a, gcry_mpi_t b,
57 ELG_secret_key *skey);
58static void sign (gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input,
59 ELG_secret_key *skey);
60static int verify (gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input,
61 ELG_public_key *pkey);
62
63
64static void (*progress_cb) (void *, const char *, int, int, int);
65static void *progress_cb_data;
66
67void
68_gcry_register_pk_elg_progress (void (*cb) (void *, const char *,
69 int, int, int),
70 void *cb_data)
71{
72 progress_cb = cb;
73 progress_cb_data = cb_data;
74}
75
76
77static void
78progress (int c)
79{
80 if (progress_cb)
81 progress_cb (progress_cb_data, "pk_elg", c, 0, 0);
82}
83
84
85/****************
86 * Michael Wiener's table on subgroup sizes to match field sizes
87 * (floating around somewhere - Fixme: need a reference)
88 */
89static unsigned int
90wiener_map( unsigned int n )
91{
92 static struct { unsigned int p_n, q_n; } t[] =
93 { /* p q attack cost */
94 { 512, 119 },/* 9 x 10^17 */
95 { 768, 145 },/* 6 x 10^21 */
96 { 1024, 165 },/* 7 x 10^24 */
97 { 1280, 183 },/* 3 x 10^27 */
98 { 1536, 198 },/* 7 x 10^29 */
99 { 1792, 212 },/* 9 x 10^31 */
100 { 2048, 225 },/* 8 x 10^33 */
101 { 2304, 237 },/* 5 x 10^35 */
102 { 2560, 249 },/* 3 x 10^37 */
103 { 2816, 259 },/* 1 x 10^39 */
104 { 3072, 269 },/* 3 x 10^40 */
105 { 3328, 279 },/* 8 x 10^41 */
106 { 3584, 288 },/* 2 x 10^43 */
107 { 3840, 296 },/* 4 x 10^44 */
108 { 4096, 305 },/* 7 x 10^45 */
109 { 4352, 313 },/* 1 x 10^47 */
110 { 4608, 320 },/* 2 x 10^48 */
111 { 4864, 328 },/* 2 x 10^49 */
112 { 5120, 335 },/* 3 x 10^50 */
113 { 0, 0 }
114 };
115 int i;
116
117 for(i=0; t[i].p_n; i++ )
118 {
119 if( n <= t[i].p_n )
120 return t[i].q_n;
121 }
122 /* Not in table - use an arbitrary high number. */
123 return n / 8 + 200;
124}
125
126static void
127test_keys( ELG_secret_key *sk, unsigned nbits )
128{
129 ELG_public_key pk;
130 gcry_mpi_t test = gcry_mpi_new ( 0 );
131 gcry_mpi_t out1_a = gcry_mpi_new ( nbits );
132 gcry_mpi_t out1_b = gcry_mpi_new ( nbits );
133 gcry_mpi_t out2 = gcry_mpi_new ( nbits );
134
135 pk.p = sk->p;
136 pk.g = sk->g;
137 pk.y = sk->y;
138
139 gcry_mpi_randomize( test, nbits, GCRY_WEAK_RANDOM );
140
141 do_encrypt( out1_a, out1_b, test, &pk );
142 decrypt( out2, out1_a, out1_b, sk );
143 if( mpi_cmp( test, out2 ) )
144 log_fatal("ElGamal operation: encrypt, decrypt failed\n");
145
146 sign( out1_a, out1_b, test, sk );
147 if( !verify( out1_a, out1_b, test, &pk ) )
148 log_fatal("ElGamal operation: sign, verify failed\n");
149
150 gcry_mpi_release ( test );
151 gcry_mpi_release ( out1_a );
152 gcry_mpi_release ( out1_b );
153 gcry_mpi_release ( out2 );
154}
155
156
157/****************
158 * Generate a random secret exponent k from prime p, so that k is
159 * relatively prime to p-1. With SMALL_K set, k will be selected for
160 * better encryption performance - this must never be used signing!
161 */
162static gcry_mpi_t
163gen_k( gcry_mpi_t p, int small_k )
164{
165 gcry_mpi_t k = mpi_alloc_secure( 0 );
166 gcry_mpi_t temp = mpi_alloc( mpi_get_nlimbs(p) );
167 gcry_mpi_t p_1 = mpi_copy(p);
168 unsigned int orig_nbits = mpi_get_nbits(p);
169 unsigned int nbits, nbytes;
170 char *rndbuf = NULL;
171
172 if (small_k)
173 {
174 /* Using a k much lesser than p is sufficient for encryption and
175 * it greatly improves the encryption performance. We use
176 * Wiener's table and add a large safety margin. */
177 nbits = wiener_map( orig_nbits ) * 3 / 2;
178 if( nbits >= orig_nbits )
179 BUG();
180 }
181 else
182 nbits = orig_nbits;
183
184
185 nbytes = (nbits+7)/8;
186 if( DBG_CIPHER )
187 log_debug("choosing a random k ");
188 mpi_sub_ui( p_1, p, 1);
189 for(;;)
190 {
191 if( !rndbuf || nbits < 32 )
192 {
193 gcry_free(rndbuf);
194 rndbuf = gcry_random_bytes_secure( nbytes, GCRY_STRONG_RANDOM );
195 }
196 else
197 {
198 /* Change only some of the higher bits. We could improve
199 this by directly requesting more memory at the first call
200 to get_random_bytes() and use this the here maybe it is
201 easier to do this directly in random.c Anyway, it is
202 highly inlikely that we will ever reach this code. */
203 char *pp = gcry_random_bytes_secure( 4, GCRY_STRONG_RANDOM );
204 memcpy( rndbuf, pp, 4 );
205 gcry_free(pp);
206 }
207 _gcry_mpi_set_buffer( k, rndbuf, nbytes, 0 );
208
209 for(;;)
210 {
211 if( !(mpi_cmp( k, p_1 ) < 0) ) /* check: k < (p-1) */
212 {
213 if( DBG_CIPHER )
214 progress('+');
215 break; /* no */
216 }
217 if( !(mpi_cmp_ui( k, 0 ) > 0) ) /* check: k > 0 */
218 {
219 if( DBG_CIPHER )
220 progress('-');
221 break; /* no */
222 }
223 if (gcry_mpi_gcd( temp, k, p_1 ))
224 goto found; /* okay, k is relative prime to (p-1) */
225 mpi_add_ui( k, k, 1 );
226 if( DBG_CIPHER )
227 progress('.');
228 }
229 }
230 found:
231 gcry_free(rndbuf);
232 if( DBG_CIPHER )
233 progress('\n');
234 mpi_free(p_1);
235 mpi_free(temp);
236
237 return k;
238}
239
240/****************
241 * Generate a key pair with a key of size NBITS
242 * Returns: 2 structures filles with all needed values
243 * and an array with n-1 factors of (p-1)
244 */
245static void
246generate ( ELG_secret_key *sk, unsigned int nbits, gcry_mpi_t **ret_factors )
247{
248 gcry_mpi_t p; /* the prime */
249 gcry_mpi_t p_min1;
250 gcry_mpi_t g;
251 gcry_mpi_t x; /* the secret exponent */
252 gcry_mpi_t y;
253 gcry_mpi_t temp;
254 unsigned int qbits;
255 unsigned int xbits;
256 byte *rndbuf;
257
258 p_min1 = gcry_mpi_new ( nbits );
259 temp = gcry_mpi_new( nbits );
260 qbits = wiener_map( nbits );
261 if( qbits & 1 ) /* better have a even one */
262 qbits++;
263 g = mpi_alloc(1);
264 p = _gcry_generate_elg_prime( 0, nbits, qbits, g, ret_factors );
265 mpi_sub_ui(p_min1, p, 1);
266
267
268 /* Select a random number which has these properties:
269 * 0 < x < p-1
270 * This must be a very good random number because this is the
271 * secret part. The prime is public and may be shared anyway,
272 * so a random generator level of 1 is used for the prime.
273 *
274 * I don't see a reason to have a x of about the same size
275 * as the p. It should be sufficient to have one about the size
276 * of q or the later used k plus a large safety margin. Decryption
277 * will be much faster with such an x.
278 */
279 xbits = qbits * 3 / 2;
280 if( xbits >= nbits )
281 BUG();
282 x = gcry_mpi_snew ( xbits );
283 if( DBG_CIPHER )
284 log_debug("choosing a random x of size %u", xbits );
285 rndbuf = NULL;
286 do
287 {
288 if( DBG_CIPHER )
289 progress('.');
290 if( rndbuf )
291 { /* Change only some of the higher bits */
292 if( xbits < 16 ) /* should never happen ... */
293 {
294 gcry_free(rndbuf);
295 rndbuf = gcry_random_bytes_secure( (xbits+7)/8,
296 GCRY_VERY_STRONG_RANDOM );
297 }
298 else
299 {
300 char *r = gcry_random_bytes_secure( 2,
301 GCRY_VERY_STRONG_RANDOM );
302 memcpy(rndbuf, r, 2 );
303 gcry_free(r);
304 }
305 }
306 else
307 {
308 rndbuf = gcry_random_bytes_secure( (xbits+7)/8,
309 GCRY_VERY_STRONG_RANDOM );
310 }
311 _gcry_mpi_set_buffer( x, rndbuf, (xbits+7)/8, 0 );
312 mpi_clear_highbit( x, xbits+1 );
313 }
314 while( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, p_min1 )<0 ) );
315 gcry_free(rndbuf);
316
317 y = gcry_mpi_new (nbits);
318 gcry_mpi_powm( y, g, x, p );
319
320 if( DBG_CIPHER )
321 {
322 progress('\n');
323 log_mpidump("elg p= ", p );
324 log_mpidump("elg g= ", g );
325 log_mpidump("elg y= ", y );
326 log_mpidump("elg x= ", x );
327 }
328
329 /* Copy the stuff to the key structures */
330 sk->p = p;
331 sk->g = g;
332 sk->y = y;
333 sk->x = x;
334
335 /* Now we can test our keys (this should never fail!) */
336 test_keys( sk, nbits - 64 );
337
338 gcry_mpi_release ( p_min1 );
339 gcry_mpi_release ( temp );
340}
341
342
343/****************
344 * Test whether the secret key is valid.
345 * Returns: if this is a valid key.
346 */
347static int
348check_secret_key( ELG_secret_key *sk )
349{
350 int rc;
351 gcry_mpi_t y = mpi_alloc( mpi_get_nlimbs(sk->y) );
352
353 gcry_mpi_powm( y, sk->g, sk->x, sk->p );
354 rc = !mpi_cmp( y, sk->y );
355 mpi_free( y );
356 return rc;
357}
358
359
360static void
361do_encrypt(gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, ELG_public_key *pkey )
362{
363 gcry_mpi_t k;
364
365 /* Note: maybe we should change the interface, so that it
366 * is possible to check that input is < p and return an
367 * error code.
368 */
369
370 k = gen_k( pkey->p, 1 );
371 gcry_mpi_powm( a, pkey->g, k, pkey->p );
372 /* b = (y^k * input) mod p
373 * = ((y^k mod p) * (input mod p)) mod p
374 * and because input is < p
375 * = ((y^k mod p) * input) mod p
376 */
377 gcry_mpi_powm( b, pkey->y, k, pkey->p );
378 gcry_mpi_mulm( b, b, input, pkey->p );
379#if 0
380 if( DBG_CIPHER )
381 {
382 log_mpidump("elg encrypted y= ", pkey->y);
383 log_mpidump("elg encrypted p= ", pkey->p);
384 log_mpidump("elg encrypted k= ", k);
385 log_mpidump("elg encrypted M= ", input);
386 log_mpidump("elg encrypted a= ", a);
387 log_mpidump("elg encrypted b= ", b);
388 }
389#endif
390 mpi_free(k);
391}
392
393
394
395
396static void
397decrypt(gcry_mpi_t output, gcry_mpi_t a, gcry_mpi_t b, ELG_secret_key *skey )
398{
399 gcry_mpi_t t1 = mpi_alloc_secure( mpi_get_nlimbs( skey->p ) );
400
401 /* output = b/(a^x) mod p */
402 gcry_mpi_powm( t1, a, skey->x, skey->p );
403 mpi_invm( t1, t1, skey->p );
404 mpi_mulm( output, b, t1, skey->p );
405#if 0
406 if( DBG_CIPHER )
407 {
408 log_mpidump("elg decrypted x= ", skey->x);
409 log_mpidump("elg decrypted p= ", skey->p);
410 log_mpidump("elg decrypted a= ", a);
411 log_mpidump("elg decrypted b= ", b);
412 log_mpidump("elg decrypted M= ", output);
413 }
414#endif
415 mpi_free(t1);
416}
417
418
419/****************
420 * Make an Elgamal signature out of INPUT
421 */
422
423static void
424sign(gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, ELG_secret_key *skey )
425{
426 gcry_mpi_t k;
427 gcry_mpi_t t = mpi_alloc( mpi_get_nlimbs(a) );
428 gcry_mpi_t inv = mpi_alloc( mpi_get_nlimbs(a) );
429 gcry_mpi_t p_1 = mpi_copy(skey->p);
430
431 /*
432 * b = (t * inv) mod (p-1)
433 * b = (t * inv(k,(p-1),(p-1)) mod (p-1)
434 * b = (((M-x*a) mod (p-1)) * inv(k,(p-1),(p-1))) mod (p-1)
435 *
436 */
437 mpi_sub_ui(p_1, p_1, 1);
438 k = gen_k( skey->p, 0 /* no small K ! */ );
439 gcry_mpi_powm( a, skey->g, k, skey->p );
440 mpi_mul(t, skey->x, a );
441 mpi_subm(t, input, t, p_1 );
442 mpi_invm(inv, k, p_1 );
443 mpi_mulm(b, t, inv, p_1 );
444
445#if 0
446 if( DBG_CIPHER )
447 {
448 log_mpidump("elg sign p= ", skey->p);
449 log_mpidump("elg sign g= ", skey->g);
450 log_mpidump("elg sign y= ", skey->y);
451 log_mpidump("elg sign x= ", skey->x);
452 log_mpidump("elg sign k= ", k);
453 log_mpidump("elg sign M= ", input);
454 log_mpidump("elg sign a= ", a);
455 log_mpidump("elg sign b= ", b);
456 }
457#endif
458 mpi_free(k);
459 mpi_free(t);
460 mpi_free(inv);
461 mpi_free(p_1);
462}
463
464
465/****************
466 * Returns true if the signature composed of A and B is valid.
467 */
468static int
469verify(gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, ELG_public_key *pkey )
470{
471 int rc;
472 gcry_mpi_t t1;
473 gcry_mpi_t t2;
474 gcry_mpi_t base[4];
475 gcry_mpi_t ex[4];
476
477 if( !(mpi_cmp_ui( a, 0 ) > 0 && mpi_cmp( a, pkey->p ) < 0) )
478 return 0; /* assertion0 < a < p failed */
479
480 t1 = mpi_alloc( mpi_get_nlimbs(a) );
481 t2 = mpi_alloc( mpi_get_nlimbs(a) );
482
483#if 0
484 /* t1 = (y^a mod p) * (a^b mod p) mod p */
485 gcry_mpi_powm( t1, pkey->y, a, pkey->p );
486 gcry_mpi_powm( t2, a, b, pkey->p );
487 mpi_mulm( t1, t1, t2, pkey->p );
488
489 /* t2 = g ^ input mod p */
490 gcry_mpi_powm( t2, pkey->g, input, pkey->p );
491
492 rc = !mpi_cmp( t1, t2 );
493#elif 0
494 /* t1 = (y^a mod p) * (a^b mod p) mod p */
495 base[0] = pkey->y; ex[0] = a;
496 base[1] = a; ex[1] = b;
497 base[2] = NULL; ex[2] = NULL;
498 mpi_mulpowm( t1, base, ex, pkey->p );
499
500 /* t2 = g ^ input mod p */
501 gcry_mpi_powm( t2, pkey->g, input, pkey->p );
502
503 rc = !mpi_cmp( t1, t2 );
504#else
505 /* t1 = g ^ - input * y ^ a * a ^ b mod p */
506 mpi_invm(t2, pkey->g, pkey->p );
507 base[0] = t2 ; ex[0] = input;
508 base[1] = pkey->y; ex[1] = a;
509 base[2] = a; ex[2] = b;
510 base[3] = NULL; ex[3] = NULL;
511 mpi_mulpowm( t1, base, ex, pkey->p );
512 rc = !mpi_cmp_ui( t1, 1 );
513
514#endif
515
516 mpi_free(t1);
517 mpi_free(t2);
518 return rc;
519}
520
521/*********************************************
522 ************** interface ******************
523 *********************************************/
524
525gcry_err_code_t
526_gcry_elg_generate (int algo, unsigned nbits, unsigned long dummy,
527 gcry_mpi_t *skey, gcry_mpi_t **retfactors)
528{
529 ELG_secret_key sk;
530
531 generate (&sk, nbits, retfactors);
532 skey[0] = sk.p;
533 skey[1] = sk.g;
534 skey[2] = sk.y;
535 skey[3] = sk.x;
536
537 return GPG_ERR_NO_ERROR;
538}
539
540
541gcry_err_code_t
542_gcry_elg_check_secret_key (int algo, gcry_mpi_t *skey)
543{
544 gcry_err_code_t err = GPG_ERR_NO_ERROR;
545 ELG_secret_key sk;
546
547 if ((! skey[0]) || (! skey[1]) || (! skey[2]) || (! skey[3]))
548 err = GPG_ERR_BAD_MPI;
549 else
550 {
551 sk.p = skey[0];
552 sk.g = skey[1];
553 sk.y = skey[2];
554 sk.x = skey[3];
555
556 if (! check_secret_key (&sk))
557 err = GPG_ERR_BAD_SECKEY;
558 }
559
560 return err;
561}
562
563
564gcry_err_code_t
565_gcry_elg_encrypt (int algo, gcry_mpi_t *resarr,
566 gcry_mpi_t data, gcry_mpi_t *pkey, int flags)
567{
568 gcry_err_code_t err = GPG_ERR_NO_ERROR;
569 ELG_public_key pk;
570
571 if ((! data) || (! pkey[0]) || (! pkey[1]) || (! pkey[2]))
572 err = GPG_ERR_BAD_MPI;
573 else
574 {
575 pk.p = pkey[0];
576 pk.g = pkey[1];
577 pk.y = pkey[2];
578 resarr[0] = mpi_alloc (mpi_get_nlimbs (pk.p));
579 resarr[1] = mpi_alloc (mpi_get_nlimbs (pk.p));
580 do_encrypt (resarr[0], resarr[1], data, &pk);
581 }
582 return err;
583}
584
585
586gcry_err_code_t
587_gcry_elg_decrypt (int algo, gcry_mpi_t *result,
588 gcry_mpi_t *data, gcry_mpi_t *skey, int flags)
589{
590 gcry_err_code_t err = GPG_ERR_NO_ERROR;
591 ELG_secret_key sk;
592
593 if ((! data[0]) || (! data[1])
594 || (! skey[0]) || (! skey[1]) || (! skey[2]) || (! skey[3]))
595 err = GPG_ERR_BAD_MPI;
596 else
597 {
598 sk.p = skey[0];
599 sk.g = skey[1];
600 sk.y = skey[2];
601 sk.x = skey[3];
602 *result = mpi_alloc_secure (mpi_get_nlimbs (sk.p));
603 decrypt (*result, data[0], data[1], &sk);
604 }
605 return err;
606}
607
608
609gcry_err_code_t
610_gcry_elg_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey)
611{
612 gcry_err_code_t err = GPG_ERR_NO_ERROR;
613 ELG_secret_key sk;
614
615 if ((! data)
616 || (! skey[0]) || (! skey[1]) || (! skey[2]) || (! skey[3]))
617 err = GPG_ERR_BAD_MPI;
618 else
619 {
620 sk.p = skey[0];
621 sk.g = skey[1];
622 sk.y = skey[2];
623 sk.x = skey[3];
624 resarr[0] = mpi_alloc (mpi_get_nlimbs (sk.p));
625 resarr[1] = mpi_alloc (mpi_get_nlimbs (sk.p));
626 sign (resarr[0], resarr[1], data, &sk);
627 }
628
629 return err;
630}
631
632gcry_err_code_t
633_gcry_elg_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey,
634 int (*cmp) (void *, gcry_mpi_t), void *opaquev)
635{
636 gcry_err_code_t err = GPG_ERR_NO_ERROR;
637 ELG_public_key pk;
638
639 if ((! data[0]) || (! data[1]) || (! hash)
640 || (! pkey[0]) || (! pkey[1]) || (! pkey[2]))
641 err = GPG_ERR_BAD_MPI;
642 else
643 {
644 pk.p = pkey[0];
645 pk.g = pkey[1];
646 pk.y = pkey[2];
647 if (! verify (data[0], data[1], hash, &pk))
648 err = GPG_ERR_BAD_SIGNATURE;
649 }
650
651 return err;
652}
653
654
655unsigned int
656_gcry_elg_get_nbits (int algo, gcry_mpi_t *pkey)
657{
658 return mpi_get_nbits (pkey[0]);
659}
660
661static char *elg_names[] =
662 {
663 "elg",
664 "openpgp-elg",
665 "openpgp-elg-sig",
666 NULL,
667 };
668
669
670gcry_pk_spec_t _gcry_pubkey_spec_elg =
671 {
672 "ELG", elg_names,
673 "pgy", "pgyx", "ab", "rs", "pgy",
674 GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR,
675 _gcry_elg_generate,
676 _gcry_elg_check_secret_key,
677 _gcry_elg_encrypt,
678 _gcry_elg_decrypt,
679 _gcry_elg_sign,
680 _gcry_elg_verify,
681 _gcry_elg_get_nbits,
682 };