Added test and working code to the sym encrypted integrity protected packet.

This commit is contained in:
Michal Kolodziej
2013-04-22 19:56:51 +02:00
parent 3f04470e1f
commit 3a3764a436
8 changed files with 550 additions and 632 deletions

View File

@@ -458,6 +458,17 @@ function _openpgp () {
var openpgp = new _openpgp();
/** RFC4880, section 9.1
* @enum {Integer}
*/
openpgp.publickey = {
rsa_encrypt_sign: 1,
rsa_encrypt: 2,
rsa_sign: 3,
elgamal: 16,
dsa: 17
};
/** RFC4880, section 9.2
* @enum {Integer}
*/
@@ -474,4 +485,27 @@ openpgp.symmetric = {
twofish: 10
};
/** RFC4880, section 9.3
* @enum {Integer}
*/
openpgp.compression = {
uncompressed: 0,
/** RFC1951 */
zip: 1,
/** RFC1950 */
zlib: 2,
bzip2: 3
};
/** RFC4880, section 9.4
* @enum {Integer}
*/
openpgp.hash = {
md5: 1,
sha1: 2,
ripemd: 3,
sha256: 8,
sha384: 9,
sha512: 10,
sha224: 11
};

View File

@@ -25,14 +25,12 @@
* a Signature or One-Pass Signature packet, and contains a literal data
* packet.
*/
function openpgp_packet_compressed(bytes) {
this.tagType = 8;
this.decompressedData = null;
this.compressedData = null;
this.type = 0;
function openpgp_packet_compressed() {
this.tag = 8;
this.packets = new openpgp_packetlist();
this.algorithm = openpgp.compression.uncompressed;
this.compressed = null;
if(bytes != undefined)
this.read(bytes);
/**
* Parsing function for the packet.
@@ -42,27 +40,22 @@ function openpgp_packet_compressed(bytes) {
* input at position
* @return {openpgp_packet_compressed} Object representation
*/
function read_packet (input, position, len) {
this.packetLength = len;
var mypos = position;
this.read = function(bytes) {
// One octet that gives the algorithm used to compress the packet.
this.type = input.charCodeAt(mypos++);
this.algorithm = input.charCodeAt(0);
// Compressed data, which makes up the remainder of the packet.
this.compressedData = input.substring(position+1, position+len);
return this;
this.compressed = input.substr(1);
this.decompress();
}
this.read = function(bytes) {
this.type = input.charCodeAt(mypos++);
this.compressedData = input.substring(position+1, position+len);
this.decompressedData = null;
}
this.write = function() {
if(this.compressedData == null)
if(this.compressed == null)
this.compress();
return String.fromCharCode(this.type) + this.compress();
return String.fromCharCode(this.type) + this.compressed;
}
@@ -71,51 +64,61 @@ function openpgp_packet_compressed(bytes) {
* read by read_packet
* @return {String} The decompressed data
*/
function decompress() {
if (this.decompressedData != null)
return this.decompressedData;
this.decompress = function() {
var bytes;
if (this.type == null)
return null;
switch (this.type) {
case 0: // - Uncompressed
this.decompressedData = this.compressedData;
switch (this.algorithm) {
case openpgp.compression.uncompressed:
decompressed = this.compressed;
break;
case 1: // - ZIP [RFC1951]
case openpgp.compression.zip:
util.print_info('Decompressed packet [Type 1-ZIP]: ' + this.toString());
var compData = this.compressedData;
var compData = this.compressed;
var radix = s2r(compData).replace(/\n/g,"");
// no header in this case, directly call deflate
var jxg_obj = new JXG.Util.Unzip(JXG.Util.Base64.decodeAsArray(radix));
this.decompressedData = unescape(jxg_obj.deflate()[0][0]);
decompressed = unescape(jxg_obj.deflate()[0][0]);
break;
case 2: // - ZLIB [RFC1950]
case openpgp.compression.zlib:
util.print_info('Decompressed packet [Type 2-ZLIB]: ' + this.toString());
var compressionMethod = this.compressedData.charCodeAt(0) % 0x10; //RFC 1950. Bits 0-3 Compression Method
//RFC 1950. Bits 0-3 Compression Method
var compressionMethod = this.compressed.charCodeAt(0) % 0x10;
//Bits 4-7 RFC 1950 are LZ77 Window. Generally this value is 7 == 32k window size.
//2nd Byte in RFC 1950 is for "FLAGs" Allows for a Dictionary (how is this defined). Basic checksum, and compression level.
// 2nd Byte in RFC 1950 is for "FLAGs" Allows for a Dictionary
// (how is this defined). Basic checksum, and compression level.
if (compressionMethod == 8) { //CM 8 is for DEFLATE, RFC 1951
// remove 4 bytes ADLER32 checksum from the end
var compData = this.compressedData.substring(0, this.compressedData.length - 4);
var compData = this.compressed.substring(0, this.compressed.length - 4);
var radix = s2r(compData).replace(/\n/g,"");
//TODO check ADLER32 checksum
this.decompressedData = JXG.decompress(radix);
decompressed = JXG.decompress(radix);
break;
} else {
util.print_error("Compression algorithm ZLIB only supports DEFLATE compression method.");
util.print_error("Compression algorithm ZLIB only supports " +
"DEFLATE compression method.");
}
break;
case 3: // - BZip2 [BZ2]
case openpgp.compression.bzip2:
// TODO: need to implement this
util.print_error("Compression algorithm BZip2 [BZ2] is not implemented.");
break;
default:
util.print_error("Compression algorithm unknown :"+this.type);
break;
}
util.print_debug("decompressed:"+util.hexstrdump(this.decompressedData));
return this.decompressedData;
util.print_debug("decompressed:"+util.hexstrdump(decompressed));
this.packets.read(decompressed);
}
/**
@@ -124,59 +127,41 @@ function openpgp_packet_compressed(bytes) {
* @param {String} data Data to be compressed
* @return {String} The compressed data stored in attribute compressedData
*/
function compress() {
this.compress = function() {
switch (this.type) {
case 0: // - Uncompressed
this.compressedData = this.decompressedData;
case openpgp.compression.uncompressed: // - Uncompressed
this.compressed = this.packets.write();
break;
case 1: // - ZIP [RFC1951]
case openpgp.compression.zip: // - ZIP [RFC1951]
util.print_error("Compression algorithm ZIP [RFC1951] is not implemented.");
break;
case 2: // - ZLIB [RFC1950]
case openpgp.compression.zlib: // - ZLIB [RFC1950]
// TODO: need to implement this
util.print_error("Compression algorithm ZLIB [RFC1950] is not implemented.");
break;
case 3: // - BZip2 [BZ2]
case openpgp.compression.bzip2: // - BZip2 [BZ2]
// TODO: need to implement this
util.print_error("Compression algorithm BZip2 [BZ2] is not implemented.");
break;
default:
util.print_error("Compression algorithm unknown :"+this.type);
break;
}
this.packetLength = this.compressedData.length +1;
return this.compressedData;
}
/**
* Creates a string representation of the packet
* @param {Integer} algorithm Algorithm to be used // See RFC 4880 9.3
* @param {String} data Data to be compressed
* @return {String} String-representation of the packet
*/
function write_packet(algorithm, data) {
this.decompressedData = data;
if (algorithm == null) {
this.type = 1;
}
var result = String.fromCharCode(this.type)+this.compress(this.type);
return openpgp_packet.write_packet_header(8, result.length)+result;
}
/**
* Pretty printing the packet (useful for debug purposes)
* @return {String}
*/
function toString() {
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';
' Compression Algorithm = '+this.algorithm+'\n'+
' Compressed Data: Byte ['+util.hexstrdump(this.compressed)+']\n';
}
this.read_packet = read_packet;
this.toString = toString;
this.compress = compress;
this.decompress = decompress;
this.write_packet = write_packet;
};

View File

@@ -1,79 +0,0 @@
// 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 Modification Detection Code Packet (Tag 19)
*
* RFC4880 5.14: The Modification Detection Code packet contains a SHA-1 hash of
* plaintext data, which is used to detect message modification. It is only used
* with a Symmetrically Encrypted Integrity Protected Data packet. The
* Modification Detection Code packet MUST be the last packet in the plaintext
* data that is encrypted in the Symmetrically Encrypted Integrity Protected
* Data packet, and MUST appear in no other place.
*/
function openpgp_packet_modificationdetectioncode() {
this.tagType = 19;
this.hash = null;
/**
* parsing function for a modification detection code packet (tag 19).
*
* @param {String} input payload of a tag 19 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
*/
function read_packet(input, position, len) {
this.packetLength = len;
if (len != 20) {
util
.print_error("openpgp.packet.modificationdetectioncode.js\n"
+ 'invalid length for a modification detection code packet!'
+ len);
return null;
}
// - A 20-octet SHA-1 hash of the preceding plaintext data of the
// Symmetrically Encrypted Integrity Protected Data packet,
// including prefix data, the tag octet, and length octet of the
// Modification Detection Code packet.
this.hash = input.substring(position, position + 20);
return this;
}
/*
* this packet is created within the encryptedintegrityprotected packet
* function write_packet(data) { }
*/
/**
* generates debug output (pretty print)
*
* @return {String} String which gives some information about the
* modification detection code
*/
function toString() {
return '5.14 Modification detection code packet\n' + ' bytes ('
+ this.hash.length + '): [' + util.hexstrdump(this.hash) + ']';
}
this.read_packet = read_packet;
this.toString = toString;
};

View File

@@ -304,7 +304,7 @@ function _openpgp_packet() {
userid: 13,
public_subkey: 14,
user_attribute: 17,
sym_encrypted_and_integrity_protected: 18,
sym_encrypted_integrity_protected: 18,
modification_detection_code: 19
};
}

View File

@@ -27,13 +27,14 @@
* packet.
*/
function openpgp_packet_encryptedintegrityprotecteddata() {
this.tagType = 18;
this.version = null; // integer == 1
this.packetLength = null; // integer
this.encryptedData = null; // string
this.decrytpedData = null; // string
function openpgp_packet_sym_encrypted_integrity_protected() {
this.tag = 18;
this.version = 1;
this.encrypted = null; // string
this.hash = null; // string
this.data = new openpgp_packetlist();
this.algorithm = openpgp.symmetric.plaintext;
/**
* Parsing function for the packet.
*
@@ -45,28 +46,23 @@ function openpgp_packet_encryptedintegrityprotecteddata() {
* @return {openpgp_packet_encryptedintegrityprotecteddata} object
* representation
*/
function read_packet(input, position, len) {
this.packetLength = len;
this.read = function(bytes) {
// - A one-octet version number. The only currently defined value is
// 1.
this.version = input[position].charCodeAt();
this.version = bytes[0].charCodeAt();
if (this.version != 1) {
util
.print_error('openpgp.packet.encryptedintegrityprotecteddata.js\nunknown encrypted integrity protected data packet version: '
util.print_error('openpgp.packet.encryptedintegrityprotecteddata.js' +
'\nunknown encrypted integrity protected data packet version: '
+ this.version
+ " , @ "
+ position
+ "hex:"
+ util.hexstrdump(input));
+ util.hexstrdump(bytes));
return null;
}
// - Encrypted data, the output of the selected symmetric-key cipher
// operating in Cipher Feedback mode with shift amount equal to the
// block size of the cipher (CFB-n where n is the block size).
this.encryptedData = input.substring(position + 1, position + 1 + len);
util.print_debug("openpgp.packet.encryptedintegrityprotecteddata.js\n"
+ this.toString());
return this;
this.encrypted = bytes.substr(1);
}
/**
@@ -80,28 +76,34 @@ function openpgp_packet_encryptedintegrityprotecteddata() {
* Plaintext data to be encrypted within the packet
* @return {String} A string representation of the packet
*/
function write_packet(symmetric_algorithm, key, data) {
this.write = function(symmetric_algorithm, key, data) {
return String.fromCharCode(this.version) + this.encrypted;
}
this.encrypt = function(symmetric_algorithm, key) {
var bytes = this.data.write()
var prefixrandom = openpgp_crypto_getPrefixRandom(symmetric_algorithm);
var prefix = prefixrandom
+ prefixrandom.charAt(prefixrandom.length - 2)
+ prefixrandom.charAt(prefixrandom.length - 1);
var tohash = data;
+ prefixrandom.charAt(prefixrandom.length - 1)
var tohash = bytes;
tohash += String.fromCharCode(0xD3);
tohash += String.fromCharCode(0x14);
util.print_debug_hexstr_dump("data to be hashed:"
, prefix + tohash);
tohash += str_sha1(prefix + tohash);
util.print_debug_hexstr_dump("hash:"
, tohash.substring(tohash.length - 20,
tohash.length));
var result = openpgp_crypto_symmetricEncrypt(prefixrandom,
this.encrypted = openpgp_crypto_symmetricEncrypt(prefixrandom,
symmetric_algorithm, key, tohash, false).substring(0,
prefix.length + tohash.length);
var header = openpgp_packet.write_packet_header(18, result.length + 1)
+ String.fromCharCode(1);
this.encryptedData = result;
return header + result;
}
/**
@@ -113,34 +115,39 @@ function openpgp_packet_encryptedintegrityprotecteddata() {
* @param {String} key The key of cipher blocksize length to be used
* @return {String} The decrypted data of this packet
*/
function decrypt(symmetric_algorithm_type, key) {
this.decryptedData = openpgp_crypto_symmetricDecrypt(
symmetric_algorithm_type, key, this.encryptedData, false);
this.decrypt = function(symmetric_algorithm_type, key) {
var decrypted = openpgp_crypto_symmetricDecrypt(
symmetric_algorithm_type, key, this.encrypted, false);
// there must be a modification detection code packet as the
// last packet and everything gets hashed except the hash itself
this.hash = str_sha1(openpgp_crypto_MDCSystemBytes(
symmetric_algorithm_type, key, this.encryptedData)
+ this.decryptedData.substring(0,
this.decryptedData.length - 20));
this.hash = str_sha1(
openpgp_crypto_MDCSystemBytes(symmetric_algorithm_type, key, this.encrypted)
+ decrypted.substring(0, decrypted.length - 20));
util.print_debug_hexstr_dump("calc hash = ", this.hash);
if (this.hash == this.decryptedData.substring(
this.decryptedData.length - 20, this.decryptedData.length))
return this.decryptedData;
else
util
.print_error("Decryption stopped: discovered a modification of encrypted data.");
return null;
this.data.read(decrypted);
// We pop the mandatory modification detection code packet.
var mdc = this.data.packets.pop();
if(this.hash != mdc.hash) {
this.data = null;
util.print_error("Decryption stopped: discovered a " +
"modification of encrypted data.");
return;
}
}
function toString() {
this.toString = function() {
var data = '';
if(openpgp.config.debug)
data = ' data: Bytes ['
+ util.hexstrdump(this.encryptedData) + ']';
+ util.hexstrdump(this.encrypted) + ']';
return '5.13. Sym. Encrypted Integrity Protected Data Packet (Tag 18)\n'
+ ' length: '
+ this.packetLength
+ '\n'
+ ' version: '
+ this.version
@@ -148,8 +155,11 @@ function openpgp_packet_encryptedintegrityprotecteddata() {
+ data;
}
this.write_packet = write_packet;
this.read_packet = read_packet;
this.toString = toString;
this.decrypt = decrypt;
};
function openpgp_packet_modification_detection_code() {
this.hash = null;
this.read = function(bytes) {
this.hash = bytes;
}
}