diff --git a/src/cleartext.js b/src/cleartext.js index 5ed0c6a3..94b56eb3 100644 --- a/src/cleartext.js +++ b/src/cleartext.js @@ -67,9 +67,10 @@ CleartextMessage.prototype.getSigningKeyIds = function() { /** * Sign the cleartext message * @param {Array} privateKeys private keys with decrypted secret key data for signing + * @return {module:message~CleartextMessage} new cleartext message with signed content */ CleartextMessage.prototype.sign = function(privateKeys) { - this.signature = this.signDetached(privateKeys); + return new CleartextMessage(this.text, this.signDetached(privateKeys)); }; /** diff --git a/src/openpgp.js b/src/openpgp.js index d523d5d4..5a2a5e5a 100644 --- a/src/openpgp.js +++ b/src/openpgp.js @@ -273,7 +273,7 @@ export function decrypt({ message, privateKey, publicKeys, sessionKey, password, /** * Signs a cleartext message. - * @param {String} data cleartext input to be signed + * @param {String | Uint8Array} data cleartext input to be signed * @param {Key|Array} privateKeys array of keys or single key with decrypted secret key data to sign cleartext * @param {Boolean} armor (optional) if the return value should be ascii armored or the message object * @param {Boolean} detached (optional) if the return value should contain a detached signature @@ -283,7 +283,7 @@ export function decrypt({ message, privateKey, publicKeys, sessionKey, password, * @static */ export function sign({ data, privateKeys, armor=true, detached=false}) { - checkString(data); + checkData(data); privateKeys = toArray(privateKeys); if (asyncProxy) { // use web worker if available @@ -292,24 +292,29 @@ export function sign({ data, privateKeys, armor=true, detached=false}) { var result = {}; return execute(() => { + var message; - const cleartextMessage = new cleartext.CleartextMessage(data); + if (util.isString(data)) { + message = new cleartext.CleartextMessage(data); + } else { + message = messageLib.fromBinary(data); + } if (detached) { - var signature = cleartextMessage.signDetached(privateKeys); + var signature = message.signDetached(privateKeys); if (armor) { result.signature = signature.armor(); } else { result.signature = signature; } } else { - cleartextMessage.sign(privateKeys); + message = message.sign(privateKeys); } if (armor) { - result.data = cleartextMessage.armor(); + result.data = message.armor(); } else { - result.message = cleartextMessage; + result.message = message; } return result; @@ -326,7 +331,7 @@ export function sign({ data, privateKeys, armor=true, detached=false}) { * @static */ export function verify({ message, publicKeys, signature=null }) { - checkCleartextMessage(message); + checkCleartextOrMessage(message); publicKeys = toArray(publicKeys); if (asyncProxy) { // use web worker if available @@ -335,8 +340,11 @@ export function verify({ message, publicKeys, signature=null }) { var result = {}; return execute(() => { - result.data = message.getText(); - + if (cleartext.CleartextMessage.prototype.isPrototypeOf(message)) { + result.data = message.getText(); + } else { + result.data = message.getLiteralData(); + } if (signature) { //detached signature result.signatures = message.verifyDetached(signature, publicKeys); @@ -367,7 +375,7 @@ export function verify({ message, publicKeys, signature=null }) { * @static */ export function encryptSessionKey({ data, algorithm, publicKeys, passwords }) { - checkbinary(data); checkString(algorithm, 'algorithm'); publicKeys = toArray(publicKeys); passwords = toArray(passwords); + checkBinary(data); checkString(algorithm, 'algorithm'); publicKeys = toArray(publicKeys); passwords = toArray(passwords); if (asyncProxy) { // use web worker if available return asyncProxy.delegate('encryptSessionKey', { data, algorithm, publicKeys, passwords }); @@ -417,7 +425,7 @@ function checkString(data, name) { throw new Error('Parameter [' + (name || 'data') + '] must be of type String'); } } -function checkbinary(data, name) { +function checkBinary(data, name) { if (!util.isUint8Array(data)) { throw new Error('Parameter [' + (name || 'data') + '] must be of type Uint8Array'); } @@ -432,9 +440,9 @@ function checkMessage(message) { throw new Error('Parameter [message] needs to be of type Message'); } } -function checkCleartextMessage(message) { - if (!cleartext.CleartextMessage.prototype.isPrototypeOf(message)) { - throw new Error('Parameter [message] needs to be of type CleartextMessage'); +function checkCleartextOrMessage(message) { + if (!cleartext.CleartextMessage.prototype.isPrototypeOf(message) && !messageLib.Message.prototype.isPrototypeOf(message)) { + throw new Error('Parameter [message] needs to be of type Message or CleartextMessage'); } } diff --git a/src/packet/signature.js b/src/packet/signature.js index f8639894..25e545c9 100644 --- a/src/packet/signature.js +++ b/src/packet/signature.js @@ -226,7 +226,7 @@ Signature.prototype.sign = function (key, data) { var trailer = this.calculateTrailer(); - var toHash = null + var toHash = null; switch (this.version) { case 3: diff --git a/test/general/signature.js b/test/general/signature.js index dacc59da..254ce574 100644 --- a/test/general/signature.js +++ b/test/general/signature.js @@ -527,7 +527,7 @@ describe("Signature", function() { }); }); - it('Sign text with openpgp.sign and verify with openpgp.verify leads to same cleartext and valid signatures', function(done) { + it('Sign text with openpgp.sign and verify with openpgp.verify leads to same string cleartext and valid signatures', function(done) { var plaintext = 'short message\nnext line\n한국어/조선말'; var pubKey = openpgp.key.readArmored(pub_key_arm2).keys[0]; var privKey = openpgp.key.readArmored(priv_key_arm2).keys[0]; @@ -549,6 +549,50 @@ describe("Signature", function() { }); + it('Sign text with openpgp.sign and verify with openpgp.verify leads to same bytes cleartext and valid signatures - armored', function(done) { + var plaintext = openpgp.util.str2Uint8Array('short message\nnext line\n한국어/조선말'); + var pubKey = openpgp.key.readArmored(pub_key_arm2).keys[0]; + var privKey = openpgp.key.readArmored(priv_key_arm2).keys[0]; + privKey.getSigningKeyPacket().decrypt('hello world'); + console.log(pubKey.armor()); + + openpgp.sign({ privateKeys:[privKey], data:plaintext }).then(function(signed) { + console.log(signed.data); + var csMsg = openpgp.message.readArmored(signed.data); + return openpgp.verify({ publicKeys:[pubKey], message:csMsg }); + + }).then(function(cleartextSig) { + expect(cleartextSig).to.exist; + expect(cleartextSig.data).to.deep.equal(plaintext); + expect(cleartextSig.signatures).to.have.length(1); + expect(cleartextSig.signatures[0].valid).to.be.true; + expect(cleartextSig.signatures[0].signature.packets.length).to.equal(1); + done(); + }); + + }); + + it('Sign text with openpgp.sign and verify with openpgp.verify leads to same bytes cleartext and valid signatures - not armored', function(done) { + var plaintext = openpgp.util.str2Uint8Array('short message\nnext line\n한국어/조선말'); + var pubKey = openpgp.key.readArmored(pub_key_arm2).keys[0]; + var privKey = openpgp.key.readArmored(priv_key_arm2).keys[0]; + privKey.getSigningKeyPacket().decrypt('hello world'); + + openpgp.sign({ privateKeys:[privKey], data:plaintext, armor:false }).then(function(signed) { + var csMsg = signed.message; + return openpgp.verify({ publicKeys:[pubKey], message:csMsg }); + + }).then(function(cleartextSig) { + expect(cleartextSig).to.exist; + expect(cleartextSig.data).to.deep.equal(plaintext); + expect(cleartextSig.signatures).to.have.length(1); + expect(cleartextSig.signatures[0].valid).to.be.true; + expect(cleartextSig.signatures[0].signature.packets.length).to.equal(1); + done(); + }); + + }); + it('Verify primary key revocation signature', function(done) { var pubKey = openpgp.key.readArmored(pub_revoked).keys[0];