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 <%2></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 }