Skip to content

Commit 12f18c5

Browse files
author
Niklas Femerstrand
committed
Adds email sign (without encryption)
1 parent 34a6360 commit 12f18c5

File tree

3 files changed

+130
-57
lines changed

3 files changed

+130
-57
lines changed

js/rc_openpgpjs.crypto.js

+37-2
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,33 @@
3030
* Return:
3131
* Encrypted message (str)
3232
*/
33-
function encrypt(pubkeys, text, sign, privkey) {
33+
// TODO: Feed key armored and do openpgp.read_* here
34+
function encrypt(pubkeys, text, sign, privkey, passphrase) {
3435
sign = (typeof sign === "undefined") ? 0 : 1;
3536
if(sign) {
3637
privkey = (typeof privkey === "undefined") ? 0 : privkey;
38+
passphrase = (typeof passphrase === "undefined") ? 0 : passphrase;
39+
3740
if(!privkey) {
3841
alert("missing privkey");
39-
return false;
42+
return false;
43+
}
44+
45+
if(!passphrase) {
46+
alert("missing passphrase");
47+
return false;
48+
}
49+
50+
if (!privkey[0].decryptSecretMPIs(passphrase)) {
51+
alert("Password for secrect key was incorrect!");
52+
return;
53+
}
54+
55+
try {
56+
encrypted = openpgp.write_signed_and_encrypted_message(privkey[0], pubkeys, text);
57+
return(encrypted);
58+
} catch (e) {
59+
return false;
4060
}
4161
}
4262

@@ -65,6 +85,21 @@ function generateKeys(bits, algo, ident, passphrase) {
6585
}
6686
}
6787

88+
function sign(msg, privkey_armored, passphrase) {
89+
var priv_key = openpgp.read_privateKey(privkey_armored);
90+
91+
if(!priv_key[0].decryptSecretMPIs(passphrase)) {
92+
alert("WRONG PASS");
93+
}
94+
95+
try {
96+
var signed = openpgp.write_signed_message(priv_key[0], msg);
97+
return(signed);
98+
} catch(e) {
99+
return false;
100+
}
101+
}
102+
68103
function decrypt(msg, privkey_armored, passphrase) {
69104
if(!("decrypt" in msg[0])) {
70105
return false;

js/rc_openpgpjs.js

+53-54
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ if(window.rcmail) {
6666
if (rcmail.env.action === "compose") {
6767
rcmail.env.compose_commands.push('open-key-manager');
6868
rcmail.addEventListener("beforesend", function(e) { if(!beforeSend()) { return false; } });
69-
$("#composebuttons").prepend("<input id='openpgpjs_encrypt' type='checkbox' checked='checked' /> " + rcmail.gettext('encrypt', 'rc_openpgpjs') + " <input id='openpgpjs_sign' type='checkbox' disabled='disabled' /> " + rcmail.gettext('sign', 'rc_openpgpjs') + "");
69+
$("#composebuttons").prepend("<input id='openpgpjs_encrypt' type='checkbox' /> " + rcmail.gettext('encrypt', 'rc_openpgpjs') + " <input id='openpgpjs_sign' type='checkbox' checked='checked' /> " + rcmail.gettext('sign', 'rc_openpgpjs') + "");
7070
} else if (rcmail.env.action === 'show' || rcmail.env.action === "preview") {
7171
processReceived();
7272
}
@@ -81,9 +81,14 @@ if(window.rcmail) {
8181
return;
8282
}
8383

84+
// msg[0].type: 2 == signed only
85+
// msg[0].type: 3 == encrypted only
86+
8487
showKeyInfo(msg);
8588

86-
// Successfully parsed OpenPGP message
89+
// TODO fix signature verification
90+
if(msg[0].type === 2) return;
91+
8792
if(!openpgp.keyring.hasPrivateKey()) {
8893
rcmail.display_message(rcmail.gettext('no_key_imported', 'rc_openpgpjs'), "error");
8994
return false;
@@ -198,54 +203,14 @@ if(window.rcmail) {
198203

199204
$('#key_select_error').addClass("hidden");
200205
$('#openpgpjs_key_select').dialog('close');
201-
}
202-
203-
function sign(encrypt) {
204-
if(this.passphrase === "" && openpgp.keyring.privateKeys.length > 0)
205-
{
206-
$("#openpgpjs_key_select").dialog('open');
207-
return false;
208-
} else if(!encrypt && openpgp.keyring.privateKeys.length === 0) {
209-
alert(rcmail.gettext('no_keys', 'rc_openpgpjs'));
210-
return false;
211-
} else if(openpgp.keyring.privateKeys.length === 0 || openpgp.keyring.publicKeys.length === 0) {
212-
alert(rcmail.gettext('no_keys', 'rc_openpgpjs'));
213-
return false;
214-
}
215206

216-
passobj = JSON.parse(this.passphrase);
217-
var keyid = openpgp.keyring.privateKeys[passobj.id].obj.getKeyId();
218-
var privkey_armored = openpgp.keyring.getPrivateKeyForKeyId(keyid)[0].key.armored;
219-
var priv_key = openpgp.read_privateKey(privkey_armored);
220-
221-
if(!priv_key[0].decryptSecretMPIs(passobj.passphrase)) {
222-
alert(rcmail.gettext('incorrect_pass', 'rc_openpgpjs'));
223-
}
224-
225-
if(!encrypt) {
226-
signed = openpgp.write_signed_message(priv_key[0], $("textarea#composebody").val());
227-
if(signed) {
228-
return signed;
229-
}
230-
}
231-
232-
var pubkeys = new Array();
233-
var recipients = $("#_to").val().split(",");
234-
235-
for (var i = 0; i < recipients.length; i++) {
236-
var recipient = recipients[i].replace(/(.+?<)/, '').replace(/>/, '');
237-
var pubkey = openpgp.keyring.getPublicKeyForAddress(recipient);
238-
pubkeys.push(pubkey[0].obj);
239-
// TODO: For some reason signing can only be made with one recipient pubkey, gotta investigate
240-
break;
241-
}
242-
243-
signed = openpgp.write_signed_and_encrypted_message(priv_key[0], pubkey[0].obj, $("textarea#composebody").val());
244-
if(signed) {
245-
return signed;
246-
}
247-
248-
return false;
207+
// This is required when sending emails and private keys are required for
208+
// sending an email (when signing a message). These lines makes the client
209+
// jump right back into beforeSend() allowing key sign and message send to
210+
// be made as soon as the passphrase is correct and available.
211+
if(typeof(this.sendmail) !== "undefined") {
212+
rcmail.command('send','',this,event)
213+
}
249214
}
250215

251216
function fetchRecipientPubkeys() {
@@ -287,16 +252,16 @@ if(window.rcmail) {
287252
}
288253

289254
function beforeSend() {
290-
if(!$("#openpgpjs_encrypt").is(":checked") &&
291-
!$("#openpgpjs_sign").is("checked")) {
292-
return true;
293-
}
255+
if(!$("#openpgpjs_encrypt").is(":checked") &&
256+
!$("#openpgpjs_sign").is(":checked")) {
257+
return true;
258+
}
294259

295260
if(typeof(this.finished_treating) !== "undefined") {
296261
return true;
297262
}
298263

299-
// Only encrypt, don't sign
264+
// Encrypt only
300265
if($("#openpgpjs_encrypt").is(":checked") &&
301266
!$("#openpgpjs_sign").is(":checked")) {
302267
// Fetch recipient pubkeys
@@ -311,9 +276,43 @@ if(window.rcmail) {
311276
this.finished_treating = 1;
312277
return true;
313278
}
279+
}
280+
281+
// Sign only
282+
if($("#openpgpjs_sign").is(":checked") &&
283+
!$("#openpgpjs_encrypt").is(":checked")) {
284+
285+
if(this.passphrase === "" &&
286+
openpgp.keyring.privateKeys.length > 0) {
287+
this.sendmail = true; // Global var to notify set_passphrase
288+
$("#openpgpjs_key_select").dialog('open');
289+
return false;
290+
}
291+
292+
if(openpgp.keyring.privateKeys.length === 0) {
293+
alert(rcmail.gettext('no_keys', 'rc_openpgpjs'));
294+
return false;
295+
}
296+
297+
var passobj = JSON.parse(this.passphrase);
298+
var keyid = openpgp.keyring.privateKeys[passobj.id].obj.getKeyId();
299+
var privkey_armored = openpgp.keyring.getPrivateKeyForKeyId(keyid)[0].key.armored;
300+
var privkey = openpgp.read_privateKey(privkey_armored);
301+
302+
if(!privkey[0].decryptSecretMPIs(passobj.passphrase)) {
303+
alert("WRONG PASS");
304+
}
305+
306+
signed = openpgp.write_signed_message(privkey[0], "hej");
307+
308+
if(signed) {
309+
$("textarea#composebody").val(signed);
310+
return true;
311+
}
314312

315313
return false;
316314
}
315+
317316
return false;
318317
}
319318

test/index.htm

+40-1
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@ <h1>rc_openpgpjs test suite</h1>
1111
<div id="container" style="float:left;">
1212
<div id="keygen">
1313
<h2>Keygen</h2>
14+
Bits:
1415
<select id="gen_bits">
1516
<option value="1024">1024</option>
1617
<option value="2048">2048</option>
1718
<option value="4096">4096</option>
1819
</select>
20+
Passphrase:
21+
<input type="text" id="gen_passphrase" value="test" />
1922
<input type="submit" onclick="testGenerateKeys();" value="Generate keypair" />
2023
<div>
2124
<textarea id="privkey"></textarea>
@@ -28,10 +31,20 @@ <h2>Keygen</h2>
2831
<h2>Encrypt</h2>
2932
<input type="text" id="string_to_encrypt" value="String to encrypt..." />
3033
<input type="button" value="Encrypt" onclick="testEncrypt();" />
34+
<input type="button" value="Encrypt & sign" onclick="testEncryptAndSign();" />
3135
<div>
3236
<textarea id="encrypted"></textarea>
3337
</div>
3438
</div>
39+
40+
<div id="sign">
41+
<h2>Sign</h2>
42+
<input type="text" id="string_to_sign" value="String to sign..." />
43+
<input type="button" value="Sign" onclick="testSign();" />
44+
<div>
45+
<textarea id="signed"></textarea>
46+
</div>
47+
</div>
3548
</div>
3649
<div id="debug" style="float:right;min-width:50%;padding:5px;"></div>
3750
<script type="text/javascript" src="../../../program/js/jquery.min.js"></script>
@@ -74,11 +87,37 @@ <h2>Encrypt</h2>
7487
}
7588
}
7689

90+
function testSign() {
91+
try {
92+
signed = sign($("#string_to_sign").val(), $("#privkey").html(), $("#gen_passphrase").val());
93+
$("#signed").html(signed);
94+
return true;
95+
} catch(e) {
96+
return false;
97+
}
98+
}
99+
100+
function testEncryptAndSign() {
101+
var pubkeys = new Array();
102+
// read armored keys
103+
var priv_key = openpgp.read_privateKey($("#privkey").html());
104+
var pub_key = openpgp.read_publicKey($("#pubkey").html());
105+
pubkeys.push(pub_key[0]);
106+
107+
try {
108+
encrypted = encrypt(pubkeys, $("#string_to_encrypt").val(), 1, priv_key, $("#gen_passphrase").val());
109+
$("#encrypted").html(encrypted);
110+
return true;
111+
} catch(e) {
112+
return false;
113+
}
114+
}
115+
77116
function runAll() {
78117
resetDebug();
79118
var fail = new Array();
80119
var success = new Array();
81-
var tests = new Array("testGenerateKeys", "testEncrypt", "testDecrypt");
120+
var tests = new Array("testGenerateKeys", "testEncrypt", "testDecrypt", "testEncryptAndSign", "testSign");
82121
for(var i = 0; i < tests.length; i++)
83122
{
84123
if(window[tests[i]]()) {

0 commit comments

Comments
 (0)