File indexing completed on 2024-04-21 05:50:42

0001 /*
0002     SPDX-FileCopyrightText: 2008-2022 Rolf Eike Beer <kde@opensource.sf-tec.de>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #include "kgpggeneratekey.h"
0007 
0008 #include "gpgproc.h"
0009 
0010 #include <KEmailAddress>
0011 #include <KLocalizedString>
0012 #include <QApplication>
0013 
0014 KGpgGenerateKey::KGpgGenerateKey(QObject *parent, const QString &name, const QString &email, const QString &comment,
0015         const KgpgCore::KgpgKeyAlgo algorithm, const uint size, const unsigned int expire,
0016         const char expireunit, const KgpgCore::KgpgSubKeyType capabilities)
0017     : KGpgTransaction(parent),
0018     m_name(name),
0019     m_email(email),
0020     m_comment(comment),
0021     m_algorithm(algorithm),
0022     m_capabilities(capabilities),
0023     m_size(size),
0024     m_expire(expire),
0025     m_expireunit(expireunit)
0026 {
0027     Q_ASSERT((expireunit == 'd') || (expireunit == 'w') ||
0028             (expireunit == 'm') || (expireunit == 'y'));
0029 
0030     addArguments( { QLatin1String("--status-fd=1"),
0031             QLatin1String("--command-fd=0"),
0032             QLatin1String("--no-verbose"),
0033             QLatin1String("--gen-key"),
0034             QLatin1String("--batch")
0035             } );
0036 
0037     getProcess()->setOutputChannelMode(KProcess::SeparateChannels);
0038 }
0039 
0040 bool
0041 KGpgGenerateKey::preStart()
0042 {
0043     if (!m_email.isEmpty() && !KEmailAddress::isValidSimpleAddress(m_email)) {
0044         setSuccess(TS_INVALID_EMAIL);
0045         return false;
0046     }
0047 
0048     m_fingerprint.clear();
0049 
0050     setSuccess(TS_MSG_SEQUENCE);
0051 
0052     setDescription(i18n("Generating New Key for %1", m_name));
0053 
0054     return true;
0055 }
0056 
0057 void
0058 KGpgGenerateKey::postStart()
0059 {
0060     QByteArray keymessage = "Key-Type: ";
0061 
0062     switch (m_algorithm) {
0063     case KgpgCore::ALGO_RSA:
0064         keymessage.append("RSA");
0065         break;
0066     case KgpgCore::ALGO_RSA_RSA:
0067         keymessage.append("RSA\nSubkey-Type: RSA");
0068         break;
0069     case KgpgCore::ALGO_DSA_ELGAMAL:
0070         keymessage.append("DSA\nSubkey-Type: ELG-E");
0071         break;
0072     default:
0073         Q_ASSERT(m_algorithm == KgpgCore::ALGO_RSA);
0074         return;
0075     }
0076 
0077     const QByteArray keylen = QByteArray::number(m_size);
0078 
0079     keymessage.append("\nKey-Length: ");
0080     keymessage.append(keylen);
0081     keymessage.append("\nSubkey-Length: ");
0082     keymessage.append(keylen);
0083     keymessage.append("\nName-Real: ");
0084     keymessage.append(m_name.toUtf8());
0085 
0086     if (!m_email.isEmpty()) {
0087         keymessage.append("\nName-Email: ");
0088         keymessage.append(m_email.toLatin1());
0089     }
0090 
0091     if (!m_comment.isEmpty()) {
0092         keymessage.append("\nName-Comment: ");
0093         keymessage.append(m_comment.toUtf8());
0094     }
0095 
0096     if (m_expire != 0) {
0097         keymessage.append("\nExpire-Date: ");
0098         keymessage.append(QByteArray::number(m_expire));
0099         keymessage.append(m_expireunit);
0100     }
0101 
0102     if (m_capabilities) {
0103         keymessage.append("\nKey-Usage: ");
0104         QStringList usage;
0105 #if 0
0106         // GnuPG always adds cert, but it does not allow this to be
0107         // explicitly specified
0108         if (m_capabilities & KgpgCore::SKT_CERTIFICATION)
0109             usage << QLatin1String("cert");
0110 #endif
0111         if (m_capabilities & KgpgCore::SKT_AUTHENTICATION)
0112             usage << QLatin1String("auth");
0113         if (m_capabilities & KgpgCore::SKT_ENCRYPTION)
0114             usage << QLatin1String("encrypt");
0115         if (m_capabilities & KgpgCore::SKT_SIGNATURE)
0116             usage << QLatin1String("sign");
0117         keymessage.append(usage.join(QLatin1Char(' ')).toLatin1());
0118     }
0119 
0120     keymessage.append("\nPassphrase: ");
0121     write(keymessage, false);
0122 
0123     QString passdlgmessage;
0124     if (!m_email.isEmpty()) {
0125         passdlgmessage = i18n("<p><b>Enter passphrase for %1 &lt;%2&gt;</b>:<br />Passphrase should include non alphanumeric characters and random sequences.</p>",
0126                 m_name, m_email);
0127     } else {
0128         passdlgmessage = i18n("<p><b>Enter passphrase for %1</b>:<br />Passphrase should include non alphanumeric characters and random sequences.</p>",
0129                 m_name);
0130     }
0131 
0132     QApplication::restoreOverrideCursor();
0133     askNewPassphrase(passdlgmessage);
0134 }
0135 
0136 bool
0137 KGpgGenerateKey::nextLine(const QString &line)
0138 {
0139     QString msg = i18n("Generating Key");
0140 
0141     if (!line.startsWith(QLatin1String("[GNUPG:] ")))
0142         return false;
0143 
0144     int result = false;
0145 
0146     if (line.contains(QLatin1String( "PROGRESS" ))) {
0147         const QStringList parts = line.mid(18).split(QLatin1Char(' '));
0148 
0149         if (parts.count() >= 4) {
0150             const QString p0(parts.at(0));
0151             if (p0 == QLatin1String( "primegen" )) {
0152                 msg = i18n("Generating prime numbers");
0153             } else if (p0 == QLatin1String( "pk_dsa" )) {
0154                 msg = i18n("Generating DSA key");
0155             } else if (p0 == QLatin1String( "pk_elg" )) {
0156                 msg = i18n("Generating ElGamal key");
0157             } else if (p0 == QLatin1String( "need_entropy" )) {
0158                 msg = i18n("Waiting for entropy");
0159 
0160                 // This message is currenlty not displayed. Nevertheless it's
0161                 // included here so string freeze is not broken if it will be
0162                 // displayed later on.
0163                 QString msglong = i18n("The entropy pool ran empty. The key generation process is stalled until enough entropy is present. You can generate entropy e.g. by moving the mouse or typing at the keyboard. The easiest way is by using another application until the key generation continues.");
0164             }
0165             if (parts.at(3) != QLatin1String( "0" ))
0166                 Q_EMIT infoProgress(parts.at(2).toUInt(), parts.at(3).toUInt());
0167         }
0168     } else if (line.contains(QLatin1String( "GOOD_PASSPHRASE" ))) {
0169         setSuccess(TS_MSG_SEQUENCE);
0170     } else if (line.contains(QLatin1String( "KEY_CREATED" ))) {
0171         m_fingerprint = line.right(40);
0172         setSuccess(TS_OK);
0173         result = true;
0174     } else if (line.contains(QLatin1String( "NEED_PASSPHRASE" ))) {
0175         setSuccess(TS_USER_ABORTED);
0176     } else if (line.contains(QLatin1String( "GET_" ))) {
0177         setSuccess(TS_MSG_SEQUENCE);
0178         result = true;
0179     } else if (line.contains(QLatin1String("KEY_NOT_CREATED"))) {
0180         result = true;
0181     } else
0182         m_errorOutput << line;
0183 
0184     Q_EMIT statusMessage(msg);
0185 
0186     return result;
0187 }
0188 
0189 void
0190 KGpgGenerateKey::finish()
0191 {
0192     switch (getSuccess()) {
0193     case TS_BAD_PASSPHRASE:
0194         Q_EMIT statusMessage(i18n("Bad passphrase. Cannot generate a new key pair."));
0195         break;
0196     case TS_USER_ABORTED:
0197         Q_EMIT statusMessage(i18n("Aborted by the user. Cannot generate a new key pair."));
0198         break;
0199     case TS_INVALID_EMAIL:
0200         Q_EMIT statusMessage(i18n("The email address is not valid. Cannot generate a new key pair."));
0201         break;
0202     case TS_INVALID_NAME:
0203         Q_EMIT statusMessage(i18n("The name is not accepted by gpg. Cannot generate a new key pair."));
0204         break;
0205     case TS_OK:
0206         Q_EMIT statusMessage(i18n("Key %1 generated", getFingerprint()));
0207         break;
0208     default:
0209         while (getProcess()->hasLineStandardError()) {
0210             QByteArray b;
0211             getProcess()->readLineStandardError(&b);
0212             m_errorOutput << QString::fromUtf8(b);
0213         }
0214 
0215         Q_EMIT statusMessage(i18n("gpg process did not finish. Cannot generate a new key pair."));
0216     }
0217 }
0218 
0219 void
0220 KGpgGenerateKey::newPassphraseEntered()
0221 {
0222     QApplication::setOverrideCursor(Qt::BusyCursor);
0223     write("%commit");
0224     getProcess()->closeWriteChannel();
0225 }
0226 
0227 QString
0228 KGpgGenerateKey::getName() const
0229 {
0230     return m_name;
0231 }
0232 
0233 QString
0234 KGpgGenerateKey::getEmail() const
0235 {
0236     return m_email;
0237 }
0238 
0239 QString
0240 KGpgGenerateKey::getFingerprint() const
0241 {
0242     return m_fingerprint;
0243 }
0244 
0245 QString
0246 KGpgGenerateKey::gpgErrorMessage() const
0247 {
0248     return m_errorOutput.join(QLatin1Char('\n'));
0249 }