ElGamal funktioniert und ist default
[gnupg.git] / g10 / seckey-cert.c
1 /* seckey-cert.c -  secret key certifucate packet handling
2  *      Copyright (c) 1997 by Werner Koch (dd9jn)
3  *
4  * This file is part of G10.
5  *
6  * G10 is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * G10 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 General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * 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
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <assert.h>
26 #include "util.h"
27 #include "memory.h"
28 #include "packet.h"
29 #include "mpi.h"
30 #include "keydb.h"
31 #include "cipher.h"
32
33 #if  BLOWFISH_BLOCKSIZE != 8
34   #error unsupportted blocksize
35 #endif
36
37 static u16
38 checksum( byte *p )
39 {
40     u16 n, a;
41
42     n = *p++ << 8;
43     n |= *p++;
44     for(a=0; n; n-- )
45         a += *p++;
46     return a;
47 }
48
49
50
51 static int
52 check_elg( PKT_seckey_cert *cert )
53 {
54     byte iv[8];
55     byte *mpibuf;
56     u16 n;
57     MPI temp_mpi;
58     int res;
59     u32 keyid[2];
60     ELG_secret_key skey;
61
62     if( cert->d.elg.is_protected ) { /* remove the protection */
63         DEK *dek = NULL;
64         BLOWFISH_context *blowfish_ctx=NULL;
65
66         switch( cert->d.elg.protect_algo ) {
67           case CIPHER_ALGO_NONE: log_bug(NULL); break;
68           case CIPHER_ALGO_BLOWFISH:
69             keyid_from_skc( cert, keyid );
70             dek = get_passphrase_hash( keyid, NULL );
71             m_free(dek); /* pw is in secure memory, so m_free() burns it */
72             memset( iv, 0, BLOWFISH_BLOCKSIZE );
73             blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx );
74             blowfish_setiv( blowfish_ctx, iv );
75             blowfish_decode_cfb( blowfish_ctx,
76                                  cert->d.elg.protect.blowfish.iv,
77                                  cert->d.elg.protect.blowfish.iv, 8 );
78             cert->d.elg.calc_csum = 0;
79             mpibuf = (byte*)cert->d.elg.x;
80             n = ((mpibuf[0] << 8) | mpibuf[1])-2;
81             blowfish_decode_cfb( blowfish_ctx, mpibuf+4, mpibuf+4, n );
82             cert->d.elg.calc_csum += checksum( mpibuf );
83             cert->d.elg.x = mpi_decode_buffer( mpibuf );
84             m_free( mpibuf );
85             m_free( blowfish_ctx );
86             cert->d.elg.is_protected = 0;
87             /* now let's see wether we have used the right passphrase */
88             if( cert->d.elg.calc_csum != cert->d.elg.csum )
89                 return G10ERR_BAD_PASS;
90
91             skey.p = cert->d.elg.p;
92             skey.g = cert->d.elg.g;
93             skey.y = cert->d.elg.y;
94             skey.x = cert->d.elg.x;
95             res = elg_check_secret_key( &skey );
96             memset( &skey, 0, sizeof skey );
97             if( !res )
98                 return G10ERR_BAD_PASS;
99             break;
100
101           default:
102             return G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
103         }
104     }
105     /* must check the checksum here, because we didn't do it when
106      * parsing an unprotected certificate */
107     if( cert->d.elg.calc_csum != cert->d.elg.csum ) {
108         log_error("checksum in secret key certificate is wrong\n");
109         log_debug("stored csum=%04hx calculated csum=%04hx\n",
110                    cert->d.elg.csum, cert->d.elg.calc_csum );
111         return G10ERR_CHECKSUM;
112     }
113     return 0;
114 }
115
116
117 #ifdef HAVE_RSA_CIPHER
118 static int
119 check_rsa( PKT_seckey_cert *cert )
120 {
121     byte iv[8];
122     byte *mpibuf;
123     u16 n;
124     MPI temp_mpi;
125     int res;
126     u32 keyid[2];
127
128     if( cert->d.rsa.is_protected ) { /* remove the protection */
129         DEK *dek = NULL;
130         BLOWFISH_context *blowfish_ctx=NULL;
131
132         switch( cert->d.rsa.protect_algo ) {
133           case CIPHER_ALGO_NONE:
134             log_bug("unprotect seckey_cert is flagged protected\n");
135             break;
136           case CIPHER_ALGO_BLOWFISH:
137             keyid_from_skc( cert, keyid );
138             dek = get_passphrase_hash( keyid, NULL );
139
140             m_free(dek); /* pw is in secure memory, so m_free() burns it */
141             memset( iv, 0, BLOWFISH_BLOCKSIZE );
142             blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx );
143             blowfish_setiv( blowfish_ctx, iv );
144             blowfish_decode_cfb( blowfish_ctx,
145                                  cert->d.rsa.protect.blowfish.iv,
146                                  cert->d.rsa.protect.blowfish.iv, 8 );
147             cert->d.rsa.calc_csum = 0;
148           #define X(a) do {                                             \
149                     mpibuf = (byte*)cert->d.rsa.rsa_##a;                \
150                     n = ((mpibuf[0] << 8) | mpibuf[1])-2;               \
151                     blowfish_decode_cfb( blowfish_ctx,                  \
152                                          mpibuf+4, mpibuf+4, n );       \
153                     cert->d.rsa.calc_csum += checksum( mpibuf );        \
154                     cert->d.rsa.rsa_##a = mpi_decode_buffer( mpibuf );  \
155                     m_free( mpibuf );                                   \
156                 } while(0)
157             X(d);
158             X(p);
159             X(q);
160             X(u);
161           #undef X
162             m_free( blowfish_ctx );
163             cert->d.rsa.is_protected = 0;
164           #if 0
165             #define X(a) do { printf("\tRSA " #a ": ");                   \
166                               mpi_print(stdout, cert->d.rsa.rsa_##a, 1 ); \
167                               putchar('\n');                              \
168                             } while(0)
169             X(n); X(e); X(d); X(p); X(q); X(u);
170             #undef X
171           #endif
172             /* now let's see wether we have used the right passphrase */
173             if( cert->d.rsa.calc_csum != cert->d.rsa.csum )
174                 return G10ERR_BAD_PASS;
175             temp_mpi = mpi_alloc(40);
176             mpi_mul(temp_mpi, cert->d.rsa.rsa_p, cert->d.rsa.rsa_q );
177             res = mpi_cmp( temp_mpi, cert->d.rsa.rsa_n );
178             mpi_free(temp_mpi);
179             if( res )
180                 return G10ERR_BAD_PASS;
181             break;
182
183           default:
184             return G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
185         }
186     }
187     /* must check the checksum here, because we didn't do it when
188      * parsing an unprotected certificate */
189     if( cert->d.rsa.calc_csum != cert->d.rsa.csum ) {
190         log_error("checksum in secret key certificate is wrong\n");
191         log_debug("stored csum=%04hx calculated csum=%04hx\n",
192                    cert->d.rsa.csum, cert->d.rsa.calc_csum );
193         return G10ERR_CHECKSUM;
194     }
195     return 0;
196 }
197 #endif /*HAVE_RSA_CIPHER*/
198
199
200
201
202 /****************
203  * Check the secret key certificate
204  */
205 int
206 check_secret_key( PKT_seckey_cert *cert )
207 {
208     if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL )
209         return check_elg( cert );
210   #ifdef HAVE_RSA_CIPHER
211     else if( cert->pubkey_algo == PUBKEY_ALGO_RSA )
212         return check_rsa( cert );
213   #endif
214     else
215         return G10ERR_PUBKEY_ALGO;
216 }
217