From 3f04470e1f4f589924657806dff6c06a50ab99bf Mon Sep 17 00:00:00 2001 From: Michal Kolodziej Date: Mon, 22 Apr 2013 18:03:50 +0200 Subject: [PATCH] First working packet: writing/reading sym encrypted and literal packets is working. Tests added. --- resources/openpgp.js | 1308 ++++++++--------- resources/openpgp.min.js | 33 +- ...enpgp.packet.literaldata.js => literal.js} | 18 +- src/packet/{openpgp.packet.js => packet.js} | 163 +- .../{openpgp.packetlist.js => packetlist.js} | 17 +- ...pteddata.js => symmetrically_encrypted.js} | 10 +- test/general/packet.js | 11 +- 7 files changed, 654 insertions(+), 906 deletions(-) rename src/packet/{openpgp.packet.literaldata.js => literal.js} (91%) rename src/packet/{openpgp.packet.js => packet.js} (66%) rename src/packet/{openpgp.packetlist.js => packetlist.js} (67%) rename src/packet/{openpgp.packet.encrypteddata.js => symmetrically_encrypted.js} (89%) diff --git a/resources/openpgp.js b/resources/openpgp.js index 722202ad..c3ed8712 100644 --- a/resources/openpgp.js +++ b/resources/openpgp.js @@ -9257,6 +9257,159 @@ function openpgp_msg_publickey() { // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/** + * @class + * @classdesc Implementation of the Literal Data Packet (Tag 11) + * + * RFC4880 5.9: A Literal Data packet contains the body of a message; data that + * is not to be further interpreted. + */ +function openpgp_packet_literal() { + this.tag = 11; + this.format = openpgp_packet_literal.format.utf8; + this.data = ''; + this.date = new Date(); + + + /** + * Set the packet data to a javascript native string or a squence of + * bytes. Conversion to a proper utf8 encoding takes place when the + * packet is written. + * @param {String} str Any native javascript string + * @param {openpgp_packet_literaldata.format} format + */ + this.set_data = function(str, format) { + this.format = format; + this.data = str; + } + + /** + * Set the packet data to value represented by the provided string + * of bytes together with the appropriate conversion format. + * @param {String} bytes The string of bytes + * @param {openpgp_packet_literaldata.format} format + */ + this.set_data_bytes = function(bytes, format) { + this.format = format; + + if(format == openpgp_packet_literal.format.utf8) + bytes = util.decode_utf8(bytes); + + this.data = bytes; + } + + /** + * Get the byte sequence representing the literal packet data + * @returns {String} A sequence of bytes + */ + this.get_data_bytes = function() { + if(this.format == openpgp_packet_literal.format.utf8) + return util.encode_utf8(this.data); + else + return this.data; + } + + + + /** + * Parsing function for a literal data packet (tag 11). + * + * @param {String} input Payload of a tag 11 packet + * @param {Integer} position + * Position to start reading from the input string + * @param {Integer} len + * Length of the packet or the remaining length of + * input at position + * @return {openpgp_packet_encrypteddata} object representation + */ + this.read = function(bytes) { + // - A one-octet field that describes how the data is formatted. + + var format = bytes[0]; + + this.filename = util.decode_utf8(bytes.substr(2, bytes + .charCodeAt(1))); + + this.date = new Date(parseInt(bytes.substr(2 + + bytes.charCodeAt(1), 4)) * 1000); + + var data = bytes.substring(6 + + bytes.charCodeAt(1)); + + this.set_data_bytes(data, format); + } + + /** + * Creates a string representation of the packet + * + * @param {String} data The data to be inserted as body + * @return {String} string-representation of the packet + */ + this.write = function() { + var filename = util.encode_utf8("msg.txt"); + + var data = this.get_data_bytes(); + + var result = ''; + result += this.format; + result += String.fromCharCode(filename.length); + result += filename; + result += String + .fromCharCode((Math.round(this.date.getTime() / 1000) >> 24) & 0xFF); + result += String + .fromCharCode((Math.round(this.date.getTime() / 1000) >> 16) & 0xFF); + result += String + .fromCharCode((Math.round(this.date.getTime() / 1000) >> 8) & 0xFF); + result += String + .fromCharCode(Math.round(this.date.getTime() / 1000) & 0xFF); + result += data; + return result; + } + + /** + * Generates debug output (pretty print) + * + * @return {String} String which gives some information about the keymaterial + */ + this.toString = function() { + return '5.9. Literal Data Packet (Tag 11)\n' + ' length: ' + + this.packetLength + '\n' + ' format: ' + this.format + + '\n' + ' filename:' + this.filename + '\n' + + ' date: ' + this.date + '\n' + ' data: |' + + this.data + '|\n' + ' rdata: |' + this.real_data + '|\n'; + } +} + +/** + * Data types in the literal packet + * @readonly + * @enum {String} + */ +openpgp_packet_literal.format = { + /** Binary data */ + binary: 'b', + /** Text data */ + text: 't', + /** Utf8 data */ + utf8: 'u' +}; +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + /** * @class * @classdesc Implementation of the Compressed Data Packet (Tag 8) @@ -9439,86 +9592,6 @@ function openpgp_packet_compressed(bytes) { // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -/** - * @class - * @classdesc Implementation of the Symmetrically Encrypted Data Packet (Tag 9) - * - * RFC4880 5.7: The Symmetrically Encrypted Data packet contains data encrypted - * with a symmetric-key algorithm. When it has been decrypted, it contains other - * packets (usually a literal data packet or compressed data packet, but in - * theory other Symmetrically Encrypted Data packets or sequences of packets - * that form whole OpenPGP messages). - */ - -function openpgp_packet_encrypteddata() { - this.tag = 9; - this.encrypted = null; - this.data = new openpgp_packetlist(); - this.algorithm = openpgp.symmetric.plaintext; - - - - this.read = function(bytes) { - this.encrypted = bytes; - } - - this.write = function() { - return this.encrypted; - } - - /** - * Symmetrically decrypt the packet data - * - * @param {Integer} symmetric_algorithm_type - * Symmetric key algorithm to use // See RFC4880 9.2 - * @param {String} key - * Key as string with the corresponding length to the - * algorithm - * @return The decrypted data; - */ - this.decrypt = function(symmetric_algorithm_type, key) { - var decrypted = openpgp_crypto_symmetricDecrypt( - symmetric_algorithm_type, key, this.encryptedData, true); - - util.print_debug("openpgp.packet.encryptedintegrityprotecteddata.js\n"+ - "data: "+util.hexstrdump(this.decryptedData)); - - - this.data = new openpgp_packetlist(decrypted); - } - - this.encrypt = function(algo, key) { - var data = this.data.write(); - - this.encrypted = openpgp_crypto_symmetricEncrypt( - openpgp_crypto_getPrefixRandom(algo), algo, key, data, true); - } - - - this.toString = function () { - return '5.7. Symmetrically Encrypted Data Packet (Tag 9)\n' - + ' Used symmetric algorithm: ' + this.algorithmType + '\n' - + ' encrypted data: Bytes [' - + util.hexstrdump(this.encryptedData) + ']\n'; - } -}; -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - /** * @class * @classdesc Implementation of the Sym. Encrypted Integrity Protected Data @@ -9900,439 +9973,6 @@ function openpgp_packet_encryptedsessionkey() { // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -/** - * @class - * @classdesc Parent openpgp packet class. Operations focus on determining - * packet types and packet header. - */ -function _openpgp_packet() { - /** - * Encodes a given integer of length to the openpgp length specifier to a - * string - * - * @param {Integer} length The length to encode - * @return {String} String with openpgp length representation - */ - function encode_length(length) { - result = ""; - if (length < 192) { - result += String.fromCharCode(length); - } else if (length > 191 && length < 8384) { - /* - * let a = (total data packet length) - 192 let bc = two octet - * representation of a let d = b + 192 - */ - result += String.fromCharCode(((length - 192) >> 8) + 192); - result += String.fromCharCode((length - 192) & 0xFF); - } else { - result += String.fromCharCode(255); - result += String.fromCharCode((length >> 24) & 0xFF); - result += String.fromCharCode((length >> 16) & 0xFF); - result += String.fromCharCode((length >> 8) & 0xFF); - result += String.fromCharCode(length & 0xFF); - } - return result; - } - this.encode_length = encode_length; - - /** - * Writes a packet header version 4 with the given tag_type and length to a - * string - * - * @param {Integer} tag_type Tag type - * @param {Integer} length Length of the payload - * @return {String} String of the header - */ - function write_packet_header(tag_type, length) { - /* we're only generating v4 packet headers here */ - var result = ""; - result += String.fromCharCode(0xC0 | tag_type); - result += encode_length(length); - return result; - } - - /** - * Writes a packet header Version 3 with the given tag_type and length to a - * string - * - * @param {Integer} tag_type Tag type - * @param {Integer} length Length of the payload - * @return {String} String of the header - */ - function write_old_packet_header(tag_type, length) { - var result = ""; - if (length < 256) { - result += String.fromCharCode(0x80 | (tag_type << 2)); - result += String.fromCharCode(length); - } else if (length < 65536) { - result += String.fromCharCode(0x80 | (tag_type << 2) | 1); - result += String.fromCharCode(length >> 8); - result += String.fromCharCode(length & 0xFF); - } else { - result += String.fromCharCode(0x80 | (tag_type << 2) | 2); - result += String.fromCharCode((length >> 24) & 0xFF); - result += String.fromCharCode((length >> 16) & 0xFF); - result += String.fromCharCode((length >> 8) & 0xFF); - result += String.fromCharCode(length & 0xFF); - } - return result; - } - this.write_old_packet_header = write_old_packet_header; - this.write_packet_header = write_packet_header; - /** - * Generic static Packet Parser function - * - * @param {String} input Input stream as string - * @param {integer} position Position to start parsing - * @param {integer} len Length of the input from position on - * @return {Object} Returns a parsed openpgp_packet - */ - function read_packet(input, position, len) { - // some sanity checks - if (input == null || input.length <= position - || input.substring(position).length < 2 - || (input[position].charCodeAt() & 0x80) == 0) { - util - .print_error("Error during parsing. This message / key is probably not containing a valid OpenPGP format."); - return null; - } - var mypos = position; - var tag = -1; - var format = -1; - - format = 0; // 0 = old format; 1 = new format - if ((input[mypos].charCodeAt() & 0x40) != 0) { - format = 1; - } - - var packet_length_type; - if (format) { - // new format header - tag = input[mypos].charCodeAt() & 0x3F; // bit 5-0 - } else { - // old format header - tag = (input[mypos].charCodeAt() & 0x3F) >> 2; // bit 5-2 - packet_length_type = input[mypos].charCodeAt() & 0x03; // bit 1-0 - } - - // header octet parsing done - mypos++; - - // parsed length from length field - var bodydata = null; - - // used for partial body lengths - var real_packet_length = -1; - if (!format) { - // 4.2.1. Old Format Packet Lengths - switch (packet_length_type) { - case 0: // The packet has a one-octet length. The header is 2 octets - // long. - packet_length = input[mypos++].charCodeAt(); - break; - case 1: // The packet has a two-octet length. The header is 3 octets - // long. - packet_length = (input[mypos++].charCodeAt() << 8) - | input[mypos++].charCodeAt(); - break; - case 2: // The packet has a four-octet length. The header is 5 - // octets long. - packet_length = (input[mypos++].charCodeAt() << 24) - | (input[mypos++].charCodeAt() << 16) - | (input[mypos++].charCodeAt() << 8) - | input[mypos++].charCodeAt(); - break; - default: - // 3 - The packet is of indeterminate length. The header is 1 - // octet long, and the implementation must determine how long - // the packet is. If the packet is in a file, this means that - // the packet extends until the end of the file. In general, - // an implementation SHOULD NOT use indeterminate-length - // packets except where the end of the data will be clear - // from the context, and even then it is better to use a - // definite length, or a new format header. The new format - // headers described below have a mechanism for precisely - // encoding data of indeterminate length. - packet_length = len; - break; - } - - } else // 4.2.2. New Format Packet Lengths - { - - // 4.2.2.1. One-Octet Lengths - if (input[mypos].charCodeAt() < 192) { - packet_length = input[mypos++].charCodeAt(); - util.print_debug("1 byte length:" + packet_length); - // 4.2.2.2. Two-Octet Lengths - } else if (input[mypos].charCodeAt() >= 192 - && input[mypos].charCodeAt() < 224) { - packet_length = ((input[mypos++].charCodeAt() - 192) << 8) - + (input[mypos++].charCodeAt()) + 192; - util.print_debug("2 byte length:" + packet_length); - // 4.2.2.4. Partial Body Lengths - } else if (input[mypos].charCodeAt() > 223 - && input[mypos].charCodeAt() < 255) { - packet_length = 1 << (input[mypos++].charCodeAt() & 0x1F); - util.print_debug("4 byte length:" + packet_length); - // EEEK, we're reading the full data here... - var mypos2 = mypos + packet_length; - bodydata = input.substring(mypos, mypos + packet_length); - while (true) { - if (input[mypos2].charCodeAt() < 192) { - var tmplen = input[mypos2++].charCodeAt(); - packet_length += tmplen; - bodydata += input.substring(mypos2, mypos2 + tmplen); - mypos2 += tmplen; - break; - } else if (input[mypos2].charCodeAt() >= 192 - && input[mypos2].charCodeAt() < 224) { - var tmplen = ((input[mypos2++].charCodeAt() - 192) << 8) - + (input[mypos2++].charCodeAt()) + 192; - packet_length += tmplen; - bodydata += input.substring(mypos2, mypos2 + tmplen); - mypos2 += tmplen; - break; - } else if (input[mypos2].charCodeAt() > 223 - && input[mypos2].charCodeAt() < 255) { - var tmplen = 1 << (input[mypos2++].charCodeAt() & 0x1F); - packet_length += tmplen; - bodydata += input.substring(mypos2, mypos2 + tmplen); - mypos2 += tmplen; - } else { - mypos2++; - var tmplen = (input[mypos2++].charCodeAt() << 24) - | (input[mypos2++].charCodeAt() << 16) - | (input[mypos2++].charCodeAt() << 8) - | input[mypos2++].charCodeAt(); - bodydata += input.substring(mypos2, mypos2 + tmplen); - packet_length += tmplen; - mypos2 += tmplen; - break; - } - } - real_packet_length = mypos2; - // 4.2.2.3. Five-Octet Lengths - } else { - mypos++; - packet_length = (input[mypos++].charCodeAt() << 24) - | (input[mypos++].charCodeAt() << 16) - | (input[mypos++].charCodeAt() << 8) - | input[mypos++].charCodeAt(); - } - } - - // if there was'nt a partial body length: use the specified - // packet_length - if (real_packet_length == -1) { - real_packet_length = packet_length; - } - - if (bodydata == null) { - bodydata = input.substring(mypos, mypos + real_packet_length); - } - - // alert('tag type: '+this.tag+' length: '+packet_length); - var version = 1; // (old format; 2= new format) - // if (input[mypos++].charCodeAt() > 15) - // version = 2; - - switch (tag) { - case 0: // Reserved - a packet tag MUST NOT have this value - break; - case 1: // Public-Key Encrypted Session Key Packet - var result = new openpgp_packet_encryptedsessionkey(); - if (result.read_pub_key_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 2: // Signature Packet - var result = new openpgp_packet_signature(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 3: // Symmetric-Key Encrypted Session Key Packet - var result = new openpgp_packet_encryptedsessionkey(); - if (result.read_symmetric_key_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 4: // One-Pass Signature Packet - var result = new openpgp_packet_onepasssignature(); - if (result.read_packet(bodydata, 0, packet_length)) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 5: // Secret-Key Packet - var result = new openpgp_packet_keymaterial(); - result.header = input.substring(position, mypos); - if (result.read_tag5(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 6: // Public-Key Packet - var result = new openpgp_packet_keymaterial(); - result.header = input.substring(position, mypos); - if (result.read_tag6(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 7: // Secret-Subkey Packet - var result = new openpgp_packet_keymaterial(); - if (result.read_tag7(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 8: // Compressed Data Packet - var result = new openpgp_packet_compressed(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 9: // Symmetrically Encrypted Data Packet - var result = new openpgp_packet_encrypteddata(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 10: // Marker Packet = PGP (0x50, 0x47, 0x50) - var result = new openpgp_packet_marker(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 11: // Literal Data Packet - var result = new openpgp_packet_literaldata(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.header = input.substring(position, mypos); - result.packetLength = real_packet_length; - return result; - } - break; - case 12: // Trust Packet - // TODO: to be implemented - break; - case 13: // User ID Packet - var result = new openpgp_packet_userid(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 14: // Public-Subkey Packet - var result = new openpgp_packet_keymaterial(); - result.header = input.substring(position, mypos); - if (result.read_tag14(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 17: // User Attribute Packet - var result = new openpgp_packet_userattribute(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 18: // Sym. Encrypted and Integrity Protected Data Packet - var result = new openpgp_packet_encryptedintegrityprotecteddata(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 19: // Modification Detection Code Packet - var result = new openpgp_packet_modificationdetectioncode(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - default: - util.print_error("openpgp.packet.js\n" - + "[ERROR] openpgp_packet: failed to parse packet @:" - + mypos + "\nchar:'" - + util.hexstrdump(input.substring(mypos)) + "'\ninput:" - + util.hexstrdump(input)); - return null; - break; - } - } - - this.read_packet = read_packet; - - - /** - * @enum {Integer} - * A list of packet type and numeric tags associated with them. - */ - this.type = { - reserved: 0, - public_key_encrypted_session_key: 1, - signature: 2, - symmetric_key_encrypted_session_key: 3, - one_pass_signature: 4, - secret_key: 5, - public_key: 6, - secret_subkey: 7, - compressed: 8, - symmetrically_encrypted_data: 9, - marker: 10, - literal: 11, - trust: 12, - userid: 13, - public_subkey: 14, - user_attribute: 17, - sym_encrypted_and_integrity_protected_data: 18, - modification_detection_code: 19 - }; -} - -var openpgp_packet = new _openpgp_packet(); -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - /** * @class * @classdesc Implementation of the Key Material Packet (Tag 5,6,7,14) @@ -11135,209 +10775,6 @@ function openpgp_packet_keymaterial() { this.write_private_key = write_private_key; this.write_public_key = write_public_key; } - - -/** - * @class - * @classdesc This class represents a list of openpgp packets. - */ -function openpgp_packetlist() { - - /** @type {openpgp_packet_[]} A list of packets */ - this.list = [] - - - - /** - * Reads a stream of binary data and interprents it as a list of packets. - * @param {openpgp_bytearray} An array of bytes. - */ - this.read = function(bytes) { - var i = 0; - - while(i < bytes.length) { - var packet = openpgp_packet.read_packet(bytes, i, bytes.length - i); - i += packet.headerLength + packet.packetLength; - - list.push(packet); - } - } - - /** - * Creates a binary representation of openpgp objects contained within the - * class instance. - * @returns {openpgp_bytearray} An array of bytes containing valid openpgp packets. - */ - this.write = function() { - var bytes = ''; - - for(var i in this.list) { - var packetbytes = this.list[i].write(); - bytes += openpgp_packet.write_packet_header(this.list[i].tag, packetbytes.length); - bytes += packetbytes; - } - - return bytes; - } - - this.push = function(packet) { - this.list.push(packet); - } - -} -// GPG4Browsers - An OpenPGP implementation in javascript -// Copyright (C) 2011 Recurity Labs GmbH -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -/** - * @class - * @classdesc Implementation of the Literal Data Packet (Tag 11) - * - * RFC4880 5.9: A Literal Data packet contains the body of a message; data that - * is not to be further interpreted. - */ -function openpgp_packet_literaldata() { - this.tag = 11; - this.format = openpgp_packet_literaldata.formats.utf8; - this.data = ''; - this.date = new Date(); - - - /** - * Set the packet data to a javascript native string or a squence of - * bytes. Conversion to a proper utf8 encoding takes place when the - * packet is written. - * @param {String} str Any native javascript string - * @param {openpgp_packet_literaldata.formats} format - */ - this.set_data = function(str, format) { - this.format = format; - this.data = str; - } - - /** - * Set the packet data to value represented by the provided string - * of bytes together with the appropriate conversion format. - * @param {String} bytes The string of bytes - * @param {openpgp_packet_literaldata.formats} format - */ - this.set_data_bytes = function(bytes, format) { - this.format = format; - - if(format == openpgp_packet_literaldata.formats.utf8) - bytes = util.decode_utf8(bytes); - - this.data = bytes; - } - - /** - * Get the byte sequence representing the literal packet data - * @returns {String} A sequence of bytes - */ - this.get_data_bytes = function() { - if(this.format == openpgp_packet_literaldata.formats.utf8) - return util.encode_utf8(this.data); - else - return this.data; - } - - - - /** - * Parsing function for a literal data packet (tag 11). - * - * @param {String} input Payload of a tag 11 packet - * @param {Integer} position - * Position to start reading from the input string - * @param {Integer} len - * Length of the packet or the remaining length of - * input at position - * @return {openpgp_packet_encrypteddata} object representation - */ - this.read = function(bytes) { - // - A one-octet field that describes how the data is formatted. - - var format = input[position]; - - this.filename = util.decode_utf8(bytes.substr(2, bytes - .charCodeAt(1))); - - this.date = new Date(parseInt(bytes.substr(2 - + bytes.charCodeAt(1), 4)) * 1000); - - var data = bytes.substring(6 - + bytes.charCodeAt(1)); - - this.set_data_bytes(data, format); - return this; - } - - /** - * Creates a string representation of the packet - * - * @param {String} data The data to be inserted as body - * @return {String} string-representation of the packet - */ - this.write = function() { - var filename = util.encode_utf8("msg.txt"); - - var data = this.get_data_bytes(); - - result += this.format; - result += String.fromCharCode(filename.length); - result += filename; - result += String - .fromCharCode((Math.round(this.date.getTime() / 1000) >> 24) & 0xFF); - result += String - .fromCharCode((Math.round(this.date.getTime() / 1000) >> 16) & 0xFF); - result += String - .fromCharCode((Math.round(this.date.getTime() / 1000) >> 8) & 0xFF); - result += String - .fromCharCode(Math.round(this.date.getTime() / 1000) & 0xFF); - result += data; - return result; - } - - /** - * Generates debug output (pretty print) - * - * @return {String} String which gives some information about the keymaterial - */ - this.toString = function() { - return '5.9. Literal Data Packet (Tag 11)\n' + ' length: ' - + this.packetLength + '\n' + ' format: ' + this.format - + '\n' + ' filename:' + this.filename + '\n' - + ' date: ' + this.date + '\n' + ' data: |' - + this.data + '|\n' + ' rdata: |' + this.real_data + '|\n'; - } -} - -/** - * Data types in the literal packet - * @readonly - * @enum {String} - */ -openpgp_packet_literaldata.formats = { - /** Binary data */ - binary: 'b', - /** Text data */ - text: 't', - /** Utf8 data */ - utf8: 'u' -}; // GPG4Browsers - An OpenPGP implementation in javascript // Copyright (C) 2011 Recurity Labs GmbH // @@ -12856,6 +12293,445 @@ function openpgp_packet_userid() { // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/** + * @class + * @classdesc Parent openpgp packet class. Operations focus on determining + * packet types and packet header. + */ +function _openpgp_packet() { + /** + * Encodes a given integer of length to the openpgp length specifier to a + * string + * + * @param {Integer} length The length to encode + * @return {String} String with openpgp length representation + */ + function encode_length(length) { + result = ""; + if (length < 192) { + result += String.fromCharCode(length); + } else if (length > 191 && length < 8384) { + /* + * let a = (total data packet length) - 192 let bc = two octet + * representation of a let d = b + 192 + */ + result += String.fromCharCode(((length - 192) >> 8) + 192); + result += String.fromCharCode((length - 192) & 0xFF); + } else { + result += String.fromCharCode(255); + result += String.fromCharCode((length >> 24) & 0xFF); + result += String.fromCharCode((length >> 16) & 0xFF); + result += String.fromCharCode((length >> 8) & 0xFF); + result += String.fromCharCode(length & 0xFF); + } + return result; + } + this.encode_length = encode_length; + + /** + * Writes a packet header version 4 with the given tag_type and length to a + * string + * + * @param {Integer} tag_type Tag type + * @param {Integer} length Length of the payload + * @return {String} String of the header + */ + function write_packet_header(tag_type, length) { + /* we're only generating v4 packet headers here */ + var result = ""; + result += String.fromCharCode(0xC0 | tag_type); + result += encode_length(length); + return result; + } + + /** + * Writes a packet header Version 3 with the given tag_type and length to a + * string + * + * @param {Integer} tag_type Tag type + * @param {Integer} length Length of the payload + * @return {String} String of the header + */ + function write_old_packet_header(tag_type, length) { + var result = ""; + if (length < 256) { + result += String.fromCharCode(0x80 | (tag_type << 2)); + result += String.fromCharCode(length); + } else if (length < 65536) { + result += String.fromCharCode(0x80 | (tag_type << 2) | 1); + result += String.fromCharCode(length >> 8); + result += String.fromCharCode(length & 0xFF); + } else { + result += String.fromCharCode(0x80 | (tag_type << 2) | 2); + result += String.fromCharCode((length >> 24) & 0xFF); + result += String.fromCharCode((length >> 16) & 0xFF); + result += String.fromCharCode((length >> 8) & 0xFF); + result += String.fromCharCode(length & 0xFF); + } + return result; + } + this.write_old_packet_header = write_old_packet_header; + this.write_packet_header = write_packet_header; + /** + * Generic static Packet Parser function + * + * @param {String} input Input stream as string + * @param {integer} position Position to start parsing + * @param {integer} len Length of the input from position on + * @return {Object} Returns a parsed openpgp_packet + */ + function read_packet(input, position, len) { + // some sanity checks + if (input == null || input.length <= position + || input.substring(position).length < 2 + || (input[position].charCodeAt() & 0x80) == 0) { + util + .print_error("Error during parsing. This message / key is probably not containing a valid OpenPGP format."); + return null; + } + var mypos = position; + var tag = -1; + var format = -1; + + format = 0; // 0 = old format; 1 = new format + if ((input[mypos].charCodeAt() & 0x40) != 0) { + format = 1; + } + + var packet_length_type; + if (format) { + // new format header + tag = input[mypos].charCodeAt() & 0x3F; // bit 5-0 + } else { + // old format header + tag = (input[mypos].charCodeAt() & 0x3F) >> 2; // bit 5-2 + packet_length_type = input[mypos].charCodeAt() & 0x03; // bit 1-0 + } + + // header octet parsing done + mypos++; + + // parsed length from length field + var bodydata = null; + + // used for partial body lengths + var real_packet_length = -1; + if (!format) { + // 4.2.1. Old Format Packet Lengths + switch (packet_length_type) { + case 0: // The packet has a one-octet length. The header is 2 octets + // long. + packet_length = input[mypos++].charCodeAt(); + break; + case 1: // The packet has a two-octet length. The header is 3 octets + // long. + packet_length = (input[mypos++].charCodeAt() << 8) + | input[mypos++].charCodeAt(); + break; + case 2: // The packet has a four-octet length. The header is 5 + // octets long. + packet_length = (input[mypos++].charCodeAt() << 24) + | (input[mypos++].charCodeAt() << 16) + | (input[mypos++].charCodeAt() << 8) + | input[mypos++].charCodeAt(); + break; + default: + // 3 - The packet is of indeterminate length. The header is 1 + // octet long, and the implementation must determine how long + // the packet is. If the packet is in a file, this means that + // the packet extends until the end of the file. In general, + // an implementation SHOULD NOT use indeterminate-length + // packets except where the end of the data will be clear + // from the context, and even then it is better to use a + // definite length, or a new format header. The new format + // headers described below have a mechanism for precisely + // encoding data of indeterminate length. + packet_length = len; + break; + } + + } else // 4.2.2. New Format Packet Lengths + { + + // 4.2.2.1. One-Octet Lengths + if (input[mypos].charCodeAt() < 192) { + packet_length = input[mypos++].charCodeAt(); + util.print_debug("1 byte length:" + packet_length); + // 4.2.2.2. Two-Octet Lengths + } else if (input[mypos].charCodeAt() >= 192 + && input[mypos].charCodeAt() < 224) { + packet_length = ((input[mypos++].charCodeAt() - 192) << 8) + + (input[mypos++].charCodeAt()) + 192; + util.print_debug("2 byte length:" + packet_length); + // 4.2.2.4. Partial Body Lengths + } else if (input[mypos].charCodeAt() > 223 + && input[mypos].charCodeAt() < 255) { + packet_length = 1 << (input[mypos++].charCodeAt() & 0x1F); + util.print_debug("4 byte length:" + packet_length); + // EEEK, we're reading the full data here... + var mypos2 = mypos + packet_length; + bodydata = input.substring(mypos, mypos + packet_length); + while (true) { + if (input[mypos2].charCodeAt() < 192) { + var tmplen = input[mypos2++].charCodeAt(); + packet_length += tmplen; + bodydata += input.substring(mypos2, mypos2 + tmplen); + mypos2 += tmplen; + break; + } else if (input[mypos2].charCodeAt() >= 192 + && input[mypos2].charCodeAt() < 224) { + var tmplen = ((input[mypos2++].charCodeAt() - 192) << 8) + + (input[mypos2++].charCodeAt()) + 192; + packet_length += tmplen; + bodydata += input.substring(mypos2, mypos2 + tmplen); + mypos2 += tmplen; + break; + } else if (input[mypos2].charCodeAt() > 223 + && input[mypos2].charCodeAt() < 255) { + var tmplen = 1 << (input[mypos2++].charCodeAt() & 0x1F); + packet_length += tmplen; + bodydata += input.substring(mypos2, mypos2 + tmplen); + mypos2 += tmplen; + } else { + mypos2++; + var tmplen = (input[mypos2++].charCodeAt() << 24) + | (input[mypos2++].charCodeAt() << 16) + | (input[mypos2++].charCodeAt() << 8) + | input[mypos2++].charCodeAt(); + bodydata += input.substring(mypos2, mypos2 + tmplen); + packet_length += tmplen; + mypos2 += tmplen; + break; + } + } + real_packet_length = mypos2; + // 4.2.2.3. Five-Octet Lengths + } else { + mypos++; + packet_length = (input[mypos++].charCodeAt() << 24) + | (input[mypos++].charCodeAt() << 16) + | (input[mypos++].charCodeAt() << 8) + | input[mypos++].charCodeAt(); + } + } + + // if there was'nt a partial body length: use the specified + // packet_length + if (real_packet_length == -1) { + real_packet_length = packet_length; + } + + if (bodydata == null) { + bodydata = input.substring(mypos, mypos + real_packet_length); + } + + // alert('tag type: '+this.tag+' length: '+packet_length); + var version = 1; // (old format; 2= new format) + // if (input[mypos++].charCodeAt() > 15) + // version = 2; + + var names_by_tag = {}; + + for(var i in this.type) + names_by_tag[this.type[i]] = i; + + var classname = 'openpgp_packet_' + names_by_tag[tag]; + + var packetclass = window[classname]; + + if(packetclass == undefined) { + throw classname; + util.print_error("openpgp.packet.js\n" + + "[ERROR] openpgp_packet: failed to parse packet @:" + + mypos + "\nchar:'" + + util.hexstrdump(input.substring(mypos)) + "'\ninput:" + + util.hexstrdump(input)); + return null; + } + + var result = new packetclass(); + result.read(bodydata); + + return { + packet: result, + offset: mypos + packet_length + }; + } + + this.read_packet = read_packet; + + + /** + * @enum {Integer} + * A list of packet type and numeric tags associated with them. + */ + this.type = { + reserved: 0, + public_key_encrypted_session_key: 1, + signature: 2, + symmetric_key_encrypted_session_key: 3, + one_pass_signature: 4, + secret_key: 5, + public_key: 6, + secret_subkey: 7, + compressed: 8, + symmetrically_encrypted: 9, + marker: 10, + literal: 11, + trust: 12, + userid: 13, + public_subkey: 14, + user_attribute: 17, + sym_encrypted_and_integrity_protected: 18, + modification_detection_code: 19 + }; +} + +var openpgp_packet = new _openpgp_packet(); + + +/** + * @class + * @classdesc This class represents a list of openpgp packets. + */ +function openpgp_packetlist() { + + /** @type {openpgp_packet_[]} A list of packets */ + this.packets = [] + + + + /** + * Reads a stream of binary data and interprents it as a list of packets. + * @param {openpgp_bytearray} An array of bytes. + */ + this.read = function(bytes) { + this.packets = []; + var i = 0; + + while(i < bytes.length) { + var parsed = openpgp_packet.read_packet(bytes, i, bytes.length - i); + i += parsed.offset; + + this.push(parsed.packet); + } + } + + /** + * Creates a binary representation of openpgp objects contained within the + * class instance. + * @returns {openpgp_bytearray} An array of bytes containing valid openpgp packets. + */ + this.write = function() { + var bytes = ''; + + for(var i in this.packets) { + var packetbytes = this.packets[i].write(); + bytes += openpgp_packet.write_packet_header(this.packets[i].tag, packetbytes.length); + bytes += packetbytes; + } + + return bytes; + } + + this.push = function(packet) { + this.packets.push(packet); + } + +} +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/** + * @class + * @classdesc Implementation of the Symmetrically Encrypted Data Packet (Tag 9) + * + * RFC4880 5.7: The Symmetrically Encrypted Data packet contains data encrypted + * with a symmetric-key algorithm. When it has been decrypted, it contains other + * packets (usually a literal data packet or compressed data packet, but in + * theory other Symmetrically Encrypted Data packets or sequences of packets + * that form whole OpenPGP messages). + */ + +function openpgp_packet_symmetrically_encrypted() { + this.tag = 9; + this.encrypted = null; + this.data = new openpgp_packetlist(); + this.algorithm = openpgp.symmetric.plaintext; + + + + this.read = function(bytes) { + this.encrypted = bytes; + } + + this.write = function() { + return this.encrypted; + } + + /** + * Symmetrically decrypt the packet data + * + * @param {Integer} symmetric_algorithm_type + * Symmetric key algorithm to use // See RFC4880 9.2 + * @param {String} key + * Key as string with the corresponding length to the + * algorithm + * @return The decrypted data; + */ + this.decrypt = function(symmetric_algorithm_type, key) { + var decrypted = openpgp_crypto_symmetricDecrypt( + symmetric_algorithm_type, key, this.encrypted, true); + + this.data.read(decrypted); + } + + this.encrypt = function(algo, key) { + var data = this.data.write(); + + this.encrypted = openpgp_crypto_symmetricEncrypt( + openpgp_crypto_getPrefixRandom(algo), algo, key, data, true); + } + + + this.toString = function () { + return '5.7. Symmetrically Encrypted Data Packet (Tag 9)\n' + + ' Used symmetric algorithm: ' + this.algorithmType + '\n' + + ' encrypted data: Bytes [' + + util.hexstrdump(this.encryptedData) + ']\n'; + } +}; +// GPG4Browsers - An OpenPGP implementation in javascript +// Copyright (C) 2011 Recurity Labs GmbH +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + /** * @class * @classdesc Implementation of type key id (RFC4880 3.3) diff --git a/resources/openpgp.min.js b/resources/openpgp.min.js index 67ff5cae..457ea4df 100644 --- a/resources/openpgp.min.js +++ b/resources/openpgp.min.js @@ -351,13 +351,14 @@ function(){for(var b=" OPENPGP Public Key\n length: "+this.len+"\n",b=b+" return b};this.validate=function(){for(var b=0;b>24&255);c+=String.fromCharCode(Math.round(this.date.getTime()/1E3)>>16&255);c+=String.fromCharCode(Math.round(this.date.getTime()/1E3)>>8&255);c+=String.fromCharCode(Math.round(this.date.getTime()/ +1E3)&255);return c+a};this.toString=function(){return"5.9. Literal Data Packet (Tag 11)\n length: "+this.packetLength+"\n format: "+this.format+"\n filename:"+this.filename+"\n date: "+this.date+"\n data: |"+this.data+"|\n rdata: |"+this.real_data+"|\n"}}openpgp_packet_literal.format={binary:"b",text:"t",utf8:"u"}; function openpgp_packet_compressed(b){this.tagType=8;this.compressedData=this.decompressedData=null;this.type=0;void 0!=b&&this.read(b);this.read=function(){this.type=input.charCodeAt(mypos++);this.compressedData=input.substring(position+1,position+len);this.decompressedData=null};this.write=function(){null==this.compressedData&&this.compress();return String.fromCharCode(this.type)+this.compress()};this.read_packet=function(a,b,d){this.packetLength=d;var e=b;this.type=a.charCodeAt(e++);this.compressedData= a.substring(b+1,b+d);return this};this.toString=function(){return"5.6. Compressed Data Packet (Tag 8)\n length: "+this.packetLength+"\n Compression Algorithm = "+this.type+"\n Compressed Data: Byte ["+util.hexstrdump(this.compressedData)+"]\n"};this.compress=function(){switch(this.type){case 0:this.compressedData=this.decompressedData;break;case 1:util.print_error("Compression algorithm ZIP [RFC1951] is not implemented.");break;case 2:util.print_error("Compression algorithm ZLIB [RFC1950] is not implemented."); break;case 3:util.print_error("Compression algorithm BZip2 [BZ2] is not implemented.");break;default:util.print_error("Compression algorithm unknown :"+this.type)}this.packetLength=this.compressedData.length+1;return this.compressedData};this.decompress=function(){if(null!=this.decompressedData)return this.decompressedData;if(null==this.type)return null;switch(this.type){case 0:this.decompressedData=this.compressedData;break;case 1:util.print_info("Decompressed packet [Type 1-ZIP]: "+this.toString()); var a=this.compressedData,a=s2r(a).replace(/\n/g,""),a=new JXG.Util.Unzip(JXG.Util.Base64.decodeAsArray(a));this.decompressedData=unescape(a.deflate()[0][0]);break;case 2:util.print_info("Decompressed packet [Type 2-ZLIB]: "+this.toString());if(8==this.compressedData.charCodeAt(0)%16){a=this.compressedData.substring(0,this.compressedData.length-4);a=s2r(a).replace(/\n/g,"");this.decompressedData=JXG.decompress(a);break}else util.print_error("Compression algorithm ZLIB only supports DEFLATE compression method."); break;case 3:util.print_error("Compression algorithm BZip2 [BZ2] is not implemented.");break;default:util.print_error("Compression algorithm unknown :"+this.type)}util.print_debug("decompressed:"+util.hexstrdump(this.decompressedData));return this.decompressedData};this.write_packet=function(a,b){this.decompressedData=b;if(null==a)this.type=1;var d=String.fromCharCode(this.type)+this.compress(this.type);return openpgp_packet.write_packet_header(8,d.length)+d}} -function openpgp_packet_encrypteddata(){this.tag=9;this.encrypted=null;this.data=new openpgp_packetlist;this.algorithm=openpgp.symmetric.plaintext;this.read=function(b){this.encrypted=b};this.write=function(){return this.encrypted};this.decrypt=function(b,a){var c=openpgp_crypto_symmetricDecrypt(b,a,this.encryptedData,!0);util.print_debug("openpgp.packet.encryptedintegrityprotecteddata.js\ndata: "+util.hexstrdump(this.decryptedData));this.data=new openpgp_packetlist(c)};this.encrypt=function(b,a){var c= -this.data.write();this.encrypted=openpgp_crypto_symmetricEncrypt(openpgp_crypto_getPrefixRandom(b),b,a,c,!0)};this.toString=function(){return"5.7. Symmetrically Encrypted Data Packet (Tag 9)\n Used symmetric algorithm: "+this.algorithmType+"\n encrypted data: Bytes ["+util.hexstrdump(this.encryptedData)+"]\n"}} function openpgp_packet_encryptedintegrityprotecteddata(){this.tagType=18;this.hash=this.decrytpedData=this.encryptedData=this.packetLength=this.version=null;this.write_packet=function(b,a,c){var d=openpgp_crypto_getPrefixRandom(b),e=d+d.charAt(d.length-2)+d.charAt(d.length-1),c=c+String.fromCharCode(211),c=c+String.fromCharCode(20);util.print_debug_hexstr_dump("data to be hashed:",e+c);c+=str_sha1(e+c);util.print_debug_hexstr_dump("hash:",c.substring(c.length-20,c.length));b=openpgp_crypto_symmetricEncrypt(d, b,a,c,!1).substring(0,e.length+c.length);a=openpgp_packet.write_packet_header(18,b.length+1)+String.fromCharCode(1);this.encryptedData=b;return a+b};this.read_packet=function(b,a,c){this.packetLength=c;this.version=b[a].charCodeAt();if(1!=this.version)return util.print_error("openpgp.packet.encryptedintegrityprotecteddata.js\nunknown encrypted integrity protected data packet version: "+this.version+" , @ "+a+"hex:"+util.hexstrdump(b)),null;this.encryptedData=b.substring(a+1,a+1+c);util.print_debug("openpgp.packet.encryptedintegrityprotecteddata.js\n"+ this.toString());return this};this.toString=function(){var b="";openpgp.config.debug&&(b=" data: Bytes ["+util.hexstrdump(this.encryptedData)+"]");return"5.13. Sym. Encrypted Integrity Protected Data Packet (Tag 18)\n length: "+this.packetLength+"\n version: "+this.version+"\n"+b};this.decrypt=function(b,a){this.decryptedData=openpgp_crypto_symmetricDecrypt(b,a,this.encryptedData,!1);this.hash=str_sha1(openpgp_crypto_MDCSystemBytes(b,a,this.encryptedData)+this.decryptedData.substring(0, @@ -368,17 +369,6 @@ d);if(s2k.s2kLength+da?result+=String.fromCharCode(a):191a?(result+=String.fromCharCode((a-192>>8)+192),result+=String.fromCharCode(a-192&255)):(result+=String.fromCharCode(255),result+=String.fromCharCode(a>>24&255),result+=String.fromCharCode(a>>16&255),result+=String.fromCharCode(a>>8&255),result+=String.fromCharCode(a&255));return result}this.encode_length=b;this.write_old_packet_header=function(a,b){var d="";256>b?(d+=String.fromCharCode(128|a<<2),d+= -String.fromCharCode(b)):(65536>b?(d+=String.fromCharCode(a<<2|129),d+=String.fromCharCode(b>>8)):(d+=String.fromCharCode(a<<2|130),d+=String.fromCharCode(b>>24&255),d+=String.fromCharCode(b>>16&255),d+=String.fromCharCode(b>>8&255)),d+=String.fromCharCode(b&255));return d};this.write_packet_header=function(a,c){var d;d=""+String.fromCharCode(192|a);return d+=b(c)};this.read_packet=function(a,b,d){if(null==a||a.length<=b||2>a.substring(b).length||0==(a[b].charCodeAt()&128))return util.print_error("Error during parsing. This message / key is probably not containing a valid OpenPGP format."), -null;var e=b,f=-1,g=-1,g=0;0!=(a[e].charCodeAt()&64)&&(g=1);var h;g?f=a[e].charCodeAt()&63:(f=(a[e].charCodeAt()&63)>>2,h=a[e].charCodeAt()&3);e++;var j=null,k=-1;if(g)if(192>a[e].charCodeAt())packet_length=a[e++].charCodeAt(),util.print_debug("1 byte length:"+packet_length);else if(192<=a[e].charCodeAt()&&224>a[e].charCodeAt())packet_length=(a[e++].charCodeAt()-192<<8)+a[e++].charCodeAt()+192,util.print_debug("2 byte length:"+packet_length);else if(223a[e].charCodeAt()){packet_length= -1<<(a[e++].charCodeAt()&31);util.print_debug("4 byte length:"+packet_length);k=e+packet_length;for(j=a.substring(e,e+packet_length);;)if(192>a[k].charCodeAt()){d=a[k++].charCodeAt();packet_length+=d;j+=a.substring(k,k+d);k+=d;break}else if(192<=a[k].charCodeAt()&&224>a[k].charCodeAt()){d=(a[k++].charCodeAt()-192<<8)+a[k++].charCodeAt()+192;packet_length+=d;j+=a.substring(k,k+d);k+=d;break}else if(223a[k].charCodeAt())d=1<<(a[k++].charCodeAt()&31),packet_length+=d,j+=a.substring(k, -k+d),k+=d;else{k++;d=a[k++].charCodeAt()<<24|a[k++].charCodeAt()<<16|a[k++].charCodeAt()<<8|a[k++].charCodeAt();j+=a.substring(k,k+d);packet_length+=d;k+=d;break}}else e++,packet_length=a[e++].charCodeAt()<<24|a[e++].charCodeAt()<<16|a[e++].charCodeAt()<<8|a[e++].charCodeAt();else switch(h){case 0:packet_length=a[e++].charCodeAt();break;case 1:packet_length=a[e++].charCodeAt()<<8|a[e++].charCodeAt();break;case 2:packet_length=a[e++].charCodeAt()<<24|a[e++].charCodeAt()<<16|a[e++].charCodeAt()<<8| -a[e++].charCodeAt();break;default:packet_length=d}-1==k&&(k=packet_length);null==j&&(j=a.substring(e,e+k));switch(f){case 0:break;case 1:f=new openpgp_packet_encryptedsessionkey;if(null!=f.read_pub_key_packet(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 2:f=new openpgp_packet_signature;if(null!=f.read_packet(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 3:f=new openpgp_packet_encryptedsessionkey;if(null!=f.read_symmetric_key_packet(j,0,packet_length))return f.headerLength= -e-b,f.packetLength=k,f;break;case 4:f=new openpgp_packet_onepasssignature;if(f.read_packet(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 5:f=new openpgp_packet_keymaterial;f.header=a.substring(b,e);if(null!=f.read_tag5(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 6:f=new openpgp_packet_keymaterial;f.header=a.substring(b,e);if(null!=f.read_tag6(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 7:f=new openpgp_packet_keymaterial; -if(null!=f.read_tag7(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 8:f=new openpgp_packet_compressed;if(null!=f.read_packet(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 9:f=new openpgp_packet_encrypteddata;if(null!=f.read_packet(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 10:f=new openpgp_packet_marker;if(null!=f.read_packet(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 11:f=new openpgp_packet_literaldata; -if(null!=f.read_packet(j,0,packet_length))return f.headerLength=e-b,f.header=a.substring(b,e),f.packetLength=k,f;break;case 12:break;case 13:f=new openpgp_packet_userid;if(null!=f.read_packet(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 14:f=new openpgp_packet_keymaterial;f.header=a.substring(b,e);if(null!=f.read_tag14(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 17:f=new openpgp_packet_userattribute;if(null!=f.read_packet(j,0,packet_length))return f.headerLength= -e-b,f.packetLength=k,f;break;case 18:f=new openpgp_packet_encryptedintegrityprotecteddata;if(null!=f.read_packet(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;case 19:f=new openpgp_packet_modificationdetectioncode;if(null!=f.read_packet(j,0,packet_length))return f.headerLength=e-b,f.packetLength=k,f;break;default:return util.print_error("openpgp.packet.js\n[ERROR] openpgp_packet: failed to parse packet @:"+e+"\nchar:'"+util.hexstrdump(a.substring(e))+"'\ninput:"+util.hexstrdump(a)), -null}};this.type={reserved:0,public_key_encrypted_session_key:1,signature:2,symmetric_key_encrypted_session_key:3,one_pass_signature:4,secret_key:5,public_key:6,secret_subkey:7,compressed:8,symmetrically_encrypted_data:9,marker:10,literal:11,trust:12,userid:13,public_subkey:14,user_attribute:17,sym_encrypted_and_integrity_protected_data:18,modification_detection_code:19}}var openpgp_packet=new _openpgp_packet; function openpgp_packet_keymaterial(){this.subKeyRevocationSignature=this.subKeySignature=this.parentNode=this.checksum=this.hasUnencryptedSecretKeyData=this.encryptedMPIData=this.IVLength=this.s2kUsageConventions=this.symmetricEncryptionAlgorithm=this.publicKey=this.secMPIs=this.MPIs=this.expiration=this.version=this.creationTime=this.tagType=this.publicKeyAlgorithm=null;this.read_tag5=function(b,a,c){this.tagType=5;this.read_priv_key(b,a,c);return this};this.read_tag6=function(b,a,c){this.tagType= 6;this.packetLength=c;this.read_pub_key(b,a,c);return this};this.read_tag7=function(b,a,c){this.tagType=7;this.packetLength=c;return this.read_priv_key(b,a,c)};this.read_tag14=function(b,a,c){this.subKeySignature=null;this.subKeyRevocationSignature=[];this.tagType=14;this.packetLength=c;this.read_pub_key(b,a,c);return this};this.toString=function(){var b="";switch(this.tagType){case 6:b+="5.5.1.1. Public-Key Packet (Tag 6)\n length: "+this.packetLength+"\n version: "+ this.version+"\n creation time: "+this.creationTime+"\n expiration time: "+this.expiration+"\n publicKeyAlgorithm: "+this.publicKeyAlgorithm+"\n";break;case 14:b+="5.5.1.2. Public-Subkey Packet (Tag 14)\n length: "+this.packetLength+"\n version: "+this.version+"\n creation time: "+this.creationTime+"\n expiration time: "+this.expiration+"\n publicKeyAlgorithm: "+this.publicKeyAlgorithm+"\n";break;case 5:b+="5.5.1.3. Secret-Key Packet (Tag 5)\n length: "+ @@ -406,11 +396,7 @@ this.parentNode.header.substring(1)+this.parentNode.data+String.fromCharCode(153 a),f=openpgp_crypto_getRandomBytes(8),util.print_debug_hexstr_dump("write_private_key Salt: ",f),e=e+f+String.fromCharCode(96),util.print_debug("write_private_key c: 96"),c=(new openpgp_type_s2k).write(3,d,c,f,96),this.symmetricEncryptionAlgorithm){case 3:this.IVLength=8;this.IV=openpgp_crypto_getRandomBytes(this.IVLength);ciphertextMPIs=normal_cfb_encrypt(function(a,b){var c=new openpgp_symenc_cast5;c.setKey(b);return c.encrypt(util.str2bin(a))},this.IVLength,util.str2bin(c.substring(0,16)),b+a, this.IV);e+=this.IV+ciphertextMPIs;break;case 7:case 8:case 9:this.IVLength=16,this.IV=openpgp_crypto_getRandomBytes(this.IVLength),ciphertextMPIs=normal_cfb_encrypt(AESencrypt,this.IVLength,c,b+a,this.IV),e+=this.IV+ciphertextMPIs}else e+=String.fromCharCode(0),e+=a.d.toMPI()+a.p.toMPI()+a.q.toMPI()+a.u.toMPI(),c=util.calc_checksum(a.d.toMPI()+a.p.toMPI()+a.q.toMPI()+a.u.toMPI()),e+=String.fromCharCode(c/256)+String.fromCharCode(c%256),util.print_debug_hexstr_dump("write_private_key basic checksum: "+ c);break;default:e="",util.print_error("openpgp.packet.keymaterial.js\nerror writing private key, unknown type :"+b)}c=openpgp_packet.write_packet_header(5,e.length);return{string:c+e,header:c,body:e}};this.write_public_key=function(b,a,c){var d=String.fromCharCode(4),d=d+c;switch(b){case 1:d+=String.fromCharCode(1);d+=a.n.toMPI();d+=a.ee.toMPI();break;default:util.print_error("openpgp.packet.keymaterial.js\nerror writing private key, unknown type :"+b)}b=openpgp_packet.write_packet_header(6,d.length); -return{string:b+d,header:b,body:d}}}function openpgp_packetlist(){this.list=[];this.read=function(b){for(var a=0;a>24&255);result+=String.fromCharCode(Math.round(this.date.getTime()/1E3)>>16&255);result+=String.fromCharCode(Math.round(this.date.getTime()/ -1E3)>>8&255);result+=String.fromCharCode(Math.round(this.date.getTime()/1E3)&255);return result+=a};this.toString=function(){return"5.9. Literal Data Packet (Tag 11)\n length: "+this.packetLength+"\n format: "+this.format+"\n filename:"+this.filename+"\n date: "+this.date+"\n data: |"+this.data+"|\n rdata: |"+this.real_data+"|\n"}}openpgp_packet_literaldata.formats={binary:"b",text:"t",utf8:"u"}; -function openpgp_packet_marker(){this.tagType=10;this.read_packet=function(b,a){this.packetLength=3;return 80==b[a].charCodeAt()&&71==b[a+1].charCodeAt()&&80==b[a+2].charCodeAt()?this:null};this.toString=function(){return'5.8. Marker Packet (Obsolete Literal Packet) (Tag 10)\n packet reads: "PGP"\n'}} +return{string:b+d,header:b,body:d}}}function openpgp_packet_marker(){this.tagType=10;this.read_packet=function(b,a){this.packetLength=3;return 80==b[a].charCodeAt()&&71==b[a+1].charCodeAt()&&80==b[a+2].charCodeAt()?this:null};this.toString=function(){return'5.8. Marker Packet (Obsolete Literal Packet) (Tag 10)\n packet reads: "PGP"\n'}} function openpgp_packet_modificationdetectioncode(){this.tagType=19;this.hash=null;this.read_packet=function(b,a,c){this.packetLength=c;if(20!=c)return util.print_error("openpgp.packet.modificationdetectioncode.js\ninvalid length for a modification detection code packet!"+c),null;this.hash=b.substring(a,a+20);return this};this.toString=function(){return"5.14 Modification detection code packet\n bytes ("+this.hash.length+"): ["+util.hexstrdump(this.hash)+"]"}} function openpgp_packet_onepasssignature(){this.tagType=4;this.flags=this.signingKeyId=this.publicKeyAlgorithm=this.hashAlgorithm=this.type=this.version=null;this.read_packet=read_packet;this.toString=function(){return"5.4. One-Pass Signature Packets (Tag 4)\n length: "+this.packetLength+"\n type: "+this.type+"\n keyID: "+this.signingKeyId.toString()+"\n hashA: "+this.hashAlgorithm+"\n pubKeyA:"+this.publicKeyAlgorithm+"\n flags: "+this.flags+"\n version:"+this.version+ "\n"};this.write_packet=write_packet} @@ -455,7 +441,16 @@ this.certificationSignatures[c].issuerKeyId)result[c]=0;else{var d=openpgp.keyri 24&255)+String.fromCharCode(a.length>>16&255)+String.fromCharCode(a.length>>8&255)+String.fromCharCode(a.length&255)+a;if(e.verify(f,d)){result[c]=this.certificationSignatures[c].issuerKeyId==b.getKeyId()?6:3;continue}}f=String.fromCharCode(153)+b.header.substring(1)+b.data+String.fromCharCode(180)+String.fromCharCode(a.length>>24&255)+String.fromCharCode(a.length>>16&255)+String.fromCharCode(a.length>>8&255)+String.fromCharCode(a.length&255)+a;result[c]=this.certificationSignatures[c].verify(f,d)? 4:0}}else if(3==this.certificationSignatures[c].version)if(null==this.certificationSignatures[c].keyId)result[c]=0;else if(d=openpgp.keyring.getPublicKeysForKeyId(this.certificationSignatures[c].keyId),null==d||0==d.length)result[c]=2;else if(d=publicKey.obj.getSigningKey(),null==d)result[c]=0;else{e=this.hasCertificationRevocationSignature(this.certificationSignatures[c].keyId);if(null!=e&&e.creationTime>this.certificationSignatures[c].creationTime&&(f=String.fromCharCode(153)+this.publicKeyPacket.header.substring(1)+ this.publicKeyPacket.data+a,e.verify(f,d))){result[c]=e.keyId==b.getKeyId()?6:3;continue}f=String.fromCharCode(153)+b.header.substring(1)+b.data+a;result[c]=this.certificationSignatures[c].verify(f,d)?4:0}else result[c]=0;return result};this.verify=function(b){b=this.verifyCertificationSignatures(b);return-1!=b.indexOf(6)?2:-1!=b.indexOf(5)?1:0};this.addCertification=function(){};this.revokeCertification=function(){}} -function openpgp_type_keyid(){this.read_packet=function(b,a){this.bytes=b.substring(a,a+8);return this};this.toString=function(){return util.hexstrdump(this.bytes)}} +function _openpgp_packet(){function b(a){result="";192>a?result+=String.fromCharCode(a):191a?(result+=String.fromCharCode((a-192>>8)+192),result+=String.fromCharCode(a-192&255)):(result+=String.fromCharCode(255),result+=String.fromCharCode(a>>24&255),result+=String.fromCharCode(a>>16&255),result+=String.fromCharCode(a>>8&255),result+=String.fromCharCode(a&255));return result}this.encode_length=b;this.write_old_packet_header=function(a,b){var d="";256>b?(d+=String.fromCharCode(128|a<<2),d+= +String.fromCharCode(b)):(65536>b?(d+=String.fromCharCode(a<<2|129),d+=String.fromCharCode(b>>8)):(d+=String.fromCharCode(a<<2|130),d+=String.fromCharCode(b>>24&255),d+=String.fromCharCode(b>>16&255),d+=String.fromCharCode(b>>8&255)),d+=String.fromCharCode(b&255));return d};this.write_packet_header=function(a,c){var d;d=""+String.fromCharCode(192|a);return d+=b(c)};this.read_packet=function(a,b,d){if(null==a||a.length<=b||2>a.substring(b).length||0==(a[b].charCodeAt()&128))return util.print_error("Error during parsing. This message / key is probably not containing a valid OpenPGP format."), +null;var e=-1,f=-1,f=0;0!=(a[b].charCodeAt()&64)&&(f=1);var g;f?e=a[b].charCodeAt()&63:(e=(a[b].charCodeAt()&63)>>2,g=a[b].charCodeAt()&3);b++;var h=null,j=-1;if(f)if(192>a[b].charCodeAt())packet_length=a[b++].charCodeAt(),util.print_debug("1 byte length:"+packet_length);else if(192<=a[b].charCodeAt()&&224>a[b].charCodeAt())packet_length=(a[b++].charCodeAt()-192<<8)+a[b++].charCodeAt()+192,util.print_debug("2 byte length:"+packet_length);else if(223a[b].charCodeAt()){packet_length= +1<<(a[b++].charCodeAt()&31);util.print_debug("4 byte length:"+packet_length);d=b+packet_length;for(h=a.substring(b,b+packet_length);;)if(192>a[d].charCodeAt()){g=a[d++].charCodeAt();packet_length+=g;h+=a.substring(d,d+g);d+=g;break}else if(192<=a[d].charCodeAt()&&224>a[d].charCodeAt()){g=(a[d++].charCodeAt()-192<<8)+a[d++].charCodeAt()+192;packet_length+=g;h+=a.substring(d,d+g);d+=g;break}else if(223a[d].charCodeAt())g=1<<(a[d++].charCodeAt()&31),packet_length+=g,h+=a.substring(d, +d+g),d+=g;else{d++;g=a[d++].charCodeAt()<<24|a[d++].charCodeAt()<<16|a[d++].charCodeAt()<<8|a[d++].charCodeAt();h+=a.substring(d,d+g);packet_length+=g;d+=g;break}j=d}else b++,packet_length=a[b++].charCodeAt()<<24|a[b++].charCodeAt()<<16|a[b++].charCodeAt()<<8|a[b++].charCodeAt();else switch(g){case 0:packet_length=a[b++].charCodeAt();break;case 1:packet_length=a[b++].charCodeAt()<<8|a[b++].charCodeAt();break;case 2:packet_length=a[b++].charCodeAt()<<24|a[b++].charCodeAt()<<16|a[b++].charCodeAt()<< +8|a[b++].charCodeAt();break;default:packet_length=d}-1==j&&(j=packet_length);null==h&&(h=a.substring(b,b+j));var a={},k;for(k in this.type)a[this.type[k]]=k;k="openpgp_packet_"+a[e];a=window[k];if(void 0==a)throw k;k=new a;k.read(h);return{packet:k,offset:b+packet_length}};this.type={reserved:0,public_key_encrypted_session_key:1,signature:2,symmetric_key_encrypted_session_key:3,one_pass_signature:4,secret_key:5,public_key:6,secret_subkey:7,compressed:8,symmetrically_encrypted:9,marker:10,literal:11, +trust:12,userid:13,public_subkey:14,user_attribute:17,sym_encrypted_and_integrity_protected:18,modification_detection_code:19}}var openpgp_packet=new _openpgp_packet; +function openpgp_packetlist(){this.packets=[];this.read=function(b){this.packets=[];for(var a=0;ae;e++)if(0==d>>e){c=e;break a}this.mpiBitLength=a+c;this.mpiByteLength=b.length;return this};this.toBin=function(){var b=String.fromCharCode(this.mpiBitLength>>8&255),b=b+String.fromCharCode(this.mpiBitLength&255);return b+=this.MPI};this.getByteLength=function(){return this.mpiByteLength}} function openpgp_type_s2k(){this.read=function(b,a){var c=a;this.type=b[c++].charCodeAt();switch(this.type){case 0:this.hashAlgorithm=b[c++].charCodeAt();this.s2kLength=1;break;case 1:this.hashAlgorithm=b[c++].charCodeAt();this.saltValue=b.substring(c,c+8);this.s2kLength=9;break;case 3:this.hashAlgorithm=b[c++].charCodeAt();this.saltValue=b.substring(c,c+8);c+=8;this.EXPBIAS=6;c=b[c++].charCodeAt();this.count=16+(c&15)<<(c>>4)+this.EXPBIAS;this.s2kLength=10;break;case 101:"GNU"==b.substring(c+1,c+ diff --git a/src/packet/openpgp.packet.literaldata.js b/src/packet/literal.js similarity index 91% rename from src/packet/openpgp.packet.literaldata.js rename to src/packet/literal.js index bc76f18d..5ffdfe1a 100644 --- a/src/packet/openpgp.packet.literaldata.js +++ b/src/packet/literal.js @@ -22,9 +22,9 @@ * RFC4880 5.9: A Literal Data packet contains the body of a message; data that * is not to be further interpreted. */ -function openpgp_packet_literaldata() { +function openpgp_packet_literal() { this.tag = 11; - this.format = openpgp_packet_literaldata.formats.utf8; + this.format = openpgp_packet_literal.format.utf8; this.data = ''; this.date = new Date(); @@ -34,7 +34,7 @@ function openpgp_packet_literaldata() { * bytes. Conversion to a proper utf8 encoding takes place when the * packet is written. * @param {String} str Any native javascript string - * @param {openpgp_packet_literaldata.formats} format + * @param {openpgp_packet_literaldata.format} format */ this.set_data = function(str, format) { this.format = format; @@ -45,12 +45,12 @@ function openpgp_packet_literaldata() { * Set the packet data to value represented by the provided string * of bytes together with the appropriate conversion format. * @param {String} bytes The string of bytes - * @param {openpgp_packet_literaldata.formats} format + * @param {openpgp_packet_literaldata.format} format */ this.set_data_bytes = function(bytes, format) { this.format = format; - if(format == openpgp_packet_literaldata.formats.utf8) + if(format == openpgp_packet_literal.format.utf8) bytes = util.decode_utf8(bytes); this.data = bytes; @@ -61,7 +61,7 @@ function openpgp_packet_literaldata() { * @returns {String} A sequence of bytes */ this.get_data_bytes = function() { - if(this.format == openpgp_packet_literaldata.formats.utf8) + if(this.format == openpgp_packet_literal.format.utf8) return util.encode_utf8(this.data); else return this.data; @@ -83,7 +83,7 @@ function openpgp_packet_literaldata() { this.read = function(bytes) { // - A one-octet field that describes how the data is formatted. - var format = input[position]; + var format = bytes[0]; this.filename = util.decode_utf8(bytes.substr(2, bytes .charCodeAt(1))); @@ -95,7 +95,6 @@ function openpgp_packet_literaldata() { + bytes.charCodeAt(1)); this.set_data_bytes(data, format); - return this; } /** @@ -109,6 +108,7 @@ function openpgp_packet_literaldata() { var data = this.get_data_bytes(); + var result = ''; result += this.format; result += String.fromCharCode(filename.length); result += filename; @@ -143,7 +143,7 @@ function openpgp_packet_literaldata() { * @readonly * @enum {String} */ -openpgp_packet_literaldata.formats = { +openpgp_packet_literal.format = { /** Binary data */ binary: 'b', /** Text data */ diff --git a/src/packet/openpgp.packet.js b/src/packet/packet.js similarity index 66% rename from src/packet/openpgp.packet.js rename to src/packet/packet.js index 36f84449..871d2875 100644 --- a/src/packet/openpgp.packet.js +++ b/src/packet/packet.js @@ -252,153 +252,32 @@ function _openpgp_packet() { // if (input[mypos++].charCodeAt() > 15) // version = 2; - switch (tag) { - case 0: // Reserved - a packet tag MUST NOT have this value - break; - case 1: // Public-Key Encrypted Session Key Packet - var result = new openpgp_packet_encryptedsessionkey(); - if (result.read_pub_key_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 2: // Signature Packet - var result = new openpgp_packet_signature(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 3: // Symmetric-Key Encrypted Session Key Packet - var result = new openpgp_packet_encryptedsessionkey(); - if (result.read_symmetric_key_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 4: // One-Pass Signature Packet - var result = new openpgp_packet_onepasssignature(); - if (result.read_packet(bodydata, 0, packet_length)) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 5: // Secret-Key Packet - var result = new openpgp_packet_keymaterial(); - result.header = input.substring(position, mypos); - if (result.read_tag5(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 6: // Public-Key Packet - var result = new openpgp_packet_keymaterial(); - result.header = input.substring(position, mypos); - if (result.read_tag6(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 7: // Secret-Subkey Packet - var result = new openpgp_packet_keymaterial(); - if (result.read_tag7(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 8: // Compressed Data Packet - var result = new openpgp_packet_compressed(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 9: // Symmetrically Encrypted Data Packet - var result = new openpgp_packet_encrypteddata(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 10: // Marker Packet = PGP (0x50, 0x47, 0x50) - var result = new openpgp_packet_marker(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 11: // Literal Data Packet - var result = new openpgp_packet_literaldata(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.header = input.substring(position, mypos); - result.packetLength = real_packet_length; - return result; - } - break; - case 12: // Trust Packet - // TODO: to be implemented - break; - case 13: // User ID Packet - var result = new openpgp_packet_userid(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 14: // Public-Subkey Packet - var result = new openpgp_packet_keymaterial(); - result.header = input.substring(position, mypos); - if (result.read_tag14(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 17: // User Attribute Packet - var result = new openpgp_packet_userattribute(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 18: // Sym. Encrypted and Integrity Protected Data Packet - var result = new openpgp_packet_encryptedintegrityprotecteddata(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - case 19: // Modification Detection Code Packet - var result = new openpgp_packet_modificationdetectioncode(); - if (result.read_packet(bodydata, 0, packet_length) != null) { - result.headerLength = mypos - position; - result.packetLength = real_packet_length; - return result; - } - break; - default: + var names_by_tag = {}; + + for(var i in this.type) + names_by_tag[this.type[i]] = i; + + var classname = 'openpgp_packet_' + names_by_tag[tag]; + + var packetclass = window[classname]; + + if(packetclass == undefined) { + throw classname; util.print_error("openpgp.packet.js\n" + "[ERROR] openpgp_packet: failed to parse packet @:" + mypos + "\nchar:'" + util.hexstrdump(input.substring(mypos)) + "'\ninput:" + util.hexstrdump(input)); return null; - break; } + + var result = new packetclass(); + result.read(bodydata); + + return { + packet: result, + offset: mypos + packet_length + }; } this.read_packet = read_packet; @@ -418,14 +297,14 @@ function _openpgp_packet() { public_key: 6, secret_subkey: 7, compressed: 8, - symmetrically_encrypted_data: 9, + symmetrically_encrypted: 9, marker: 10, literal: 11, trust: 12, userid: 13, public_subkey: 14, user_attribute: 17, - sym_encrypted_and_integrity_protected_data: 18, + sym_encrypted_and_integrity_protected: 18, modification_detection_code: 19 }; } diff --git a/src/packet/openpgp.packetlist.js b/src/packet/packetlist.js similarity index 67% rename from src/packet/openpgp.packetlist.js rename to src/packet/packetlist.js index 69994410..d00c1190 100644 --- a/src/packet/openpgp.packetlist.js +++ b/src/packet/packetlist.js @@ -7,7 +7,7 @@ function openpgp_packetlist() { /** @type {openpgp_packet_[]} A list of packets */ - this.list = [] + this.packets = [] @@ -16,13 +16,14 @@ function openpgp_packetlist() { * @param {openpgp_bytearray} An array of bytes. */ this.read = function(bytes) { + this.packets = []; var i = 0; while(i < bytes.length) { - var packet = openpgp_packet.read_packet(bytes, i, bytes.length - i); - i += packet.headerLength + packet.packetLength; + var parsed = openpgp_packet.read_packet(bytes, i, bytes.length - i); + i += parsed.offset; - list.push(packet); + this.push(parsed.packet); } } @@ -34,9 +35,9 @@ function openpgp_packetlist() { this.write = function() { var bytes = ''; - for(var i in this.list) { - var packetbytes = this.list[i].write(); - bytes += openpgp_packet.write_packet_header(this.list[i].tag, packetbytes.length); + for(var i in this.packets) { + var packetbytes = this.packets[i].write(); + bytes += openpgp_packet.write_packet_header(this.packets[i].tag, packetbytes.length); bytes += packetbytes; } @@ -44,7 +45,7 @@ function openpgp_packetlist() { } this.push = function(packet) { - this.list.push(packet); + this.packets.push(packet); } } diff --git a/src/packet/openpgp.packet.encrypteddata.js b/src/packet/symmetrically_encrypted.js similarity index 89% rename from src/packet/openpgp.packet.encrypteddata.js rename to src/packet/symmetrically_encrypted.js index 116ba537..2855ed46 100644 --- a/src/packet/openpgp.packet.encrypteddata.js +++ b/src/packet/symmetrically_encrypted.js @@ -26,7 +26,7 @@ * that form whole OpenPGP messages). */ -function openpgp_packet_encrypteddata() { +function openpgp_packet_symmetrically_encrypted() { this.tag = 9; this.encrypted = null; this.data = new openpgp_packetlist(); @@ -54,13 +54,9 @@ function openpgp_packet_encrypteddata() { */ this.decrypt = function(symmetric_algorithm_type, key) { var decrypted = openpgp_crypto_symmetricDecrypt( - symmetric_algorithm_type, key, this.encryptedData, true); + symmetric_algorithm_type, key, this.encrypted, true); - util.print_debug("openpgp.packet.encryptedintegrityprotecteddata.js\n"+ - "data: "+util.hexstrdump(this.decryptedData)); - - - this.data = new openpgp_packetlist(decrypted); + this.data.read(decrypted); } this.encrypt = function(algo, key) { diff --git a/test/general/packet.js b/test/general/packet.js index fc1843a2..d99a3bd1 100644 --- a/test/general/packet.js +++ b/test/general/packet.js @@ -5,10 +5,10 @@ unittests.register("Packet testing", function() { - var literal = new openpgp_packet_literaldata(); - literal.set_data('Hello world', openpgp_packet_literaldata.formats.utf8); + var literal = new openpgp_packet_literal(); + literal.set_data('Hello world', openpgp_packet_literal.format.utf8); - var enc = new openpgp_packet_encrypteddata(); + var enc = new openpgp_packet_symmetrically_encrypted(); enc.data.push(literal); var key = '12345678901234567890123456789012', @@ -23,9 +23,10 @@ unittests.register("Packet testing", function() { var msg2 = new openpgp_packetlist(); msg2.read(message.write()); - msg2[0].decrypt(algo, key); + msg2.packets[0].decrypt(algo, key); - return msg2[0].data[0].data == literal.data; + return new test_result('Symmetrically encrypted data packet', + msg2.packets[0].data.packets[0].data == literal.data); }]; var results = [];