• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepim API Reference
  • KDE Home
  • Contact Us
 

libkpgp

  • sources
  • kde-4.14
  • kdepim
  • libkpgp
kpgpbaseG.cpp
Go to the documentation of this file.
1 /*
2  kpgpbaseG.cpp
3 
4  Copyright (C) 2001,2002 the KPGP authors
5  See file AUTHORS.kpgp for details
6 
7  This file is part of KPGP, the KDE PGP/GnuPG support library.
8 
9  KPGP 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; either version 2 of the License, or
12  (at your option) any later version.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software Foundation,
16  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #include "kpgpbase.h"
20 #include "kpgp.h"
21 
22 #include <klocale.h>
23 #include <kshell.h>
24 #include <kdebug.h>
25 
26 #include <QTextCodec>
27 #include <QByteArray>
28 
29 #include <algorithm>
30 #include <string.h> /* strncmp */
31 
32 namespace Kpgp {
33 
34 BaseG::BaseG()
35  : Base()
36 {
37  // determine the version of gpg (the method is equivalent to gpgme's method)
38  runGpg( "--version", 0 );
39  int eol = output.indexOf( '\n' );
40  if( eol > 0 ) {
41  int pos = output.lastIndexOf( ' ', eol - 1 );
42  if( pos != -1 ) {
43  mVersion = output.mid( pos + 1, eol - pos - 1 );
44  kDebug( 5326 ) <<"found GnuPG" << mVersion;
45  }
46  }
47 }
48 
49 
50 BaseG::~BaseG()
51 {
52 }
53 
54 
55 int
56 BaseG::encrypt( Block& block, const KeyIDList& recipients )
57 {
58  return encsign( block, recipients, 0 );
59 }
60 
61 
62 int
63 BaseG::clearsign( Block& block, const char *passphrase )
64 {
65  return encsign( block, KeyIDList(), passphrase );
66 }
67 
68 
69 int
70 BaseG::encsign( Block& block, const KeyIDList& recipients,
71  const char *passphrase )
72 {
73  QByteArray cmd;
74  int exitStatus = 0;
75 
76  if(!recipients.isEmpty() && passphrase != 0)
77  cmd = "--batch --armor --sign --encrypt --textmode";
78  else if(!recipients.isEmpty())
79  cmd = "--batch --armor --encrypt --textmode";
80  else if(passphrase != 0)
81  cmd = "--batch --escape-from --clearsign";
82  else
83  {
84  kDebug( 5326 ) <<"kpgpbase: Neither recipients nor passphrase specified.";
85  return OK;
86  }
87 
88  if(passphrase != 0)
89  cmd += addUserId();
90 
91  if(!recipients.isEmpty())
92  {
93  cmd += " --set-filename stdin";
94 
95  QByteArray pgpUser = Module::getKpgp()->user();
96  if(Module::getKpgp()->encryptToSelf() && !pgpUser.isEmpty()) {
97  cmd += " -r 0x";
98  cmd += pgpUser;
99  }
100 
101  for( KeyIDList::ConstIterator it = recipients.begin();
102  it != recipients.end(); ++it ) {
103  cmd += " -r 0x";
104  cmd += (*it);
105  }
106  }
107 
108  clear();
109  input = block.text();
110  exitStatus = runGpg(cmd.data(), passphrase);
111  if( !output.isEmpty() )
112  block.setProcessedText( output );
113  block.setError( error );
114 
115  if( exitStatus != 0 )
116  {
117  // this error message is later hopefully overwritten
118  errMsg = i18n( "Unknown error." );
119  status = ERROR;
120  }
121 
122 #if 0
123  // #### FIXME: As we check the keys ourselves the following problems
124  // shouldn't occur. Therefore I don't handle them for now.
125  // IK 01/2002
126  if(!recipients.isEmpty())
127  {
128  int index = 0;
129  bool bad = false;
130  unsigned int num = 0;
131  QByteArray badkeys = "";
132  // Examples:
133  // gpg: 0x12345678: skipped: public key not found
134  // gpg: 0x12345678: skipped: public key is disabled
135  // gpg: 0x12345678: skipped: unusable public key
136  // (expired or revoked key)
137  // gpg: 23456789: no info to calculate a trust probability
138  // (untrusted key, 23456789 is the key Id of the encryption sub key)
139  while((index = error.indexOf("skipped: ",index) ) != -1 )
140  {
141  bad = true;
142  index = error.indexOf('\'',index);
143  int index2 = error.indexOf('\'',index+1);
144  badkeys += error.mid(index, index2-index+1) + ", ";
145  num++;
146  }
147  if(bad)
148  {
149  badkeys.trimmed();
150  if(num == recipients.count())
151  errMsg = i18n("Could not find public keys matching the userid(s)\n"
152  "%1;\n"
153  "the message is not encrypted.",
154  badkeys.data() );
155  else
156  errMsg = i18n("Could not find public keys matching the userid(s)\n"
157  "%1;\n"
158  "these persons will not be able to read the message.",
159  badkeys.data() );
160  status |= MISSINGKEY;
161  status |= ERROR;
162  }
163  }
164 #endif
165  if( passphrase != 0 )
166  {
167  // Example 1 (bad passphrase, clearsign only):
168  // gpg: skipped `0x12345678': bad passphrase
169  // gpg: [stdin]: clearsign failed: bad passphrase
170  // Example 2 (bad passphrase, sign & encrypt):
171  // gpg: skipped `0x12345678': bad passphrase
172  // gpg: [stdin]: sign+encrypt failed: bad passphrase
173  // Example 3 (unusable secret key, clearsign only):
174  // gpg: skipped `0x12345678': unusable secret key
175  // gpg: [stdin]: clearsign failed: unusable secret key
176  // Example 4 (unusable secret key, sign & encrypt):
177  // gpg: skipped `0xAC0EB35D': unusable secret key
178  // gpg: [stdin]: sign+encrypt failed: unusable secret key
179  if( error.contains("bad passphrase") )
180  {
181  errMsg = i18n("Signing failed because the passphrase is wrong.");
182  status |= BADPHRASE;
183  status |= ERR_SIGNING;
184  status |= ERROR;
185  }
186  else if( error.contains("unusable secret key") )
187  {
188  errMsg = i18n("Signing failed because your secret key is unusable.");
189  status |= ERR_SIGNING;
190  status |= ERROR;
191  }
192  else if( !( status & ERROR ) )
193  {
194  //kDebug( 5326 ) <<"Base: Good Passphrase!";
195  status |= SIGNED;
196  }
197  }
198 
199  //kDebug( 5326 ) <<"status =" << status;
200  block.setStatus( status );
201  return status;
202 }
203 
204 
205 int
206 BaseG::decrypt( Block& block, const char *passphrase )
207 {
208  int index, index2;
209  int exitStatus = 0;
210 
211  clear();
212  input = block.text();
213  exitStatus = runGpg("--batch --decrypt", passphrase);
214  if( !output.isEmpty() && ( !error.contains( "gpg: quoted printable" ) ) )
215  block.setProcessedText( output );
216  block.setError( error );
217 
218  if(exitStatus == -1) {
219  errMsg = i18n("Error running gpg");
220  status = ERROR;
221  block.setStatus( status );
222  return status;
223  }
224 
225  // Example 1 (good passphrase, decryption successful):
226  // gpg: encrypted with 2048-bit ELG-E key, ID 12345678, created 2000-11-11
227  // "Foo Bar <foo@bar.xyz>"
228  //
229  // Example 2 (bad passphrase):
230  // gpg: encrypted with 1024-bit RSA key, ID 12345678, created 1991-01-01
231  // "Foo Bar <foo@bar.xyz>"
232  // gpg: public key decryption failed: bad passphrase
233  // gpg: decryption failed: secret key not available
234  //
235  // Example 3 (no secret key available):
236  // gpg: encrypted with RSA key, ID 12345678
237  // gpg: decryption failed: secret key not available
238  //
239  // Example 4 (good passphrase for second key, decryption successful):
240  // gpg: encrypted with 2048-bit ELG-E key, ID 12345678, created 2000-01-01
241  // "Foo Bar (work) <foo@bar.xyz>"
242  // gpg: public key decryption failed: bad passphrase
243  // gpg: encrypted with 2048-bit ELG-E key, ID 23456789, created 2000-02-02
244  // "Foo Bar (home) <foo@bar.xyz>"
245 
246  // Example 5: passphrase dialog cancelled by user
247  // gpg: cancelled by user
248  // gpg: encrypted with 2048-bit ELG key, ID XXXXXXXX, created 2006-11-16
249  // "Foo Bar <foobar@foo.org>"
250  // gpg: public key decryption failed: General error [..]
251  if( error.contains( "gpg: encrypted with" ) )
252  {
253  //kDebug( 5326 ) <<"kpgpbase: message is encrypted";
254  status |= ENCRYPTED;
255  if( error.contains( "\ngpg: decryption failed" ) )
256  {
257  if( ( index = error.indexOf( "bad passphrase" ) ) != -1 )
258  {
259  if( passphrase != 0 )
260  {
261  errMsg = i18n( "Bad passphrase; could not decrypt." );
262  kDebug( 5326 ) <<"Base: passphrase is bad";
263  status |= BADPHRASE;
264  status |= ERROR;
265  }
266  else
267  {
268  // Search backwards the user ID of the needed key
269  index2 = error.lastIndexOf('"', index) - 1;
270  index = error.lastIndexOf(" \"", index2) + 7;
271  // The conversion from UTF8 is necessary because gpg stores and
272  // prints user IDs in UTF8
273  block.setRequiredUserId( QString::fromUtf8( error.mid( index, index2 - index + 1 ) ) );
274  kDebug( 5326 ) <<"Base: key needed is \"" << block.requiredUserId() <<"\"!";
275  }
276  }
277  else if( error.contains( "secret key not available" ) )
278  {
279  // no secret key fitting this message
280  status |= NO_SEC_KEY;
281  status |= ERROR;
282  errMsg = i18n("You do not have the secret key needed to decrypt this message.");
283  kDebug( 5326 ) <<"Base: no secret key for this message";
284  }
285  else if( error.contains( "cancelled by user" ) )
286  {
287  status |= CANCEL;
288  status |= ERROR;
289  errMsg = i18n("The passphrase dialog was cancelled.");
290  kDebug( 5326 ) << errMsg;
291  }
292  }
293  // check for persons
294 #if 0
295  // ##### FIXME: This information is anyway currently not used
296  // I'll change it to always determine the recipients.
297  index = error.indexOf("can only be read by:");
298  if(index != -1)
299  {
300  index = error.indexOf('\n',index);
301  int end = error.indexOf("\n\n",index);
302 
303  mRecipients.clear();
304  while( (index2 = error.indexOf('\n',index+1)) <= end )
305  {
306  QByteArray item = error.mid(index+1,index2-index-1);
307  item.trimmed();
308  mRecipients.append(item);
309  index = index2;
310  }
311  }
312 #endif
313  }
314 
315  // Example 1 (unknown signature key):
316  // gpg: Signature made Wed 02 Jan 2002 11:26:33 AM CET using DSA key ID 2E250C64
317  // gpg: Can't check signature: public key not found
318  if( ( index = error.indexOf("Signature made") ) != -1 )
319  {
320  //kDebug( 5326 ) <<"Base: message is signed";
321  status |= SIGNED;
322  // get signature date and signature key ID
323  // Example: Signature made Sun 06 May 2001 03:49:27 PM CEST using DSA key ID 12345678
324  index2 = error.indexOf("using", index+15);
325  block.setSignatureDate( error.mid(index+15, index2-(index+15)-1) );
326  kDebug( 5326 ) <<"Message was signed on '" << block.signatureDate() <<"'";
327  index2 = error.indexOf("key ID ", index2) + 7;
328  block.setSignatureKeyId( error.mid(index2,8) );
329  kDebug( 5326 ) <<"Message was signed with key '" << block.signatureKeyId() <<"'";
330  // move index to start of next line
331  index = error.indexOf('\n', index2)+1;
332 
333  if ((error.indexOf("Key matching expected", index) != -1 )
334  || (error.indexOf("Can't check signature", index) != -1 ))
335  {
336  status |= UNKNOWN_SIG;
337  status |= GOODSIG;
338  block.setSignatureUserId( QString() );
339  }
340  else if( error.indexOf("Good signature", index) != -1 )
341  {
342  status |= GOODSIG;
343  // get the primary user ID of the signer
344  index = error.indexOf('"',index);
345  index2 = error.indexOf('\n',index+1);
346  index2 = error.lastIndexOf('"', index2-1);
347  block.setSignatureUserId( QLatin1String(error.mid( index+1, index2-index-1 )) );
348  }
349  else if( error.indexOf("BAD signature", index) != -1 )
350  {
351  //kDebug( 5326 ) <<"BAD signature";
352  status |= ERROR;
353  // get the primary user ID of the signer
354  index = error.indexOf('"',index);
355  index2 = error.indexOf('\n',index+1);
356  index2 = error.lastIndexOf('"', index2-1);
357  block.setSignatureUserId( QLatin1String(error.mid( index+1, index2-index-1 )) );
358  }
359  else if( error.indexOf("Can't find the right public key", index) != -1 )
360  {
361  // #### fix this hack
362  // I think this can't happen anymore because if the pubring is missing
363  // the current GnuPG creates a new empty one.
364  status |= UNKNOWN_SIG;
365  status |= GOODSIG; // this is a hack...
366  block.setSignatureUserId( i18n("??? (file ~/.gnupg/pubring.gpg not found)") );
367  }
368  else
369  {
370  status |= ERROR;
371  block.setSignatureUserId( QString() );
372  }
373  }
374  //kDebug( 5326 ) <<"status =" << status;
375  block.setStatus( status );
376  return status;
377 }
378 
379 
380 Key*
381 BaseG::readPublicKey( const KeyID& keyID,
382  const bool readTrust /* = false */,
383  Key* key /* = 0 */ )
384 {
385  int exitStatus = 0;
386 
387  status = 0;
388  if( readTrust )
389  exitStatus = runGpg( QByteArray(QByteArray("--batch --list-public-keys --with-fingerprint --with-colons --fixed-list-mode 0x") + keyID), 0, true );
390  else
391  exitStatus = runGpg( QByteArray(QByteArray("--batch --list-public-keys --with-fingerprint --with-colons --fixed-list-mode --no-expensive-trust-checks 0x") + keyID), 0, true );
392 
393  if(exitStatus != 0) {
394  status = ERROR;
395  return 0;
396  }
397 
398  int offset;
399  // search start of key data
400  if( !strncmp( output.data(), "pub:", 4 ) )
401  offset = 0;
402  else {
403  offset = output.indexOf( "\npub:" );
404  if( offset == -1 )
405  return 0;
406  else
407  offset++;
408  }
409 
410  key = parseKeyData( output, offset, key );
411 
412  return key;
413 }
414 
415 
416 KeyList
417 BaseG::publicKeys( const QStringList & patterns )
418 {
419  int exitStatus = 0;
420 
421  // the option --with-colons should be used for interprocess communication
422  // with gpg (according to Werner Koch)
423  QByteArray cmd = "--batch --list-public-keys --with-fingerprint --with-colons "
424  "--fixed-list-mode --no-expensive-trust-checks";
425  for ( QStringList::ConstIterator it = patterns.begin();
426  it != patterns.end(); ++it ) {
427  cmd += ' ';
428  cmd += KShell::quoteArg( *it ).toLocal8Bit();
429  }
430  status = 0;
431  exitStatus = runGpg( cmd, 0, true );
432 
433  if(exitStatus != 0) {
434  status = ERROR;
435  return KeyList();
436  }
437 
438  // now we need to parse the output for public keys
439  KeyList publicKeys = parseKeyList(output, false);
440 
441  // sort the list of public keys
442  std::sort( publicKeys.begin(), publicKeys.end(), KeyCompare );
443 
444  return publicKeys;
445 }
446 
447 
448 KeyList
449 BaseG::secretKeys( const QStringList & patterns )
450 {
451  int exitStatus = 0;
452 
453  // the option --with-colons should be used for interprocess communication
454  // with gpg (according to Werner Koch)
455  QByteArray cmd = "--batch --list-secret-keys --with-fingerprint --with-colons "
456  "--fixed-list-mode";
457  for ( QStringList::ConstIterator it = patterns.begin();
458  it != patterns.end(); ++it ) {
459  cmd += ' ';
460  cmd += KShell::quoteArg( *it ).toLocal8Bit();
461  }
462  status = 0;
463  exitStatus = runGpg( cmd, 0, true );
464 
465  if(exitStatus != 0) {
466  status = ERROR;
467  return KeyList();
468  }
469 
470  // now we need to parse the output for secret keys
471  KeyList secretKeys = parseKeyList(output, true);
472 
473  // sort the list of secret keys
474  std::sort( secretKeys.begin(), secretKeys.end(), KeyCompare );
475 
476  return secretKeys;
477 }
478 
479 
480 int
481 BaseG::signKey(const KeyID& keyID, const char *passphrase)
482 {
483  QByteArray cmd;
484  int exitStatus = 0;
485 
486  cmd = "--batch";
487  cmd += addUserId();
488  cmd += " --sign-key 0x";
489  cmd += keyID;
490 
491  status = 0;
492  exitStatus = runGpg(cmd.data(), passphrase);
493 
494  if (exitStatus != 0)
495  status = ERROR;
496 
497  return status;
498 }
499 
500 
501 QByteArray
502 BaseG::getAsciiPublicKey(const KeyID& keyID)
503 {
504  int exitStatus = 0;
505 
506  if (keyID.isEmpty())
507  return QByteArray();
508 
509  status = 0;
510  exitStatus = runGpg(QByteArray(QByteArray("--batch --armor --export 0x") + keyID), 0, true);
511 
512  if(exitStatus != 0) {
513  status = ERROR;
514  return QByteArray();
515  }
516 
517  return output;
518 }
519 
520 
521 Key*
522 BaseG::parseKeyData( const QByteArray& output, int& offset, Key* key /* = 0 */ )
523 // This function parses the data for a single key which is output by GnuPG
524 // with the following command line arguments:
525 // --batch --list-public-keys --with-fingerprint --with-colons
526 // --fixed-list-mode [--no-expensive-trust-checks]
527 // It expects the key data to start at offset and returns the start of
528 // the next key's data in offset.
529 // Subkeys are currently ignored.
530 {
531  int index = offset;
532 
533  if( ( strncmp( output.data() + offset, "pub:", 4 ) != 0 )
534  && ( strncmp( output.data() + offset, "sec:", 4 ) != 0 ) ) {
535  return 0;
536  }
537 
538  if( key == 0 )
539  key = new Key();
540  else
541  key->clear();
542 
543  QByteArray keyID;
544  bool firstKey = true;
545 
546  while( true )
547  {
548  int eol;
549  // search the end of the current line
550  if( ( eol = output.indexOf( '\n', index ) ) == -1 )
551  break;
552 
553  bool bIsPublicKey = false;
554  if( ( bIsPublicKey = !strncmp( output.data() + index, "pub:", 4 ) )
555  || !strncmp( output.data() + index, "sec:", 4 ) )
556  { // line contains primary key data
557  // Example: pub:f:1024:17:63CB691DFAEBD5FC:860451781::379:-:::scESC:
558 
559  // abort parsing if we found the start of the next key
560  if( !firstKey )
561  break;
562  firstKey = false;
563 
564  key->setSecret( !bIsPublicKey );
565 
566  Subkey *subkey = new Subkey( QByteArray(), !bIsPublicKey );
567 
568  int pos = index + 4; // begin of 2nd field
569  int pos2 = output.indexOf( ':', pos );
570  for( int field = 2; field <= 12; field++ )
571  {
572  switch( field )
573  {
574  case 2: // the calculated trust
575  if( pos2 > pos )
576  {
577  switch( output[pos] )
578  {
579  case 'o': // unknown (this key is new to the system)
580  break;
581  case 'i': // the key is invalid, e.g. missing self-signature
582  subkey->setInvalid( true );
583  key->setInvalid( true );
584  break;
585  case 'd': // the key has been disabled
586  subkey->setDisabled( true );
587  key->setDisabled( true );
588  break;
589  case 'r': // the key has been revoked
590  subkey->setRevoked( true );
591  key->setRevoked( true );
592  break;
593  case 'e': // the key has expired
594  subkey->setExpired( true );
595  key->setExpired( true );
596  break;
597  case '-': // undefined (no path leads to the key)
598  case 'q': // undefined (no trusted path leads to the key)
599  case 'n': // don't trust this key at all
600  case 'm': // the key is marginally trusted
601  case 'f': // the key is fully trusted
602  case 'u': // the key is ultimately trusted (secret key available)
603  // These values are ignored since we determine the key trust
604  // from the trust values of the user ids.
605  break;
606  default:
607  kDebug( 5326 ) <<"Unknown trust value";
608  }
609  }
610  break;
611  case 3: // length of key in bits
612  if( pos2 > pos )
613  subkey->setKeyLength( output.mid( pos, pos2-pos ).toUInt() );
614  break;
615  case 4: // the key algorithm
616  if( pos2 > pos )
617  subkey->setKeyAlgorithm( output.mid( pos, pos2-pos ).toUInt() );
618  break;
619  case 5: // the long key id
620  keyID = output.mid( pos, pos2-pos );
621  subkey->setKeyID( keyID );
622  break;
623  case 6: // the creation date (in seconds since 1970-01-01 00:00:00)
624  if( pos2 > pos )
625  subkey->setCreationDate( QString(QLatin1String(output.mid( pos, pos2-pos ))).toLong() );
626  break;
627  case 7: // the expiration date (in seconds since 1970-01-01 00:00:00)
628  if( pos2 > pos )
629  subkey->setExpirationDate( QString(QLatin1String(output.mid( pos, pos2-pos ))).toLong() );
630  else
631  subkey->setExpirationDate( -1 ); // key expires never
632  break;
633  case 8: // local ID (ignored)
634  case 9: // Ownertrust (ignored for now)
635  case 10: // User-ID (always empty in --fixed-list-mode)
636  case 11: // signature class (always empty except for key signatures)
637  break;
638  case 12: // key capabilities
639  for( int i=pos; i<pos2; ++i )
640  switch( output[i] )
641  {
642  case 'e':
643  subkey->setCanEncrypt( true );
644  break;
645  case 's':
646  subkey->setCanSign( true );
647  break;
648  case 'c':
649  subkey->setCanCertify( true );
650  break;
651  case 'E':
652  key->setCanEncrypt( true );
653  break;
654  case 'S':
655  key->setCanSign( true );
656  break;
657  case 'C':
658  key->setCanCertify( true );
659  break;
660  default:
661  kDebug( 5326 ) <<"Unknown key capability";
662  }
663  break;
664  }
665  pos = pos2 + 1;
666  pos2 = output.indexOf( ':', pos );
667  }
668  key->addSubkey( subkey );
669  }
670  else if( !strncmp( output.data() + index, "uid:", 4 ) )
671  { // line contains a user id
672  // Example: uid:f::::::::Philip R. Zimmermann <prz@pgp.com>:
673 
674  UserID *userID = new UserID( QLatin1String("") );
675 
676  int pos = index + 4; // begin of 2nd field
677  int pos2 = output.indexOf( ':', pos );
678  for( int field=2; field <= 10; field++ )
679  {
680  switch( field )
681  {
682  case 2: // the calculated trust
683  if( pos2 > pos )
684  {
685  switch( output[pos] )
686  {
687  case 'i': // the user id is invalid, e.g. missing self-signature
688  userID->setInvalid( true );
689  break;
690  case 'r': // the user id has been revoked
691  userID->setRevoked( true );
692  break;
693  case '-': // undefined (no path leads to the key)
694  case 'q': // undefined (no trusted path leads to the key)
695  userID->setValidity( KPGP_VALIDITY_UNDEFINED );
696  break;
697  case 'n': // don't trust this key at all
698  userID->setValidity( KPGP_VALIDITY_NEVER );
699  break;
700  case 'm': // the key is marginally trusted
701  userID->setValidity( KPGP_VALIDITY_MARGINAL );
702  break;
703  case 'f': // the key is fully trusted
704  userID->setValidity( KPGP_VALIDITY_FULL );
705  break;
706  case 'u': // the key is ultimately trusted (secret key available)
707  userID->setValidity( KPGP_VALIDITY_ULTIMATE );
708  break;
709  default:
710  kDebug( 5326 ) <<"Unknown trust value";
711  }
712  }
713  break;
714  case 3: // these fields are empty
715  case 4:
716  case 5:
717  case 6:
718  case 7:
719  case 8:
720  case 9:
721  break;
722  case 10: // User-ID
723  QByteArray uid = output.mid( pos, pos2-pos );
724  // replace "\xXX" with the corresponding character;
725  // other escaped characters, i.e. \n, \r etc., are ignored
726  // because they shouldn't appear in user IDs
727  for ( int idx = 0 ; (idx = uid.indexOf( "\\x", idx ) != -1) ; ++idx ) {
728  char str[2] = "x";
729  str[0] = (char) QString( QLatin1String(uid.mid( idx + 2, 2 )) ).toShort( 0, 16 );
730  uid.replace( idx, 4, str );
731  }
732  QString uidString = QString::fromUtf8( uid.data() );
733  // check whether uid was utf-8 encoded
734  bool isUtf8 = true;
735  for ( int i = 0; i + 1 < uidString.length(); ++i ) {
736  if ( uidString[i].unicode() == 0xdbff &&
737  uidString[i+1].row() == 0xde ) {
738  // we found a non-Unicode character (see QString::fromUtf8())
739  isUtf8 = false;
740  break;
741  }
742  }
743  if( !isUtf8 ) {
744  // The user id isn't utf-8 encoded. It was most likely
745  // created with PGP which either used latin1 or koi8-r.
746  kDebug( 5326 ) <<"User Id '" << uid
747  << "' doesn't seem to be utf-8 encoded.";
748 
749  // We determine the ratio between non-ASCII and ASCII chars.
750  // A koi8-r user id should have lots of non-ASCII chars.
751  int nonAsciiCount = 0, asciiCount = 0;
752 
753  // We only look at the first part of the user id (i. e. everything
754  // before the email address resp. before a comment)
755  for( signed char* ch = (signed char*)uid.data();
756  *ch && ( *ch != '(' ) && ( *ch != '<' );
757  ++ch ) {
758  if( ( ( *ch >= 'A' ) && ( *ch <= 'Z' ) )
759  || ( ( *ch >= 'a' ) && ( *ch <= 'z' ) ) )
760  ++asciiCount;
761  else if( *ch < 0 )
762  ++nonAsciiCount;
763  }
764  kDebug( 5326 ) <<"ascii-nonAscii ratio :" << asciiCount
765  << ":" << nonAsciiCount;
766  if( nonAsciiCount > asciiCount ) {
767  // assume koi8-r encoding
768  kDebug( 5326 ) <<"Assume koi8-r encoding.";
769  QTextCodec *codec = QTextCodec::codecForName("KOI8-R");
770  uidString = codec->toUnicode( uid.data() );
771  // check the case of the first two characters to find out
772  // whether the user id is probably CP1251 encoded (for some
773  // reason in CP1251 the lower case characters have smaller
774  // codes than the upper case characters, so if the first char
775  // of the koi8-r decoded user id is lower case and the second
776  // char is upper case then it's likely that the user id is
777  // CP1251 encoded)
778  if( ( uidString.length() >= 2 )
779  && ( uidString[0].toLower() == uidString[0] )
780  && ( uidString[1].toUpper() == uidString[1] ) ) {
781  // koi8-r decoded user id has inverted case, so assume
782  // CP1251 encoding
783  kDebug( 5326 ) <<"No, it doesn't seem to be koi8-r."
784  "Use CP 1251 instead.";
785  QTextCodec *codec = QTextCodec::codecForName("CP1251");
786  uidString = codec->toUnicode( uid.data() );
787  }
788  }
789  else {
790  // assume latin1 encoding
791  kDebug( 5326 ) <<"Assume latin1 encoding.";
792  uidString = QString::fromLatin1( uid.data() );
793  }
794  }
795  userID->setText( uidString );
796  break;
797  }
798  pos = pos2 + 1;
799  pos2 = output.indexOf( ':', pos );
800  }
801 
802  // user IDs are printed in UTF-8 by gpg (if one uses --with-colons)
803  key->addUserID( userID );
804  }
805  else if( !strncmp( output.data() + index, "fpr:", 4 ) )
806  { // line contains a fingerprint
807  // Example: fpr:::::::::17AFBAAF21064E513F037E6E63CB691DFAEBD5FC:
808 
809  if (key == 0) // invalid key data
810  break;
811 
812  // search the fingerprint (it's in the 10th field)
813  int pos = index + 4;
814  for( int i = 0; i < 8; ++i )
815  pos = output.indexOf( ':', pos ) + 1;
816  int pos2 = output.indexOf( ':', pos );
817 
818  key->setFingerprint( keyID, output.mid( pos, pos2-pos ) );
819  }
820  index = eol + 1;
821  }
822 
823  //kDebug( 5326 ) <<"finished parsing key data";
824 
825  offset = index;
826 
827  return key;
828 }
829 
830 
831 KeyList
832 BaseG::parseKeyList( const QByteArray& output, bool secretKeys )
833 {
834  KeyList keys;
835  Key *key = 0;
836  int offset;
837 
838  // search start of key data
839  if( !strncmp( output.data(), "pub:", 4 )
840  || !strncmp( output.data(), "sec:", 4 ) )
841  offset = 0;
842  else {
843  if( secretKeys )
844  offset = output.indexOf( "\nsec:" );
845  else
846  offset = output.indexOf( "\npub:" );
847  if( offset == -1 )
848  return keys;
849  else
850  offset++;
851  }
852 
853  do {
854  key = parseKeyData( output, offset );
855 
856  if( key != 0 )
857  keys.append( key );
858  }
859  while( key != 0 );
860 
861  //kDebug( 5326 ) <<"finished parsing keys";
862 
863  return keys;
864 }
865 
866 
867 } // namespace Kpgp
Kpgp::BaseG::~BaseG
virtual ~BaseG()
Definition: kpgpbaseG.cpp:50
Kpgp::KeyList
QList< Key * > KeyList
Definition: kpgpkey.h:843
QByteArray::toUInt
uint toUInt(bool *ok, int base) const
Kpgp::Key::setCanCertify
void setCanCertify(const bool canCertify)
Sets the flag if the key can be used to certify keys to canCertify .
Definition: kpgpkey.h:762
Kpgp::BaseG::publicKeys
virtual KeyList publicKeys(const QStringList &patterns=QStringList())
Returns the list of public keys in the users public keyring.
Definition: kpgpbaseG.cpp:417
QString::toShort
short toShort(bool *ok, int base) const
Kpgp::Block::setError
void setError(const QByteArray &str)
Definition: kpgpblock.h:222
Kpgp::Key::setFingerprint
void setFingerprint(const KeyID &keyID, const QByteArray &fpr)
Sets the fingerprint of the given subkey to fpr .
Definition: kpgpkey.cpp:252
Kpgp::Block::setSignatureDate
void setSignatureDate(const QByteArray &date)
Definition: kpgpblock.h:278
Kpgp::BaseG::signKey
virtual int signKey(const KeyID &keyID, const char *passphrase)
Signs the given key with the currently set user key.
Definition: kpgpbaseG.cpp:481
QByteArray::trimmed
QByteArray trimmed() const
QByteArray
Kpgp::Base::output
QByteArray output
Definition: kpgpbase.h:97
Kpgp::NO_SEC_KEY
Definition: kpgpblock.h:56
QByteArray::lastIndexOf
int lastIndexOf(char ch, int from) const
Kpgp::Module::user
const KeyID user() const
Returns the actual key ID of the currently set key.
Definition: kpgp.cpp:160
Kpgp::BaseG::encrypt
virtual int encrypt(Block &block, const KeyIDList &recipients)
Encrypts the message with the given keys.
Definition: kpgpbaseG.cpp:56
Kpgp::KPGP_VALIDITY_ULTIMATE
Definition: kpgpkey.h:39
Kpgp::Key::setCanEncrypt
void setCanEncrypt(const bool canEncrypt)
Sets the flag if the key can be used to encrypt data to canEncrypt .
Definition: kpgpkey.h:752
QByteArray::isEmpty
bool isEmpty() const
Kpgp::KPGP_VALIDITY_FULL
Definition: kpgpkey.h:38
Kpgp::Block
Definition: kpgpblock.h:89
Kpgp::Base::addUserId
QByteArray addUserId()
Definition: kpgpbase.cpp:688
Kpgp::BaseG::secretKeys
virtual KeyList secretKeys(const QStringList &patterns=QStringList())
Returns the list of secret keys in the users secret keyring.
Definition: kpgpbaseG.cpp:449
Kpgp::BaseG::readPublicKey
virtual Key * readPublicKey(const KeyID &keyID, const bool readTrust=false, Key *key=0)
Reads the key data for the given key and returns it.
Definition: kpgpbaseG.cpp:381
Kpgp::Base::errMsg
QString errMsg
Definition: kpgpbase.h:99
Kpgp::BADPHRASE
Definition: kpgpblock.h:54
Kpgp::Block::setRequiredUserId
void setRequiredUserId(const QString &userId)
Definition: kpgpblock.h:302
Kpgp::Module::getKpgp
static Kpgp::Module * getKpgp()
return the actual pgp object
Definition: kpgp.cpp:1067
Kpgp::Key::setSecret
void setSecret(const bool secret)
Sets the flag if the key is a secret key to secret .
Definition: kpgpkey.h:727
Kpgp::Base::mVersion
QByteArray mVersion
Definition: kpgpbase.h:101
Kpgp::Key::setDisabled
void setDisabled(const bool disabled)
Sets the flag if the key has been disabled to disabled .
Definition: kpgpkey.h:742
QByteArray::indexOf
int indexOf(char ch, int from) const
QList::count
int count(const T &value) const
Kpgp::KeyCompare
bool KeyCompare(Key *left, Key *right)
Definition: kpgpkey.h:845
QString::fromUtf8
QString fromUtf8(const char *str, int size)
Kpgp::BaseG::decrypt
virtual int decrypt(Block &block, const char *passphrase=0)
Decrypts the message.
Definition: kpgpbaseG.cpp:206
Kpgp::Block::setSignatureUserId
void setSignatureUserId(const QString &userId)
Definition: kpgpblock.h:254
kpgpbase.h
Kpgp::Key::setInvalid
void setInvalid(const bool invalid)
Sets the flag if the key is invalid to invalid .
Definition: kpgpkey.h:747
Kpgp::CANCEL
Definition: kpgpblock.h:58
QList::isEmpty
bool isEmpty() const
Kpgp::GOODSIG
Definition: kpgpblock.h:51
Kpgp::Key::addUserID
void addUserID(const QString &uid, const Validity validity=KPGP_VALIDITY_UNKNOWN, const bool revoked=false, const bool invalid=false)
Adds a user ID with the given values to the key if uid isn't an empty string.
Definition: kpgpkey.cpp:200
QByteArray::replace
QByteArray & replace(int pos, int len, const char *after)
Kpgp::KPGP_VALIDITY_UNDEFINED
Definition: kpgpkey.h:35
QString
QList
Kpgp::KeyIDList
Definition: kpgpkey.h:57
Kpgp::ENCRYPTED
Definition: kpgpblock.h:49
Kpgp::OK
Definition: kpgpblock.h:46
QTextCodec
QByteArray::mid
QByteArray mid(int pos, int len) const
Kpgp::Block::signatureDate
QByteArray signatureDate() const
date of the signature WARNING: Will most likely be changed to QDateTime
Definition: kpgpblock.h:272
QStringList
Kpgp::Block::signatureKeyId
QByteArray signatureKeyId() const
keyID of signer
Definition: kpgpblock.h:260
QByteArray::append
QByteArray & append(char ch)
QList::end
iterator end()
Kpgp::KPGP_VALIDITY_MARGINAL
Definition: kpgpkey.h:37
Kpgp::BaseG::clearsign
virtual int clearsign(Block &block, const char *passphrase)
Clearsigns the message with the currently set key.
Definition: kpgpbaseG.cpp:63
QString::toLong
long toLong(bool *ok, int base) const
Kpgp::Block::setSignatureKeyId
void setSignatureKeyId(const QByteArray &keyId)
Definition: kpgpblock.h:266
Kpgp::MISSINGKEY
Definition: kpgpblock.h:57
Kpgp::Block::text
QByteArray text() const
Definition: kpgpblock.h:193
Kpgp::Base::runGpg
virtual int runGpg(const char *cmd, const char *passphrase=0, bool onlyReadFromGnuPG=false)
Definition: kpgpbase.cpp:390
QLatin1String
Kpgp::Key::addSubkey
void addSubkey(const KeyID &keyID, const bool secret=false)
Adds a subkey with the given values to the key if keyID isn't an empty string.
Definition: kpgpkey.cpp:222
Kpgp::BaseG::BaseG
BaseG()
Definition: kpgpbaseG.cpp:34
Kpgp::Base
Definition: kpgpbase.h:30
Kpgp::Base::input
QByteArray input
Definition: kpgpbase.h:96
Kpgp::Key::setExpired
void setExpired(const bool expired)
Sets the flag if the key has expired to expired .
Definition: kpgpkey.h:737
QTextCodec::codecForName
QTextCodec * codecForName(const QByteArray &name)
Kpgp::Block::setProcessedText
void setProcessedText(const QByteArray &str)
Definition: kpgpblock.h:209
QList< KeyID >::ConstIterator
typedef ConstIterator
QByteArray::contains
bool contains(char ch) const
Kpgp::Key::setRevoked
void setRevoked(const bool revoked)
Sets the flag if the key has been revoked to revoked .
Definition: kpgpkey.h:732
Kpgp::KPGP_VALIDITY_NEVER
Definition: kpgpkey.h:36
QString::length
int length() const
QByteArray::data
char * data()
Kpgp::Key
This class is used to store information about a PGP key.
Definition: kpgpkey.h:506
Kpgp::ERROR
Definition: kpgpblock.h:48
QString::fromLatin1
QString fromLatin1(const char *str, int size)
Kpgp::UNKNOWN_SIG
Definition: kpgpblock.h:53
Kpgp::BaseG::encsign
virtual int encsign(Block &block, const KeyIDList &recipients, const char *passphrase=0)
Encrypts and signs the message with the given keys.
Definition: kpgpbaseG.cpp:70
Kpgp::Base::clear
virtual void clear()
Definition: kpgpbase.cpp:56
Kpgp::Base::error
QByteArray error
Definition: kpgpbase.h:98
Kpgp::SIGNED
Definition: kpgpblock.h:50
kpgp.h
Kpgp::Base::status
int status
Definition: kpgpbase.h:103
Kpgp::BaseG::getAsciiPublicKey
virtual QByteArray getAsciiPublicKey(const KeyID &keyID)
Returns the ascii armored data of the public key with the given key id.
Definition: kpgpbaseG.cpp:502
Kpgp::Key::setCanSign
void setCanSign(const bool canSign)
Sets the flag if the key can be used to sign data to canSign .
Definition: kpgpkey.h:757
Kpgp::ERR_SIGNING
Definition: kpgpblock.h:52
Kpgp::Block::requiredUserId
QString requiredUserId() const
Definition: kpgpblock.h:296
QList::begin
iterator begin()
QTextCodec::toUnicode
QString toUnicode(const QByteArray &a) const
Kpgp::Key::clear
void clear()
Clears/resets all key data.
Definition: kpgpkey.cpp:117
Kpgp::Block::setStatus
void setStatus(const int status)
Definition: kpgpblock.h:234
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:32:22 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

libkpgp

Skip menu "libkpgp"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer
  • pimprint

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal