From 28e5f5d3f408e1943924f1abfb6d12ad262d8314 Mon Sep 17 00:00:00 2001 From: Sanjana Rajan Date: Tue, 4 Jul 2017 14:15:39 -0700 Subject: [PATCH] allow cleartext msg data to be string or byte array --- src/cleartext.js | 54 +++++++++++++++++++++++++++++++++-------- src/openpgp.js | 11 ++++++--- src/packet/signature.js | 2 +- 3 files changed, 52 insertions(+), 15 deletions(-) diff --git a/src/cleartext.js b/src/cleartext.js index e9ab668e..9e6f1be9 100644 --- a/src/cleartext.js +++ b/src/cleartext.js @@ -28,7 +28,9 @@ import config from './config'; import packet from './packet'; import enums from './enums.js'; +import util from './util'; import armor from './encoding/armor.js'; +import base64 from './encoding/base64.js'; import * as sigModule from './signature.js'; /** @@ -39,12 +41,16 @@ import * as sigModule from './signature.js'; * @param {module:signature} signature The detached signature or an empty signature if message not yet signed */ -export function CleartextMessage(text, signature) { +export function CleartextMessage(data, signature) { if (!(this instanceof CleartextMessage)) { - return new CleartextMessage(text, signature); + return new CleartextMessage(data, signature); + } + if (util.isString(data)) { + // normalize EOL to canonical form + this.text = data.replace(/\r/g, '').replace(/[\t ]+\n/g, "\n").replace(/\n/g,"\r\n"); + } else { + this.bytes = data; } - // normalize EOL to canonical form - this.text = text.replace(/\r/g, '').replace(/[\t ]+\n/g, "\n").replace(/\n/g,"\r\n"); if (signature && !(signature instanceof sigModule.Signature)) { throw new Error('Invalid signature input'); } @@ -80,7 +86,11 @@ CleartextMessage.prototype.sign = function(privateKeys) { CleartextMessage.prototype.signDetached = function(privateKeys) { var packetlist = new packet.List(); var literalDataPacket = new packet.Literal(); - literalDataPacket.setText(this.text); + if (this.text) { + literalDataPacket.setText(this.text); + } else { + literalDataPacket.setBytes(this.bytes, enums.read(enums.literal, enums.literal.binary)); + } for (var i = 0; i < privateKeys.length; i++) { if (privateKeys[i].isPublic()) { throw new Error('Need private key for signing'); @@ -118,7 +128,11 @@ CleartextMessage.prototype.verifyDetached = function(signature, keys) { var signatureList = signature.packets; var literalDataPacket = new packet.Literal(); // we assume that cleartext signature is generated based on UTF8 cleartext - literalDataPacket.setText(this.text); + if (this.text) { + literalDataPacket.setText(this.text); + } else { + literalDataPacket.setBytes(this.bytes, enums.read(enums.literal, enums.literal.binary)); + } for (var i = 0; i < signatureList.length; i++) { var keyPacket = null; for (var j = 0; j < keys.length; j++) { @@ -144,7 +158,7 @@ CleartextMessage.prototype.verifyDetached = function(signature, keys) { }; /** - * Get cleartext + * Get cleartext as native JavaScript string * @return {String} cleartext of message */ CleartextMessage.prototype.getText = function() { @@ -152,6 +166,14 @@ CleartextMessage.prototype.getText = function() { return this.text.replace(/\r\n/g,"\n"); }; +/** + * Get cleartext as byte array + * @returns {Uint8Array} A sequence of bytes + */ +CleartextMessage.prototype.getBytes = function() { + return this.bytes; +}; + /** * Returns ASCII armored text of cleartext signed message * @return {String} ASCII armor @@ -159,9 +181,14 @@ CleartextMessage.prototype.getText = function() { CleartextMessage.prototype.armor = function() { var body = { hash: enums.read(enums.hash, config.prefer_hash_algorithm).toUpperCase(), - text: this.text, data: this.signature.packets.write() }; + + if (this.text) { + body.text = this.text; + } else { + body.bytes = this.bytes; + } return armor.encode(enums.armor.signed, body); }; @@ -169,10 +196,11 @@ CleartextMessage.prototype.armor = function() { /** * reads an OpenPGP cleartext signed message and returns a CleartextMessage object * @param {String} armoredText text to be parsed + * @param {bool} whether the decoded cleartext message should be returned as a string (alternative is a byte array) * @return {module:cleartext~CleartextMessage} new cleartext message object * @static */ -export function readArmored(armoredText) { +export function readArmored(armoredText, isText=true) { var input = armor.decode(armoredText); if (input.type !== enums.armor.signed) { throw new Error('No cleartext signed message.'); @@ -181,7 +209,13 @@ export function readArmored(armoredText) { packetlist.read(input.data); verifyHeaders(input.headers, packetlist); var signature = new sigModule.Signature(packetlist); - var newMessage = new CleartextMessage(input.text, signature); + var cleartext; + if (isText) { + cleartext = input.cleartext.replace(/\n$/, '').replace(/\n/g, "\r\n"); + } else { + cleartext = base64.decode(input.cleartext); + } + var newMessage = new CleartextMessage(cleartext, signature); return newMessage; } diff --git a/src/openpgp.js b/src/openpgp.js index d523d5d4..57fea8f1 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 @@ -294,7 +294,6 @@ export function sign({ data, privateKeys, armor=true, detached=false}) { return execute(() => { const cleartextMessage = new cleartext.CleartextMessage(data); - if (detached) { var signature = cleartextMessage.signDetached(privateKeys); if (armor) { @@ -335,7 +334,11 @@ export function verify({ message, publicKeys, signature=null }) { var result = {}; return execute(() => { - result.data = message.getText(); + if (message.text) { + result.data = message.getText(); + } else { + result.data = message.getBytes(); + } if (signature) { //detached signature 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: