1 /*
2 SPDX-FileCopyrightText: 2008, 2009, 2010, 2011, 2012, 2013, 2018 Rolf Eike Beer <kde@opensource.sf-tec.de>
3 SPDX-License-Identifier: GPL-2.0-or-later
4 */
5
6 #include "kgpggeneratekey.h"
7
8 #include "gpgproc.h"
9
10 #include <KEmailAddress>
11 #include <KLocalizedString>
12 #include <QApplication>
13
KGpgGenerateKey(QObject * parent,const QString & name,const QString & email,const QString & comment,const KgpgCore::KgpgKeyAlgo & algorithm,const uint size,const unsigned int expire,const char expireunit,const KgpgCore::KgpgSubKeyType capabilities)14 KGpgGenerateKey::KGpgGenerateKey(QObject *parent, const QString &name, const QString &email, const QString &comment,
15 const KgpgCore::KgpgKeyAlgo &algorithm, const uint size, const unsigned int expire,
16 const char expireunit, const KgpgCore::KgpgSubKeyType capabilities)
17 : KGpgTransaction(parent),
18 m_name(name),
19 m_email(email),
20 m_comment(comment),
21 m_algorithm(algorithm),
22 m_capabilities(capabilities),
23 m_size(size),
24 m_expire(expire),
25 m_expireunit(expireunit)
26 {
27 Q_ASSERT((expireunit == 'd') || (expireunit == 'w') ||
28 (expireunit == 'm') || (expireunit == 'y'));
29
30 addArguments( { QLatin1String("--status-fd=1"),
31 QLatin1String("--command-fd=0"),
32 QLatin1String("--no-verbose"),
33 QLatin1String("--gen-key"),
34 QLatin1String("--batch")
35 } );
36
37 getProcess()->setOutputChannelMode(KProcess::SeparateChannels);
38 }
39
~KGpgGenerateKey()40 KGpgGenerateKey::~KGpgGenerateKey()
41 {
42 }
43
44 bool
preStart()45 KGpgGenerateKey::preStart()
46 {
47 if (!m_email.isEmpty() && !KEmailAddress::isValidSimpleAddress(m_email)) {
48 setSuccess(TS_INVALID_EMAIL);
49 return false;
50 }
51
52 m_fingerprint.clear();
53
54 setSuccess(TS_MSG_SEQUENCE);
55
56 setDescription(i18n("Generating New Key for %1", m_name));
57
58 return true;
59 }
60
61 void
postStart()62 KGpgGenerateKey::postStart()
63 {
64 QByteArray keymessage = "Key-Type: ";
65
66 switch (m_algorithm) {
67 case KgpgCore::ALGO_RSA:
68 keymessage.append("RSA");
69 break;
70 case KgpgCore::ALGO_RSA_RSA:
71 keymessage.append("RSA\nSubkey-Type: RSA");
72 break;
73 case KgpgCore::ALGO_DSA_ELGAMAL:
74 keymessage.append("DSA\nSubkey-Type: ELG-E");
75 break;
76 default:
77 Q_ASSERT(m_algorithm == KgpgCore::ALGO_RSA);
78 return;
79 }
80
81 const QByteArray keylen = QByteArray::number(m_size);
82
83 keymessage.append("\nKey-Length: ");
84 keymessage.append(keylen);
85 keymessage.append("\nSubkey-Length: ");
86 keymessage.append(keylen);
87 keymessage.append("\nName-Real: ");
88 keymessage.append(m_name.toUtf8());
89
90 if (!m_email.isEmpty()) {
91 keymessage.append("\nName-Email: ");
92 keymessage.append(m_email.toLatin1());
93 }
94
95 if (!m_comment.isEmpty()) {
96 keymessage.append("\nName-Comment: ");
97 keymessage.append(m_comment.toUtf8());
98 }
99
100 if (m_expire != 0) {
101 keymessage.append("\nExpire-Date: ");
102 keymessage.append(QByteArray::number(m_expire));
103 keymessage.append(m_expireunit);
104 }
105
106 if (m_capabilities) {
107 keymessage.append("\nKey-Usage: ");
108 QStringList usage;
109 #if 0
110 // GnuPG always adds cert, but it does not allow this to be
111 // explicitly specified
112 if (m_capabilities & KgpgCore::SKT_CERTIFICATION)
113 usage << QLatin1String("cert");
114 #endif
115 if (m_capabilities & KgpgCore::SKT_AUTHENTICATION)
116 usage << QLatin1String("auth");
117 if (m_capabilities & KgpgCore::SKT_ENCRYPTION)
118 usage << QLatin1String("encrypt");
119 if (m_capabilities & KgpgCore::SKT_SIGNATURE)
120 usage << QLatin1String("sign");
121 keymessage.append(usage.join(QLatin1Char(' ')).toLatin1());
122 }
123
124 keymessage.append("\nPassphrase: ");
125 write(keymessage, false);
126
127 QString passdlgmessage;
128 if (!m_email.isEmpty()) {
129 passdlgmessage = i18n("<p><b>Enter passphrase for %1 <%2></b>:<br />Passphrase should include non alphanumeric characters and random sequences.</p>",
130 m_name, m_email);
131 } else {
132 passdlgmessage = i18n("<p><b>Enter passphrase for %1</b>:<br />Passphrase should include non alphanumeric characters and random sequences.</p>",
133 m_name);
134 }
135
136 QApplication::restoreOverrideCursor();
137 askNewPassphrase(passdlgmessage);
138 }
139
140 bool
nextLine(const QString & line)141 KGpgGenerateKey::nextLine(const QString &line)
142 {
143 QString msg = i18n("Generating Key");
144
145 if (!line.startsWith(QLatin1String("[GNUPG:] ")))
146 return false;
147
148 int result = false;
149
150 if (line.contains(QLatin1String( "PROGRESS" ))) {
151 const QStringList parts = line.mid(18).split(QLatin1Char(' '));
152
153 if (parts.count() >= 4) {
154 const QString p0(parts.at(0));
155 if (p0 == QLatin1String( "primegen" )) {
156 msg = i18n("Generating prime numbers");
157 } else if (p0 == QLatin1String( "pk_dsa" )) {
158 msg = i18n("Generating DSA key");
159 } else if (p0 == QLatin1String( "pk_elg" )) {
160 msg = i18n("Generating ElGamal key");
161 } else if (p0 == QLatin1String( "need_entropy" )) {
162 msg = i18n("Waiting for entropy");
163
164 // This message is currenlty not displayed. Nevertheless it's
165 // included here so string freeze is not broken if it will be
166 // displayed later on.
167 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.");
168 }
169 if (parts.at(3) != QLatin1String( "0" ))
170 Q_EMIT infoProgress(parts.at(2).toUInt(), parts.at(3).toUInt());
171 }
172 } else if (line.contains(QLatin1String( "GOOD_PASSPHRASE" ))) {
173 setSuccess(TS_MSG_SEQUENCE);
174 } else if (line.contains(QLatin1String( "KEY_CREATED" ))) {
175 m_fingerprint = line.right(40);
176 setSuccess(TS_OK);
177 result = true;
178 } else if (line.contains(QLatin1String( "NEED_PASSPHRASE" ))) {
179 setSuccess(TS_USER_ABORTED);
180 } else if (line.contains(QLatin1String( "GET_" ))) {
181 setSuccess(TS_MSG_SEQUENCE);
182 result = true;
183 } else if (line.contains(QLatin1String("KEY_NOT_CREATED"))) {
184 result = true;
185 } else
186 m_errorOutput << line;
187
188 Q_EMIT statusMessage(msg);
189
190 return result;
191 }
192
193 void
finish()194 KGpgGenerateKey::finish()
195 {
196 switch (getSuccess()) {
197 case TS_BAD_PASSPHRASE:
198 Q_EMIT statusMessage(i18n("Bad passphrase. Cannot generate a new key pair."));
199 break;
200 case TS_USER_ABORTED:
201 Q_EMIT statusMessage(i18n("Aborted by the user. Cannot generate a new key pair."));
202 break;
203 case TS_INVALID_EMAIL:
204 Q_EMIT statusMessage(i18n("The email address is not valid. Cannot generate a new key pair."));
205 break;
206 case TS_INVALID_NAME:
207 Q_EMIT statusMessage(i18n("The name is not accepted by gpg. Cannot generate a new key pair."));
208 break;
209 case TS_OK:
210 Q_EMIT statusMessage(i18n("Key %1 generated", getFingerprint()));
211 break;
212 default:
213 while (getProcess()->hasLineStandardError()) {
214 QByteArray b;
215 getProcess()->readLineStandardError(&b);
216 m_errorOutput << QString::fromUtf8(b);
217 }
218
219 Q_EMIT statusMessage(i18n("gpg process did not finish. Cannot generate a new key pair."));
220 }
221 }
222
223 void
newPassphraseEntered()224 KGpgGenerateKey::newPassphraseEntered()
225 {
226 QApplication::setOverrideCursor(Qt::BusyCursor);
227 write("%commit");
228 }
229
230 QString
getName() const231 KGpgGenerateKey::getName() const
232 {
233 return m_name;
234 }
235
236 QString
getEmail() const237 KGpgGenerateKey::getEmail() const
238 {
239 return m_email;
240 }
241
242 QString
getFingerprint() const243 KGpgGenerateKey::getFingerprint() const
244 {
245 return m_fingerprint;
246 }
247
248 QString
gpgErrorMessage() const249 KGpgGenerateKey::gpgErrorMessage() const
250 {
251 return m_errorOutput.join(QLatin1Char('\n'));
252 }
253