5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2007 - 2008 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
20 #include "silccrypto.h"
24 /*************************** Private Key Routines ***************************/
26 /* Decode OpenPGP Secret Key packet */
28 int silc_pgp_packet_private_key_decode(unsigned char *key, SilcUInt32 key_len,
29 const char *passphrase,
30 SilcUInt32 passphrase_len,
31 SilcPGPPrivateKey privkey)
33 SilcBufferStruct keybuf;
34 SilcPGPPublicKey pubkey = NULL;
35 unsigned char *iv, *salt = NULL, *dec = NULL;
36 unsigned char *dec_key;
37 SilcUInt32 iv_len = 0;
39 SilcUInt8 s2k_usage, s2k_count;
40 SilcCipher cipher = NULL;
43 SILC_LOG_DEBUG(("Parsing OpenPGP private key"));
47 silc_buffer_set(&keybuf, key, key_len);
49 SILC_LOG_HEXDUMP(("OpenPGP private key"), key, key_len);
51 pubkey = silc_calloc(1, sizeof(*pubkey));
57 /* Parse public key from the private key */
58 ret = silc_pgp_packet_public_key_decode(key, key_len, pubkey);
60 SILC_LOG_DEBUG(("Malformed private key"));
63 if (!silc_buffer_pull(&keybuf, ret))
66 if (silc_buffer_len(&keybuf) < 12)
69 /* Decode algorithm info */
70 s2k_usage = keybuf.data[0];
71 silc_buffer_pull(&keybuf, 1);
74 /* Plaintext private key */
75 SILC_LOG_DEBUG(("Private key is not encrypted"));
80 /* Encrypted, string-to-key (S2K) specifier present */
81 if (silc_buffer_unformat(&keybuf,
83 SILC_STR_UINT8(&privkey->cipher),
84 SILC_STR_UINT8(&privkey->s2k_type),
85 SILC_STR_UINT8(&privkey->s2k_hash),
87 SILC_LOG_DEBUG(("Malformed S2K specifier in private key"));
91 SILC_LOG_DEBUG(("Private key S2K type %d", privkey->s2k_type));
93 switch (privkey->s2k_type) {
94 case SILC_PGP_S2K_SIMPLE:
99 case SILC_PGP_S2K_SALTED:
101 if (silc_buffer_unformat(&keybuf,
103 SILC_STR_DATA(&salt, 8),
105 SILC_LOG_DEBUG(("Malformed S2K specifier in private key"));
110 case SILC_PGP_S2K_ITERATED_SALTED:
111 /* Iterated and salted S2K */
112 if (silc_buffer_unformat(&keybuf,
114 SILC_STR_DATA(&salt, 8),
115 SILC_STR_UINT8(&s2k_count),
117 SILC_LOG_DEBUG(("Malformed S2K specifier in private key"));
121 /* Get the iterator octet count, formula comes from the RFC */
122 privkey->s2k_count = ((SilcUInt32)16 +
123 (s2k_count & 15)) << ((s2k_count >> 4) + 6);
127 SILC_LOG_DEBUG(("Malformed private key"));
134 /* Encrypted with given algorithm */
135 privkey->cipher = keybuf.data[0];
136 silc_buffer_pull(&keybuf, 1);
140 ret_len = silc_buffer_headlen(&keybuf);
143 if (privkey->cipher) {
144 cipher = silc_pgp_cipher_alloc(privkey->cipher);
148 iv_len = silc_cipher_get_iv_len(cipher);
151 if (!silc_buffer_unformat(&keybuf,
153 SILC_STR_DATA(&iv, iv_len),
155 SILC_LOG_DEBUG(("Malformed private key, IV not present"));
160 SILC_LOG_HEXDUMP(("IV, iv_len %d", iv_len), iv, iv_len);
162 /* Generate decryption key from passphrase */
163 dec_key = silc_pgp_s2k(privkey->s2k_type, privkey->s2k_hash, passphrase,
164 passphrase_len, silc_cipher_get_key_len(cipher) / 8,
165 salt, privkey->s2k_count, NULL);
169 SILC_LOG_HEXDUMP(("S2K"), dec_key, silc_cipher_get_key_len(cipher) / 8);
171 /* Set decryption key */
172 silc_cipher_set_key(cipher, dec_key, silc_cipher_get_key_len(cipher),
174 silc_cipher_set_iv(cipher, iv);
176 /* Decrypt the private key */
177 SILC_LOG_DEBUG(("Decrypting private key"));
178 dec = silc_memdup(silc_buffer_data(&keybuf), silc_buffer_len(&keybuf));
181 silc_buffer_set(&keybuf, dec, silc_buffer_len(&keybuf));
183 if (pubkey->version >= 4) {
184 silc_cipher_decrypt(cipher, keybuf.data, keybuf.data,
185 silc_buffer_len(&keybuf), NULL);
187 /* Versions 2 and 3 */
188 /* Support may be added for these at some point. */
189 SILC_LOG_ERROR(("Version %d encrypted private keys not supported",
195 /* Verify checksum to see if decryption succeeded */
196 if (s2k_usage == 254) {
198 unsigned char cksum_hash[20], pcksum_hash[20];
200 if (!silc_buffer_push_tail(&keybuf, 20)) {
201 SILC_LOG_DEBUG(("Malformed private key, checksum not present"));
205 memcpy(pcksum_hash, keybuf.tail, 20);
207 if (!silc_hash_alloc("sha1", &sha1))
209 silc_hash_init(sha1);
210 silc_hash_update(sha1, silc_buffer_data(&keybuf),
211 silc_buffer_len(&keybuf));
212 silc_hash_final(sha1, cksum_hash);
213 silc_hash_free(sha1);
216 if (memcmp(cksum_hash, pcksum_hash, sizeof(cksum_hash))) {
217 SILC_LOG_DEBUG(("Private key checksum invalid, decryption failed"));
223 SilcUInt16 cksum = 0;
226 if (silc_buffer_unformat(&keybuf,
228 SILC_STR_UINT16(&pcksum),
230 SILC_LOG_DEBUG(("Malformed private key, checksum not present"));
234 for (i = 0; i < silc_buffer_len(&keybuf); i++)
235 cksum = (cksum + keybuf.data[i]) % 0x10000;
238 if (cksum != pcksum) {
239 SILC_LOG_DEBUG(("Private key checksum invalid, decryption failed"));
246 /* Import the algorithm private key */
247 ret = pubkey->pkcs->import_private_key(pubkey->pkcs,
248 silc_buffer_data(&keybuf),
249 silc_buffer_len(&keybuf),
250 &privkey->private_key);
252 SILC_LOG_DEBUG(("Malformed private key"));
258 privkey->public_key = pubkey;
260 return ret_len + ret;
264 silc_pgp_public_key_free(pubkey);
269 /* Decode private key from PGP packets */
271 SilcBool silc_pgp_private_key_decode(SilcList *list,
272 const char *passphrase,
273 SilcUInt32 passphrase_len,
274 SilcPGPPrivateKey *ret_private_key)
276 SilcPGPPrivateKey privkey, subkey;
279 SilcPGPPacket prv, packet;
281 SILC_LOG_DEBUG(("Parse OpenPGP private key"));
283 privkey = silc_calloc(1, sizeof(*privkey));
287 /* First packet must be private key packet */
288 prv = silc_list_get(*list);
291 if (silc_pgp_packet_get_tag(prv) != SILC_PGP_PACKET_SECKEY &&
292 silc_pgp_packet_get_tag(prv) != SILC_PGP_PACKET_SECKEY_SUB)
295 /* Parse the private key */
296 data = silc_pgp_packet_get_data(prv, &data_len);
297 if (!silc_pgp_packet_private_key_decode(data, data_len, passphrase,
298 passphrase_len, privkey))
301 /* Parse any and all packets until we hit end of the packets or next
302 private key in the list. We simply copy the raw data, and actual
303 parsing is done later if and when the packets are needed. */
304 if (silc_pgp_packet_get_tag(prv) == SILC_PGP_PACKET_SECKEY) {
305 silc_list_init(privkey->packets, struct SilcPGPPacketStruct, next);
307 /* Copy the raw private key packet */
308 packet = silc_pgp_packet_copy(prv);
310 silc_list_add(privkey->packets, packet);
312 while ((packet = silc_list_get(*list))) {
313 SILC_LOG_DEBUG(("Adding %d (%s) packet to private key",
314 silc_pgp_packet_get_tag(packet),
315 silc_pgp_packet_name(silc_pgp_packet_get_tag(packet))));
317 switch (silc_pgp_packet_get_tag(packet)) {
319 case SILC_PGP_PACKET_SECKEY:
320 /* Next private key, stop decoding. Set list pointer so that the list
321 points to the next private key. */
322 list->current = packet;
325 case SILC_PGP_PACKET_SECKEY_SUB:
326 /* Parse subkeys recursively */
327 list->current = packet;
328 if (!silc_pgp_private_key_decode(list, passphrase,
329 passphrase_len, &subkey))
332 if (!privkey->subkeys) {
333 privkey->subkeys = silc_dlist_init();
334 if (!privkey->subkeys)
337 silc_dlist_add(privkey->subkeys, subkey);
340 /* Copy packet to the private key */
341 packet = silc_pgp_packet_copy(packet);
343 silc_list_add(privkey->packets, packet);
350 *ret_private_key = privkey;
359 /* Free private key */
361 void silc_pgp_private_key_free(SilcPGPPrivateKey private_key)
364 SilcPGPPacket packet;
366 if (private_key->public_key && private_key->public_key->pkcs)
367 private_key->public_key->pkcs->private_key_free(private_key->
369 private_key->private_key);
371 silc_pgp_public_key_free(private_key->public_key);
373 if (private_key->subkeys) {
374 silc_dlist_start(private_key->subkeys);
375 while ((p = silc_dlist_get(private_key->subkeys)))
376 silc_pgp_private_key_free(p);
377 silc_dlist_uninit(private_key->subkeys);
380 silc_list_start(private_key->packets);
381 while ((packet = silc_list_get(private_key->packets)))
382 silc_pgp_packet_free(packet);
384 silc_free(private_key);