binary strings to typed arrays in most places

This commit is contained in:
Bart Butler 2015-04-17 16:10:27 -07:00 committed by Tankred Hase
parent b310877c7d
commit b4916e29a3
41 changed files with 802 additions and 677 deletions

View File

@ -1,3 +1,5 @@
// Modified by ProtonTech AG
// Modified by Recurity Labs GmbH // Modified by Recurity Labs GmbH
// modified version of http://www.hanewin.net/encrypt/PGdecode.js: // modified version of http://www.hanewin.net/encrypt/PGdecode.js:
@ -17,32 +19,30 @@
/** /**
* @requires crypto/cipher * @requires crypto/cipher
* @requires util
* @module crypto/cfb * @module crypto/cfb
*/ */
'use strict'; 'use strict';
var util = require('../util.js'), var cipher = require('./cipher');
cipher = require('./cipher');
module.exports = { module.exports = {
/** /**
* This function encrypts a given with the specified prefixrandom * This function encrypts a given with the specified prefixrandom
* using the specified blockcipher to encrypt a message * using the specified blockcipher to encrypt a message
* @param {String} prefixrandom random bytes of block_size length provided * @param {Uint8Array} prefixrandom random bytes of block_size length
* as a string to be used in prefixing the data * to be used in prefixing the data
* @param {String} cipherfn the algorithm cipher class to encrypt * @param {String} cipherfn the algorithm cipher class to encrypt
* data in one block_size encryption, {@link module:crypto/cipher}. * data in one block_size encryption, {@link module:crypto/cipher}.
* @param {String} plaintext data to be encrypted provided as a string * @param {Uint8Array} plaintext data to be encrypted
* @param {String} key binary string representation of key to be used to encrypt the plaintext. * @param {Uint8Array} key key to be used to encrypt the plaintext.
* This will be passed to the cipherfn * This will be passed to the cipherfn
* @param {Boolean} resync a boolean value specifying if a resync of the * @param {Boolean} resync a boolean value specifying if a resync of the
* IV should be used or not. The encrypteddatapacket uses the * IV should be used or not. The encrypteddatapacket uses the
* "old" style with a resync. Encryption within an * "old" style with a resync. Encryption within an
* encryptedintegrityprotecteddata packet is not resyncing the IV. * encryptedintegrityprotecteddata packet is not resyncing the IV.
* @return {String} a string with the encrypted data * @return {Uint8Array} encrypted data
*/ */
encrypt: function(prefixrandom, cipherfn, plaintext, key, resync) { encrypt: function(prefixrandom, cipherfn, plaintext, key, resync) {
cipherfn = new cipher[cipherfn](key); cipherfn = new cipher[cipherfn](key);
@ -51,7 +51,12 @@ module.exports = {
var FR = new Uint8Array(block_size); var FR = new Uint8Array(block_size);
var FRE = new Uint8Array(block_size); var FRE = new Uint8Array(block_size);
prefixrandom = prefixrandom + prefixrandom.charAt(block_size - 2) + prefixrandom.charAt(block_size - 1); var new_prefix = new Uint8Array(prefixrandom.length+2);
new_prefix.set(prefixrandom);
new_prefix[prefixrandom.length] = prefixrandom[block_size-2];
new_prefix[prefixrandom.length+1] = prefixrandom[block_size-1];
prefixrandom = new_prefix;
var ciphertext = new Uint8Array(plaintext.length + 2 + block_size * 2); var ciphertext = new Uint8Array(plaintext.length + 2 + block_size * 2);
var i, n, begin; var i, n, begin;
var offset = resync ? 0 : 2; var offset = resync ? 0 : 2;
@ -68,7 +73,7 @@ module.exports = {
// the plaintext to produce C[1] through C[BS], the first BS octets // the plaintext to produce C[1] through C[BS], the first BS octets
// of ciphertext. // of ciphertext.
for (i = 0; i < block_size; i++) { for (i = 0; i < block_size; i++) {
ciphertext[i] = FRE[i] ^ prefixrandom.charCodeAt(i); ciphertext[i] = FRE[i] ^ prefixrandom[i];
} }
// 4. FR is loaded with C[1] through C[BS]. // 4. FR is loaded with C[1] through C[BS].
@ -81,8 +86,8 @@ module.exports = {
// 6. The left two octets of FRE get xored with the next two octets of // 6. The left two octets of FRE get xored with the next two octets of
// data that were prefixed to the plaintext. This produces C[BS+1] // data that were prefixed to the plaintext. This produces C[BS+1]
// and C[BS+2], the next two octets of ciphertext. // and C[BS+2], the next two octets of ciphertext.
ciphertext[block_size] = FRE[0] ^ prefixrandom.charCodeAt(block_size); ciphertext[block_size] = FRE[0] ^ prefixrandom[block_size];
ciphertext[block_size + 1] = FRE[1] ^ prefixrandom.charCodeAt(block_size + 1); ciphertext[block_size + 1] = FRE[1] ^ prefixrandom[block_size + 1];
if (resync) { if (resync) {
// 7. (The resync step) FR is loaded with C[3] through C[BS+2]. // 7. (The resync step) FR is loaded with C[3] through C[BS+2].
@ -98,7 +103,7 @@ module.exports = {
// data. This produces C[BS+3] through C[BS+(BS+2)], the next BS // data. This produces C[BS+3] through C[BS+(BS+2)], the next BS
// octets of ciphertext. // octets of ciphertext.
for (i = 0; i < block_size; i++) { for (i = 0; i < block_size; i++) {
ciphertext[block_size + 2 + i] = FRE[i + offset] ^ plaintext.charCodeAt(i); ciphertext[block_size + 2 + i] = FRE[i + offset] ^ plaintext[i];
} }
for (n = block_size; n < plaintext.length + offset; n += block_size) { for (n = block_size; n < plaintext.length + offset; n += block_size) {
// 10. FR is loaded with C[BS+3] to C[BS + (BS+2)] (which is C11-C18 for // 10. FR is loaded with C[BS+3] to C[BS + (BS+2)] (which is C11-C18 for
@ -113,22 +118,22 @@ module.exports = {
// the next BS octets of ciphertext. These are loaded into FR, and // the next BS octets of ciphertext. These are loaded into FR, and
// the process is repeated until the plaintext is used up. // the process is repeated until the plaintext is used up.
for (i = 0; i < block_size; i++) { for (i = 0; i < block_size; i++) {
ciphertext[block_size + begin + i] = FRE[i] ^ plaintext.charCodeAt(n + i - offset); ciphertext[block_size + begin + i] = FRE[i] ^ plaintext[n + i - offset];
} }
} }
ciphertext = ciphertext.subarray(0, plaintext.length + 2 + block_size); ciphertext = ciphertext.subarray(0, plaintext.length + 2 + block_size);
return util.Uint8Array2str(ciphertext); return ciphertext;
}, },
/** /**
* Decrypts the prefixed data for the Modification Detection Code (MDC) computation * Decrypts the prefixed data for the Modification Detection Code (MDC) computation
* @param {String} cipherfn.encrypt Cipher function to use, * @param {String} cipherfn.encrypt Cipher function to use,
* @see module:crypto/cipher. * @see module:crypto/cipher.
* @param {String} key binary string representation of key to be used to check the mdc * @param {Uint8Array} key Uint8Array representation of key to be used to check the mdc
* This will be passed to the cipherfn * This will be passed to the cipherfn
* @param {String} ciphertext The encrypted data * @param {Uint8Array} ciphertext The encrypted data
* @return {String} plaintext Data of D(ciphertext) with blocksize length +2 * @return {Uint8Array} plaintext Data of D(ciphertext) with blocksize length +2
*/ */
mdc: function(cipherfn, key, ciphertext) { mdc: function(cipherfn, key, ciphertext) {
cipherfn = new cipher[cipherfn](key); cipherfn = new cipher[cipherfn](key);
@ -146,29 +151,31 @@ module.exports = {
iblock = cipherfn.encrypt(iblock); iblock = cipherfn.encrypt(iblock);
for (i = 0; i < block_size; i++) { for (i = 0; i < block_size; i++) {
ablock[i] = ciphertext.charCodeAt(i); ablock[i] = ciphertext[i];
iblock[i] ^= ablock[i]; iblock[i] ^= ablock[i];
} }
ablock = cipherfn.encrypt(ablock); ablock = cipherfn.encrypt(ablock);
return util.bin2str(iblock) + var result = new Uint8Array(iblock.length + 2);
String.fromCharCode(ablock[0] ^ ciphertext.charCodeAt(block_size)) + result.set(iblock);
String.fromCharCode(ablock[1] ^ ciphertext.charCodeAt(block_size + 1)); result[iblock.length] = ablock[0] ^ ciphertext[block_size];
result[iblock.length + 1] = ablock[1] ^ ciphertext[block_size + 1];
return result;
}, },
/** /**
* This function decrypts a given plaintext using the specified * This function decrypts a given plaintext using the specified
* blockcipher to decrypt a message * blockcipher to decrypt a message
* @param {String} cipherfn the algorithm cipher class to decrypt * @param {String} cipherfn the algorithm cipher class to decrypt
* data in one block_size encryption, {@link module:crypto/cipher}. * data in one block_size encryption, {@link module:crypto/cipher}.
* @param {String} key binary string representation of key to be used to decrypt the ciphertext. * @param {Uint8Array} key Uint8Array representation of key to be used to decrypt the ciphertext.
* This will be passed to the cipherfn * This will be passed to the cipherfn
* @param {String} ciphertext to be decrypted provided as a string * @param {Uint8Array} ciphertext to be decrypted
* @param {Boolean} resync a boolean value specifying if a resync of the * @param {Boolean} resync a boolean value specifying if a resync of the
* IV should be used or not. The encrypteddatapacket uses the * IV should be used or not. The encrypteddatapacket uses the
* "old" style with a resync. Decryption within an * "old" style with a resync. Decryption within an
* encryptedintegrityprotecteddata packet is not resyncing the IV. * encryptedintegrityprotecteddata packet is not resyncing the IV.
* @return {String} a string with the plaintext data * @return {Uint8Array} the plaintext data
*/ */
decrypt: function(cipherfn, key, ciphertext, resync) { decrypt: function(cipherfn, key, ciphertext, resync) {
@ -177,8 +184,9 @@ module.exports = {
var iblock = new Uint8Array(block_size); var iblock = new Uint8Array(block_size);
var ablock = new Uint8Array(block_size); var ablock = new Uint8Array(block_size);
var i, n = '';
var text = []; var i, j, n;
var text = new Uint8Array(ciphertext.length - block_size);
// initialisation vector // initialisation vector
for (i = 0; i < block_size; i++) { for (i = 0; i < block_size; i++) {
@ -187,15 +195,15 @@ module.exports = {
iblock = cipherfn.encrypt(iblock); iblock = cipherfn.encrypt(iblock);
for (i = 0; i < block_size; i++) { for (i = 0; i < block_size; i++) {
ablock[i] = ciphertext.charCodeAt(i); ablock[i] = ciphertext[i];
iblock[i] ^= ablock[i]; iblock[i] ^= ablock[i];
} }
ablock = cipherfn.encrypt(ablock); ablock = cipherfn.encrypt(ablock);
// test check octets // test check octets
if (iblock[block_size - 2] != (ablock[0] ^ ciphertext.charCodeAt(block_size)) || if (iblock[block_size - 2] != (ablock[0] ^ ciphertext[block_size]) ||
iblock[block_size - 1] != (ablock[1] ^ ciphertext.charCodeAt(block_size + 1))) { iblock[block_size - 1] != (ablock[1] ^ ciphertext[block_size + 1])) {
throw new Error('CFB decrypt: invalid key'); throw new Error('CFB decrypt: invalid key');
} }
@ -206,35 +214,42 @@ module.exports = {
*/ */
j = 0;
if (resync) { if (resync) {
for (i = 0; i < block_size; i++) { for (i = 0; i < block_size; i++) {
iblock[i] = ciphertext.charCodeAt(i + 2); iblock[i] = ciphertext[i + 2];
} }
for (n = block_size + 2; n < ciphertext.length; n += block_size) { for (n = block_size + 2; n < ciphertext.length; n += block_size) {
ablock = cipherfn.encrypt(iblock); ablock = cipherfn.encrypt(iblock);
for (i = 0; i < block_size && i + n < ciphertext.length; i++) { for (i = 0; i < block_size && i + n < ciphertext.length; i++) {
iblock[i] = ciphertext.charCodeAt(n + i); iblock[i] = ciphertext[n + i];
text.push(String.fromCharCode(ablock[i] ^ iblock[i])); if(j < text.length) {
text[j] = ablock[i] ^ iblock[i];
j++;
}
} }
} }
} else { } else {
for (i = 0; i < block_size; i++) { for (i = 0; i < block_size; i++) {
iblock[i] = ciphertext.charCodeAt(i); iblock[i] = ciphertext[i];
} }
for (n = block_size; n < ciphertext.length; n += block_size) { for (n = block_size; n < ciphertext.length; n += block_size) {
ablock = cipherfn.encrypt(iblock); ablock = cipherfn.encrypt(iblock);
for (i = 0; i < block_size && i + n < ciphertext.length; i++) { for (i = 0; i < block_size && i + n < ciphertext.length; i++) {
iblock[i] = ciphertext.charCodeAt(n + i); iblock[i] = ciphertext[n + i];
text.push(String.fromCharCode(ablock[i] ^ iblock[i])); if(j < text.length) {
text[j] = ablock[i] ^ iblock[i];
j++;
}
} }
} }
} }
if (!resync)
{ n = resync ? 0 : 2;
text.splice(0, 2);
} text = text.subarray(n, ciphertext.length - block_size - 2 + n);
text.splice(ciphertext.length - block_size - 2);
return text; return text;
}, },
@ -242,26 +257,29 @@ module.exports = {
cipherfn = new cipher[cipherfn](key); cipherfn = new cipher[cipherfn](key);
var block_size = cipherfn.blockSize; var block_size = cipherfn.blockSize;
var blocki = ''; var blocki = new Uint8Array(block_size);
var blockc = ''; var blockc = new Uint8Array(block_size);
var pos = 0; var pos = 0;
var cyphertext = ''; var cyphertext = new Uint8Array(plaintext.length);
var tempBlock = ''; var j = 0;
if (iv === null)
if (iv === null) {
for (i = 0; i < block_size; i++) { for (i = 0; i < block_size; i++) {
blockc += String.fromCharCode(0); blockc[i] = 0;
} }
else }
blockc = iv.substring(0, block_size); else {
for (i = 0; i < block_size; i++) {
blockc[i] = iv[i];
}
}
while (plaintext.length > block_size * pos) { while (plaintext.length > block_size * pos) {
var encblock = cipherfn.encrypt(util.str2bin(blockc)); var encblock = cipherfn.encrypt(blockc);
blocki = plaintext.substring((pos * block_size), (pos * block_size) + block_size); blocki = plaintext.subarray((pos * block_size), (pos * block_size) + block_size);
for (var i = 0; i < blocki.length; i++) { for (var i = 0; i < blocki.length; i++) {
tempBlock += String.fromCharCode(blocki.charCodeAt(i) ^ encblock[i]); blockc[i] = blocki[i] ^ encblock[i];
cyphertext[j++] = blockc[i];
} }
blockc = tempBlock;
tempBlock = '';
cyphertext += blockc;
pos++; pos++;
} }
return cyphertext; return cyphertext;
@ -271,22 +289,26 @@ module.exports = {
cipherfn = new cipher[cipherfn](key); cipherfn = new cipher[cipherfn](key);
var block_size = cipherfn.blockSize; var block_size = cipherfn.blockSize;
var blockp = ''; var blockp;
var pos = 0; var pos = 0;
var plaintext = ''; var plaintext = new Uint8Array(ciphertext.length);
var offset = 0; var offset = 0;
var i; var j = 0;
if (iv === null)
if (iv === null) {
blockp = new Uint8Array(block_size);
for (i = 0; i < block_size; i++) { for (i = 0; i < block_size; i++) {
blockp += String.fromCharCode(0); blockp[i] = 0;
} }
else }
blockp = iv.substring(0, block_size); else {
blockp = iv.subarray(0, block_size);
}
while (ciphertext.length > (block_size * pos)) { while (ciphertext.length > (block_size * pos)) {
var decblock = cipherfn.encrypt(util.str2bin(blockp)); var decblock = cipherfn.encrypt(blockp);
blockp = ciphertext.substring((pos * (block_size)) + offset, (pos * (block_size)) + (block_size) + offset); blockp = ciphertext.subarray((pos * (block_size)) + offset, (pos * (block_size)) + (block_size) + offset);
for (i = 0; i < blockp.length; i++) { for (var i = 0; i < blockp.length; i++) {
plaintext += String.fromCharCode(blockp.charCodeAt(i) ^ decblock[i]); plaintext[j++] = blockp[i] ^ decblock[i];
} }
pos++; pos++;
} }

View File

@ -12,14 +12,11 @@
*/ */
/** /**
* @requires util
* @module crypto/cipher/aes * @module crypto/cipher/aes
*/ */
'use strict'; 'use strict';
var util = require('../../util.js');
// The round constants used in subkey expansion // The round constants used in subkey expansion
var Rcon = new Uint8Array([ var Rcon = new Uint8Array([
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
@ -398,7 +395,7 @@ function keyExpansion(key) {
} }
for (i = 0, j = 0; j < keylen; j++, i += 4) { for (i = 0, j = 0; j < keylen; j++, i += 4) {
k[j] = key.charCodeAt(i) | (key.charCodeAt(i + 1) << 8) | (key.charCodeAt(i + 2) << 16) | (key.charCodeAt(i + 3) << 24); k[j] = key[i] | (key[i + 1] << 8) | (key[i + 2] << 16) | (key[i + 3] << 24);
} }
for (j = kc - 1; j >= 0; j--) { for (j = kc - 1; j >= 0; j--) {

View File

@ -391,19 +391,17 @@ Blowfish.prototype.init = function(key) {
} }
}; };
var util = require('../../util.js');
// added by Recurity Labs // added by Recurity Labs
function BFencrypt(block, key) { function BFencrypt(block, key) {
var bf = new Blowfish(); var bf = new Blowfish();
bf.init(util.str2bin(key)); bf.init(key);
return bf.encrypt_block(block); return bf.encrypt_block(block);
} }
function BF(key) { function BF(key) {
this.bf = new Blowfish(); this.bf = new Blowfish();
this.bf.init(util.str2bin(key)); this.bf.init(key);
this.encrypt = function(block) { this.encrypt = function(block) {
return this.bf.encrypt_block(block); return this.bf.encrypt_block(block);

View File

@ -591,11 +591,10 @@ function openpgp_symenc_cast5() {
0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e); 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e);
} }
var util = require('../../util.js');
function cast5(key) { function cast5(key) {
this.cast5 = new openpgp_symenc_cast5(); this.cast5 = new openpgp_symenc_cast5();
this.cast5.setKey(util.str2bin(key)); this.cast5.setKey(key);
this.encrypt = function(block) { this.encrypt = function(block) {
return this.cast5.encrypt(block); return this.cast5.encrypt(block);

View File

@ -85,7 +85,7 @@ function des(keys, message, encrypt, mode, iv, padding) {
var cbcleft, cbcleft2, cbcright, cbcright2; var cbcleft, cbcleft2, cbcright, cbcright2;
var endloop, loopinc; var endloop, loopinc;
var len = message.length; var len = message.length;
var chunk = 0;
//set up the loops for single and triple des //set up the loops for single and triple des
var iterations = keys.length == 32 ? 3 : 9; //single or triple des var iterations = keys.length == 32 ? 3 : 9; //single or triple des
if (iterations == 3) { if (iterations == 3) {
@ -102,21 +102,19 @@ function des(keys, message, encrypt, mode, iv, padding) {
} }
//store the result here //store the result here
var result = ""; var result = new Uint8Array(len);
var tempresult = ""; var k = 0;
if (mode == 1) { //CBC mode if (mode == 1) { //CBC mode
cbcleft = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++); cbcleft = (iv[m++] << 24) | (iv[m++] << 16) | (iv[m++] << 8) | iv[m++];
cbcright = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++); cbcright = (iv[m++] << 24) | (iv[m++] << 16) | (iv[m++] << 8) | iv[m++];
m = 0; m = 0;
} }
//loop through each 64 bit chunk of the message //loop through each 64 bit chunk of the message
while (m < len) { while (m < len) {
left = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) | message left = (message[m++] << 24) | (message[m++] << 16) | (message[m++] << 8) | message[m++];
.charCodeAt(m++); right = (message[m++] << 24) | (message[m++] << 16) | (message[m++] << 8) | message[m++];
right = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) |
message.charCodeAt(m++);
//for Cipher Block Chaining mode, xor the message with the previous result //for Cipher Block Chaining mode, xor the message with the previous result
if (mode == 1) { if (mode == 1) {
@ -202,20 +200,17 @@ function des(keys, message, encrypt, mode, iv, padding) {
right ^= cbcright2; right ^= cbcright2;
} }
} }
tempresult += String.fromCharCode((left >>> 24), ((left >>> 16) & 0xff), ((left >>> 8) & 0xff), (left & 0xff), (
right >>> 24), ((right >>> 16) & 0xff), ((right >>> 8) & 0xff), (right & 0xff));
chunk += 8; result[k++] = (left >>> 24);
if (chunk == 512) { result[k++] = ((left >>> 16) & 0xff);
result += tempresult; result[k++] = ((left >>> 8) & 0xff);
tempresult = ""; result[k++] = (left & 0xff);
chunk = 0; result[k++] = (right >>> 24);
} result[k++] = ((right >>> 16) & 0xff);
result[k++] = ((right >>> 8) & 0xff);
result[k++] = (right & 0xff);
} //for every 8 characters, or 64 bits in the message } //for every 8 characters, or 64 bits in the message
//return the result as an array
result += tempresult;
//only remove padding if decrypting - note that you need to use the same padding option for both encrypt and decrypt //only remove padding if decrypting - note that you need to use the same padding option for both encrypt and decrypt
if (!encrypt) { if (!encrypt) {
result = des_removePadding(result, padding); result = des_removePadding(result, padding);
@ -272,8 +267,8 @@ function des_createKeys(key) {
temp; temp;
for (var j = 0; j < iterations; j++) { //either 1 or 3 iterations for (var j = 0; j < iterations; j++) { //either 1 or 3 iterations
var left = (key.charCodeAt(m++) << 24) | (key.charCodeAt(m++) << 16) | (key.charCodeAt(m++) << 8) | key.charCodeAt(m++); var left = (key[m++] << 24) | (key[m++] << 16) | (key[m++] << 8) | key[m++];
var right = (key.charCodeAt(m++) << 24) | (key.charCodeAt(m++) << 16) | (key.charCodeAt(m++) << 8) | key.charCodeAt(m++); var right = (key[m++] << 24) | (key[m++] << 16) | (key[m++] << 8) | key[m++];
temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; temp = ((left >>> 4) ^ right) & 0x0f0f0f0f;
right ^= temp; right ^= temp;
@ -338,27 +333,55 @@ function des_createKeys(key) {
function des_addPadding(message, padding) { function des_addPadding(message, padding) {
var padLength = 8 - (message.length % 8); var padLength = 8 - (message.length % 8);
if ((padding == 2) && (padLength < 8)) { //pad the message with spaces
message += " ".substr(0, padLength); var pad;
if (padding == 2 && (padLength < 8)) { //pad the message with spaces
pad = " ".charCodeAt(0);
} else if (padding == 1) { //PKCS7 padding } else if (padding == 1) { //PKCS7 padding
message += String.fromCharCode(padLength, padLength, padLength, padLength, padLength, padLength, padLength, pad = padLength;
padLength).substr(0, padLength);
} else if (!padding && (padLength < 8)) { //pad the message out with null bytes } else if (!padding && (padLength < 8)) { //pad the message out with null bytes
message += "\0\0\0\0\0\0\0\0".substr(0, padLength); pad = 0;
} else if (padLength == 8) {
return message;
} }
return message; else {
throw new Error('des: invalid padding');
}
var paddedMessage = new Uint8Array(message.length + padLength);
for(var i = 0; i < message.length; i++) {
paddedMessage[i] = message[i];
}
for(var j = 0; j < padLength; j++) {
paddedMessage[message.length + j] = pad;
}
return paddedMessage;
} }
function des_removePadding(message, padding) { function des_removePadding(message, padding) {
var padLength = null;
var pad;
if (padding == 2) { // space padded if (padding == 2) { // space padded
message = message.replace(/ *$/g, ""); pad = " ".charCodeAt(0);
} else if (padding == 1) { // PKCS7 } else if (padding == 1) { // PKCS7
var padCount = message.charCodeAt(message.length - 1); padLength = message[message.length - 1];
message = message.substr(0, message.length - padCount);
} else if (!padding) { // null padding } else if (!padding) { // null padding
message = message.replace(/\0*$/g, ""); pad = 0;
} }
return message; else {
throw new Error('des: invalid padding');
}
if(!padLength) {
padLength = 1;
while(message[message.length - padLength] === pad) {
padLength++;
}
padLength--;
}
return message.subarray(0, message.length - padLength);
} }
@ -370,15 +393,15 @@ function Des(key) {
this.key = []; this.key = [];
for (var i = 0; i < 3; i++) { for (var i = 0; i < 3; i++) {
this.key.push(key.substr(i * 8, 8)); this.key.push(new Uint8Array(key.subarray(i * 8, (i * 8) + 8)));
} }
this.encrypt = function(block) { this.encrypt = function(block) {
return util.str2bin(des(des_createKeys(this.key[2]), return des(des_createKeys(this.key[2]),
des(des_createKeys(this.key[1]), des(des_createKeys(this.key[1]),
des(des_createKeys(this.key[0]), des(des_createKeys(this.key[0]),
util.bin2str(block), true, 0, null, null), block, true, 0, null, null),
false, 0, null, null), true, 0, null, null)); false, 0, null, null), true, 0, null, null);
}; };
} }
@ -393,12 +416,12 @@ function OriginalDes(key) {
this.encrypt = function(block, padding) { this.encrypt = function(block, padding) {
var keys = des_createKeys(this.key); var keys = des_createKeys(this.key);
return util.str2bin(des(keys, util.bin2str(block), true, 0, null, padding)); return des(keys, block, true, 0, null, padding);
}; };
this.decrypt = function(block, padding) { this.decrypt = function(block, padding) {
var keys = des_createKeys(this.key); var keys = des_createKeys(this.key);
return util.str2bin(des(keys, util.bin2str(block), false, 0, null, padding)); return des(keys, block, false, 0, null, padding);
}; };
} }

View File

@ -332,14 +332,12 @@ function createTwofish() {
}; };
} }
var util = require('../../util.js');
// added by Recurity Labs // added by Recurity Labs
function TFencrypt(block, key) { function TFencrypt(block, key) {
var block_copy = toArray(block); var block_copy = toArray(block);
var tf = createTwofish(); var tf = createTwofish();
tf.open(util.str2bin(key), 0); tf.open(toArray(key), 0);
var result = tf.encrypt(block_copy, 0); var result = tf.encrypt(block_copy, 0);
tf.close(); tf.close();
return result; return result;
@ -347,7 +345,7 @@ function TFencrypt(block, key) {
function TF(key) { function TF(key) {
this.tf = createTwofish(); this.tf = createTwofish();
this.tf.open(util.str2bin(key), 0); this.tf.open(toArray(key), 0);
this.encrypt = function(block) { this.encrypt = function(block) {
return this.tf.encrypt(toArray(block), 0); return this.tf.encrypt(toArray(block), 0);

View File

@ -212,7 +212,7 @@ module.exports = {
/** /**
* generate random byte prefix as string for the specified algorithm * generate random byte prefix as string for the specified algorithm
* @param {module:enums.symmetric} algo Algorithm to use (see {@link http://tools.ietf.org/html/rfc4880#section-9.2|RFC 4880 9.2}) * @param {module:enums.symmetric} algo Algorithm to use (see {@link http://tools.ietf.org/html/rfc4880#section-9.2|RFC 4880 9.2})
* @return {String} Random bytes with length equal to the block * @return {Uint8Array} Random bytes with length equal to the block
* size of the cipher * size of the cipher
*/ */
getPrefixRandom: function(algo) { getPrefixRandom: function(algo) {
@ -222,7 +222,7 @@ module.exports = {
/** /**
* Generating a session key for the specified symmetric algorithm * Generating a session key for the specified symmetric algorithm
* @param {module:enums.symmetric} algo Algorithm to use (see {@link http://tools.ietf.org/html/rfc4880#section-9.2|RFC 4880 9.2}) * @param {module:enums.symmetric} algo Algorithm to use (see {@link http://tools.ietf.org/html/rfc4880#section-9.2|RFC 4880 9.2})
* @return {String} Random bytes as a string to be used as a key * @return {Uint8Array} Random bytes as a string to be used as a key
*/ */
generateSessionKey: function(algo) { generateSessionKey: function(algo) {
return random.getRandomBytes(cipher[algo].keySize); return random.getRandomBytes(cipher[algo].keySize);

View File

@ -19,10 +19,12 @@
/** /**
* @requires type/mpi * @requires type/mpi
* @requires util
* @module crypto/random * @module crypto/random
*/ */
var type_mpi = require('../type/mpi.js'); var type_mpi = require('../type/mpi.js'),
util = require('../util.js');
var nodeCrypto = null; var nodeCrypto = null;
if (typeof window === 'undefined') { if (typeof window === 'undefined') {
@ -31,14 +33,14 @@ if (typeof window === 'undefined') {
module.exports = { module.exports = {
/** /**
* Retrieve secure random byte string of the specified length * Retrieve secure random byte array of the specified length
* @param {Integer} length Length in bytes to generate * @param {Integer} length Length in bytes to generate
* @return {String} Random byte string * @return {Uint8Array} Random byte array
*/ */
getRandomBytes: function(length) { getRandomBytes: function(length) {
var result = ''; var result = new Uint8Array(length);
for (var i = 0; i < length; i++) { for (var i = 0; i < length; i++) {
result += String.fromCharCode(this.getSecureRandomOctet()); result[i] = this.getSecureRandomOctet();
} }
return result; return result;
}, },
@ -104,7 +106,7 @@ module.exports = {
} }
var numBytes = Math.floor((bits + 7) / 8); var numBytes = Math.floor((bits + 7) / 8);
var randomBits = this.getRandomBytes(numBytes); var randomBits = util.Uint8Array2str(this.getRandomBytes(numBytes));
if (bits % 8 > 0) { if (bits % 8 > 0) {
randomBits = String.fromCharCode( randomBits = String.fromCharCode(

View File

@ -1,10 +1,12 @@
/** /**
* @requires util
* @requires crypto/hash * @requires crypto/hash
* @requires crypto/pkcs1 * @requires crypto/pkcs1
* @requires crypto/public_key * @requires crypto/public_key
* @module crypto/signature */ * @module crypto/signature */
var publicKey = require('./public_key'), var util = require('../util'),
publicKey = require('./public_key'),
pkcs1 = require('./pkcs1.js'), pkcs1 = require('./pkcs1.js'),
hashModule = require('./hash'); hashModule = require('./hash');
@ -15,11 +17,13 @@ module.exports = {
* @param {module:enums.hash} hash_algo Hash algorithm * @param {module:enums.hash} hash_algo Hash algorithm
* @param {Array<module:type/mpi>} msg_MPIs Signature multiprecision integers * @param {Array<module:type/mpi>} msg_MPIs Signature multiprecision integers
* @param {Array<module:type/mpi>} publickey_MPIs Public key multiprecision integers * @param {Array<module:type/mpi>} publickey_MPIs Public key multiprecision integers
* @param {String} data Data on where the signature was computed on. * @param {Uint8Array} data Data on where the signature was computed on.
* @return {Boolean} true if signature (sig_data was equal to data over hash) * @return {Boolean} true if signature (sig_data was equal to data over hash)
*/ */
verify: function(algo, hash_algo, msg_MPIs, publickey_MPIs, data) { verify: function(algo, hash_algo, msg_MPIs, publickey_MPIs, data) {
data = util.Uint8Array2str(data);
switch (algo) { switch (algo) {
case 1: case 1:
// RSA (Encrypt or Sign) [HAC] // RSA (Encrypt or Sign) [HAC]
@ -63,11 +67,13 @@ module.exports = {
* of the private key * of the private key
* @param {Array<module:type/mpi>} secretMPIs Private key multiprecision * @param {Array<module:type/mpi>} secretMPIs Private key multiprecision
* integers which is used to sign the data * integers which is used to sign the data
* @param {String} data Data to be signed * @param {Uint8Array} data Data to be signed
* @return {Array<module:type/mpi>} * @return {Array<module:type/mpi>}
*/ */
sign: function(hash_algo, algo, keyIntegers, data) { sign: function(hash_algo, algo, keyIntegers, data) {
data = util.Uint8Array2str(data);
var m; var m;
switch (algo) { switch (algo) {
@ -82,7 +88,6 @@ module.exports = {
var n = keyIntegers[0].toBigInteger(); var n = keyIntegers[0].toBigInteger();
m = pkcs1.emsa.encode(hash_algo, m = pkcs1.emsa.encode(hash_algo,
data, keyIntegers[0].byteLength()); data, keyIntegers[0].byteLength());
return rsa.sign(m, d, n).toMPI(); return rsa.sign(m, d, n).toMPI();
case 17: case 17:

View File

@ -115,10 +115,8 @@ function addheader() {
*/ */
function getCheckSum(data) { function getCheckSum(data) {
var c = createcrc24(data); var c = createcrc24(data);
var str = "" + String.fromCharCode(c >> 16) + var bytes = new Uint8Array([c >> 16, (c >> 8) & 0xFF, c & 0xFF]);
String.fromCharCode((c >> 8) & 0xFF) + return base64.encode(bytes);
String.fromCharCode(c & 0xFF);
return base64.encode(str);
} }
/** /**
@ -178,27 +176,27 @@ function createcrc24(input) {
var index = 0; var index = 0;
while ((input.length - index) > 16) { while ((input.length - index) > 16) {
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index)) & 0xff]; crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input[index]) & 0xff];
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 1)) & 0xff]; crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input[index + 1]) & 0xff];
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 2)) & 0xff]; crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input[index + 2]) & 0xff];
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 3)) & 0xff]; crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input[index + 3]) & 0xff];
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 4)) & 0xff]; crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input[index + 4]) & 0xff];
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 5)) & 0xff]; crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input[index + 5]) & 0xff];
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 6)) & 0xff]; crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input[index + 6]) & 0xff];
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 7)) & 0xff]; crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input[index + 7]) & 0xff];
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 8)) & 0xff]; crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input[index + 8]) & 0xff];
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 9)) & 0xff]; crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input[index + 9]) & 0xff];
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 10)) & 0xff]; crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input[index + 10]) & 0xff];
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 11)) & 0xff]; crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input[index + 11]) & 0xff];
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 12)) & 0xff]; crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input[index + 12]) & 0xff];
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 13)) & 0xff]; crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input[index + 13]) & 0xff];
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 14)) & 0xff]; crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input[index + 14]) & 0xff];
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 15)) & 0xff]; crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input[index + 15]) & 0xff];
index += 16; index += 16;
} }
for (var j = index; j < input.length; j++) { for (var j = index; j < input.length; j++) {
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index++)) & 0xff]; crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input[index++]) & 0xff];
} }
return crc & 0xffffff; return crc & 0xffffff;
} }

View File

@ -18,8 +18,8 @@
var b64s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; var b64s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
/** /**
* Convert binary string to radix-64 * Convert binary array to radix-64
* @param {String} t binary string to convert * @param {Uint8Array} t Uint8Array to convert
* @returns {string} radix-64 version of input string * @returns {string} radix-64 version of input string
* @static * @static
*/ */
@ -32,7 +32,7 @@ function s2r(t, o) {
var tl = t.length; var tl = t.length;
for (n = 0; n < tl; n++) { for (n = 0; n < tl; n++) {
c = t.charCodeAt(n); c = t[n];
if (s === 0) { if (s === 0) {
r.push(b64s.charAt((c >> 2) & 63)); r.push(b64s.charAt((c >> 2) & 63));
a = (c & 3) << 4; a = (c & 3) << 4;
@ -75,29 +75,30 @@ function s2r(t, o) {
} }
/** /**
* Convert radix-64 to binary string * Convert radix-64 to binary array
* @param {String} t radix-64 string to convert * @param {String} t radix-64 string to convert
* @returns {string} binary version of input string * @returns {Uint8Array} binary array version of input string
* @static * @static
*/ */
function r2s(t) { function r2s(t) {
// TODO check atob alternative // TODO check atob alternative
var c, n; var c, n;
var r = [], var r = [],
s = 0,
a = 0; var s = 0,
var a = 0;
var tl = t.length; var tl = t.length;
for (n = 0; n < tl; n++) { for (n = 0; n < tl; n++) {
c = b64s.indexOf(t.charAt(n)); c = b64s.indexOf(t.charAt(n));
if (c >= 0) { if (c >= 0) {
if (s) if (s)
r.push(String.fromCharCode(a | (c >> (6 - s)) & 255)); r.push(a | (c >> (6 - s)) & 255);
s = (s + 2) & 7; s = (s + 2) & 7;
a = (c << s) & 255; a = (c << s) & 255;
} }
} }
return r.join(''); return new Uint8Array(r);
} }
module.exports = { module.exports = {

View File

@ -217,7 +217,7 @@ Key.prototype.getUserIds = function() {
var userids = []; var userids = [];
for (var i = 0; i < this.users.length; i++) { for (var i = 0; i < this.users.length; i++) {
if (this.users[i].userId) { if (this.users[i].userId) {
userids.push(this.users[i].userId.write()); userids.push(util.Uint8Array2str(this.users[i].userId.write()));
} }
} }
return userids; return userids;
@ -590,7 +590,7 @@ function mergeSignatures(source, dest, attr, checkFn) {
source.forEach(function(sourceSig) { source.forEach(function(sourceSig) {
if (!sourceSig.isExpired() && (!checkFn || checkFn(sourceSig)) && if (!sourceSig.isExpired() && (!checkFn || checkFn(sourceSig)) &&
!dest[attr].some(function(destSig) { !dest[attr].some(function(destSig) {
return destSig.signature === sourceSig.signature; return util.equalsUint8Array(destSig.signature,sourceSig.signature);
})) { })) {
dest[attr].push(sourceSig); dest[attr].push(sourceSig);
} }
@ -960,7 +960,7 @@ function generate(options) {
options.userId.forEach(function(userId, index) { options.userId.forEach(function(userId, index) {
userIdPacket = new packet.Userid(); userIdPacket = new packet.Userid();
userIdPacket.read(userId); userIdPacket.read(util.str2Uint8Array(userId));
dataToSign = {}; dataToSign = {};
dataToSign.userid = userIdPacket; dataToSign.userid = userIdPacket;

View File

@ -26,7 +26,8 @@
'use strict'; 'use strict';
var packet = require('./packet'), var util = require('./util.js'),
packet = require('./packet'),
enums = require('./enums.js'), enums = require('./enums.js'),
armor = require('./encoding/armor.js'), armor = require('./encoding/armor.js'),
config = require('./config'), config = require('./config'),
@ -463,11 +464,11 @@ function read(input) {
/** /**
* Create a message object from signed content and a detached armored signature. * Create a message object from signed content and a detached armored signature.
* @param {String} content An 8 bit ascii string containing e.g. a MIME subtree with text nodes or attachments * @param {String} content An 8 bit ascii string containing e.g. a MIME subtree with text nodes or attachments
* @param {String} detachedSignature The detached ascii armored PGP signarure * @param {String} detachedSignature The detached ascii armored PGP signature
*/ */
function readSignedContent(content, detachedSignature) { function readSignedContent(content, detachedSignature) {
var literalDataPacket = new packet.Literal(); var literalDataPacket = new packet.Literal();
literalDataPacket.setBytes(content, enums.read(enums.literal, enums.literal.binary)); literalDataPacket.setBytes(util.str2Uint8Array(content), enums.read(enums.literal, enums.literal.binary));
var packetlist = new packet.List(); var packetlist = new packet.List();
packetlist.push(literalDataPacket); packetlist.push(literalDataPacket);
var input = armor.decode(detachedSignature).data; var input = armor.decode(detachedSignature).data;
@ -496,12 +497,16 @@ function fromText(text, filename) {
/** /**
* creates new message object from binary data * creates new message object from binary data
* @param {String} bytes * @param {Uint8Array} bytes
* @param {String} filename (optional) * @param {String} filename (optional)
* @return {module:message~Message} new message object * @return {module:message~Message} new message object
* @static * @static
*/ */
function fromBinary(bytes, filename) { function fromBinary(bytes, filename) {
if(!Uint8Array.prototype.isPrototypeOf(bytes)) {
throw new Error('Data must be in the form of a Uint8Array');
}
var literalDataPacket = new packet.Literal(); var literalDataPacket = new packet.Literal();
if (filename) { if (filename) {
literalDataPacket.setFilename(filename); literalDataPacket.setFilename(filename);

View File

@ -90,13 +90,12 @@ function encryptMessage(keys, data, passwords, params) {
var filename, binary, packets; var filename, binary, packets;
if(params) { if(params) {
filename = params.filename; filename = params.filename;
binary = params.binary;
packets = params.packets; packets = params.packets;
} }
return execute(function() { return execute(function() {
var msg, armored; var msg, armored;
if(binary) { if(data instanceof Uint8Array) {
msg = message.fromBinary(data, filename); msg = message.fromBinary(data, filename);
} }
else { else {

View File

@ -70,10 +70,10 @@ function Compressed() {
*/ */
Compressed.prototype.read = function (bytes) { Compressed.prototype.read = function (bytes) {
// One octet that gives the algorithm used to compress the packet. // One octet that gives the algorithm used to compress the packet.
this.algorithm = enums.read(enums.compression, bytes.charCodeAt(0)); this.algorithm = enums.read(enums.compression, bytes[0]);
// Compressed data, which makes up the remainder of the packet. // Compressed data, which makes up the remainder of the packet.
this.compressed = bytes.substr(1); this.compressed = bytes.subarray(1, bytes.length);
this.decompress(); this.decompress();
}; };
@ -88,7 +88,7 @@ Compressed.prototype.write = function () {
if (this.compressed === null) if (this.compressed === null)
this.compress(); this.compress();
return String.fromCharCode(enums.write(enums.compression, this.algorithm)) + this.compressed; return util.concatUint8Array(new Uint8Array([enums.write(enums.compression, this.algorithm)]), this.compressed);
}; };
@ -105,13 +105,13 @@ Compressed.prototype.decompress = function () {
break; break;
case 'zip': case 'zip':
var inflate = new RawInflate.Zlib.RawInflate(util.str2Uint8Array(this.compressed)); var inflate = new RawInflate.Zlib.RawInflate(this.compressed);
decompressed = util.Uint8Array2str(inflate.decompress()); decompressed = inflate.decompress();
break; break;
case 'zlib': case 'zlib':
var inflate = new Zlib.Zlib.Inflate(util.str2Uint8Array(this.compressed)); var inflate = new Zlib.Zlib.Inflate(this.compressed);
decompressed = util.Uint8Array2str(inflate.decompress()); decompressed = inflate.decompress();
break; break;
case 'bzip2': case 'bzip2':
@ -141,14 +141,14 @@ Compressed.prototype.compress = function () {
case 'zip': case 'zip':
// - ZIP [RFC1951] // - ZIP [RFC1951]
deflate = new RawDeflate.Zlib.RawDeflate(util.str2Uint8Array(uncompressed)); deflate = new RawDeflate.Zlib.RawDeflate(uncompressed);
this.compressed = util.Uint8Array2str(deflate.compress()); this.compressed = deflate.compress();
break; break;
case 'zlib': case 'zlib':
// - ZLIB [RFC1950] // - ZLIB [RFC1950]
deflate = new Zlib.Zlib.Deflate(util.str2Uint8Array(uncompressed)); deflate = new Zlib.Zlib.Deflate(uncompressed);
this.compressed = util.Uint8Array2str(deflate.compress()); this.compressed = deflate.compress();
break; break;
case 'bzip2': case 'bzip2':

View File

@ -36,8 +36,8 @@ var util = require('../util.js'),
function Literal() { function Literal() {
this.tag = enums.packet.literal; this.tag = enums.packet.literal;
this.format = 'utf8'; // default format for literal data packets this.format = 'utf8'; // default format for literal data packets
this.data = ''; // literal data representation as native JavaScript string or bytes
this.date = new Date(); this.date = new Date();
this.data = new Uint8Array(0); // literal data representation
this.filename = 'msg.txt'; this.filename = 'msg.txt';
} }
@ -50,7 +50,7 @@ Literal.prototype.setText = function (text) {
// normalize EOL to \r\n // normalize EOL to \r\n
text = text.replace(/\r/g, '').replace(/\n/g, '\r\n'); text = text.replace(/\r/g, '').replace(/\n/g, '\r\n');
// encode UTF8 // encode UTF8
this.data = this.format == 'utf8' ? util.encode_utf8(text) : text; this.data = this.format == 'utf8' ? util.str2Uint8Array(util.encode_utf8(text)) : util.str2Uint8Array(text);
}; };
/** /**
@ -60,14 +60,14 @@ Literal.prototype.setText = function (text) {
*/ */
Literal.prototype.getText = function () { Literal.prototype.getText = function () {
// decode UTF8 // decode UTF8
var text = util.decode_utf8(this.data); var text = util.decode_utf8(util.Uint8Array2str(this.data));
// normalize EOL to \n // normalize EOL to \n
return text.replace(/\r\n/g, '\n'); return text.replace(/\r\n/g, '\n');
}; };
/** /**
* Set the packet data to value represented by the provided string of bytes. * Set the packet data to value represented by the provided string of bytes.
* @param {String} bytes The string of bytes * @param {Uint8Array} bytes The string of bytes
* @param {utf8|binary|text} format The format of the string of bytes * @param {utf8|binary|text} format The format of the string of bytes
*/ */
Literal.prototype.setBytes = function (bytes, format) { Literal.prototype.setBytes = function (bytes, format) {
@ -78,7 +78,7 @@ Literal.prototype.setBytes = function (bytes, format) {
/** /**
* Get the byte sequence representing the literal packet data * Get the byte sequence representing the literal packet data
* @returns {String} A sequence of bytes * @returns {Uint8Array} A sequence of bytes
*/ */
Literal.prototype.getBytes = function () { Literal.prototype.getBytes = function () {
return this.data; return this.data;
@ -106,25 +106,20 @@ Literal.prototype.getFilename = function() {
/** /**
* Parsing function for a literal data packet (tag 11). * Parsing function for a literal data packet (tag 11).
* *
* @param {String} input Payload of a tag 11 packet * @param {Uint8Array} 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 {module:packet/literal} object representation * @return {module:packet/literal} object representation
*/ */
Literal.prototype.read = function (bytes) { Literal.prototype.read = function (bytes) {
// - A one-octet field that describes how the data is formatted. // - A one-octet field that describes how the data is formatted.
var format = enums.read(enums.literal, bytes[0]);
var format = enums.read(enums.literal, bytes.charCodeAt(0)); var filename_len = bytes[1];
this.filename = util.decode_utf8(util.Uint8Array2str(bytes.subarray(2, 2 + filename_len)));
var filename_len = bytes.charCodeAt(1); this.date = util.readDate(bytes.subarray(2 + filename_len, 2 + filename_len + 4));
this.filename = util.decode_utf8(bytes.substr(2, filename_len));
this.date = util.readDate(bytes.substr(2 + filename_len, 4)); var data = bytes.subarray(6 + filename_len, bytes.length);
var data = bytes.substring(6 + filename_len);
this.setBytes(data, format); this.setBytes(data, format);
}; };
@ -132,19 +127,15 @@ Literal.prototype.read = function (bytes) {
/** /**
* Creates a string representation of the packet * Creates a string representation of the packet
* *
* @param {String} data The data to be inserted as body * @return {Uint8Array} Uint8Array representation of the packet
* @return {String} string-representation of the packet
*/ */
Literal.prototype.write = function () { Literal.prototype.write = function () {
var filename = util.encode_utf8(this.filename); var filename = util.str2Uint8Array(util.encode_utf8(this.filename));
var filename_length = new Uint8Array([filename.length]);
var format = new Uint8Array([enums.write(enums.literal, this.format)]);
var date = util.writeDate(this.date);
var data = this.getBytes(); var data = this.getBytes();
var result = ''; return util.concatUint8Array([format, filename_length, filename, date, data]);
result += String.fromCharCode(enums.write(enums.literal, this.format));
result += String.fromCharCode(filename.length);
result += filename;
result += util.writeDate(this.date);
result += data;
return result;
}; };

View File

@ -52,9 +52,9 @@ function Marker() {
* @return {module:packet/marker} Object representation * @return {module:packet/marker} Object representation
*/ */
Marker.prototype.read = function (bytes) { Marker.prototype.read = function (bytes) {
if (bytes.charCodeAt(0) == 0x50 && // P if (bytes[0] == 0x50 && // P
bytes.charCodeAt(1) == 0x47 && // G bytes[1] == 0x47 && // G
bytes.charCodeAt(2) == 0x50) // P bytes[2] == 0x50) // P
return true; return true;
// marker packet does not contain "PGP" // marker packet does not contain "PGP"
return false; return false;

View File

@ -23,6 +23,7 @@
* hashes needed to verify the signature. It allows the Signature * hashes needed to verify the signature. It allows the Signature
* packet to be placed at the end of the message, so that the signer * packet to be placed at the end of the message, so that the signer
* can compute the entire signed message in one pass. * can compute the entire signed message in one pass.
* @requires util
* @requires enums * @requires enums
* @requires type/keyid * @requires type/keyid
* @module packet/one_pass_signature * @module packet/one_pass_signature
@ -30,7 +31,8 @@
module.exports = OnePassSignature; module.exports = OnePassSignature;
var enums = require('../enums.js'), var util = require('../util.js'),
enums = require('../enums.js'),
type_keyid = require('../type/keyid.js'); type_keyid = require('../type/keyid.js');
/** /**
@ -48,52 +50,50 @@ function OnePassSignature() {
/** /**
* parsing function for a one-pass signature packet (tag 4). * parsing function for a one-pass signature packet (tag 4).
* @param {String} bytes payload of a tag 4 packet * @param {Uint8Array} bytes payload of a tag 4 packet
* @return {module:packet/one_pass_signature} object representation * @return {module:packet/one_pass_signature} object representation
*/ */
OnePassSignature.prototype.read = function (bytes) { OnePassSignature.prototype.read = function (bytes) {
var mypos = 0; var mypos = 0;
// A one-octet version number. The current version is 3. // A one-octet version number. The current version is 3.
this.version = bytes.charCodeAt(mypos++); this.version = bytes[mypos++];
// A one-octet signature type. Signature types are described in // A one-octet signature type. Signature types are described in
// Section 5.2.1. // Section 5.2.1.
this.type = enums.read(enums.signature, bytes.charCodeAt(mypos++)); this.type = enums.read(enums.signature, bytes[mypos++]);
// A one-octet number describing the hash algorithm used. // A one-octet number describing the hash algorithm used.
this.hashAlgorithm = enums.read(enums.hash, bytes.charCodeAt(mypos++)); this.hashAlgorithm = enums.read(enums.hash, bytes[mypos++]);
// A one-octet number describing the public-key algorithm used. // A one-octet number describing the public-key algorithm used.
this.publicKeyAlgorithm = enums.read(enums.publicKey, bytes.charCodeAt(mypos++)); this.publicKeyAlgorithm = enums.read(enums.publicKey, bytes[mypos++]);
// An eight-octet number holding the Key ID of the signing key. // An eight-octet number holding the Key ID of the signing key.
this.signingKeyId = new type_keyid(); this.signingKeyId = new type_keyid();
this.signingKeyId.read(bytes.substr(mypos)); this.signingKeyId.read(bytes.subarray(mypos, mypos + 8));
mypos += 8; mypos += 8;
// A one-octet number holding a flag showing whether the signature // A one-octet number holding a flag showing whether the signature
// is nested. A zero value indicates that the next packet is // is nested. A zero value indicates that the next packet is
// another One-Pass Signature packet that describes another // another One-Pass Signature packet that describes another
// signature to be applied to the same message data. // signature to be applied to the same message data.
this.flags = bytes.charCodeAt(mypos++); this.flags = bytes[mypos++];
return this; return this;
}; };
/** /**
* creates a string representation of a one-pass signature packet * creates a string representation of a one-pass signature packet
* @return {String} a string representation of a one-pass signature packet * @return {Uint8Array} a Uint8Array representation of a one-pass signature packet
*/ */
OnePassSignature.prototype.write = function () { OnePassSignature.prototype.write = function () {
var result = "";
result += String.fromCharCode(3); var start = new Uint8Array([3, enums.write(enums.signature, this.type),
result += String.fromCharCode(enums.write(enums.signature, this.type)); enums.write(enums.hash, this.hashAlgorithm),
result += String.fromCharCode(enums.write(enums.hash, this.hashAlgorithm)); enums.write(enums.publicKey, this.publicKeyAlgorithm)]);
result += String.fromCharCode(enums.write(enums.publicKey, this.publicKeyAlgorithm));
result += this.signingKeyId.write();
result += String.fromCharCode(this.flags);
return result; var end = new Uint8Array([this.flags]);
return util.concatUint8Array([start, this.signingKeyId.write(), end]);
}; };
/** /**

View File

@ -28,17 +28,17 @@ module.exports = {
readSimpleLength: function(bytes) { readSimpleLength: function(bytes) {
var len = 0, var len = 0,
offset, offset,
type = bytes.charCodeAt(0); type = bytes[0];
if (type < 192) { if (type < 192) {
len = bytes.charCodeAt(0); len = bytes[0];
offset = 1; offset = 1;
} else if (type < 255) { } else if (type < 255) {
len = ((bytes.charCodeAt(0) - 192) << 8) + (bytes.charCodeAt(1)) + 192; len = ((bytes[0] - 192) << 8) + (bytes[1]) + 192;
offset = 2; offset = 2;
} else if (type == 255) { } else if (type == 255) {
len = util.readNumber(bytes.substr(1, 4)); len = util.readNumber(bytes.subarray(1, 1 + 4));
offset = 5; offset = 5;
} }
@ -53,24 +53,21 @@ module.exports = {
* string * string
* *
* @param {Integer} length The length to encode * @param {Integer} length The length to encode
* @return {String} String with openpgp length representation * @return {Uint8Array} String with openpgp length representation
*/ */
writeSimpleLength: function(length) { writeSimpleLength: function(length) {
var result = "";
if (length < 192) { if (length < 192) {
result += String.fromCharCode(length); return new Uint8Array([length]);
} else if (length > 191 && length < 8384) { } else if (length > 191 && length < 8384) {
/* /*
* let a = (total data packet length) - 192 let bc = two octet * let a = (total data packet length) - 192 let bc = two octet
* representation of a let d = b + 192 * representation of a let d = b + 192
*/ */
result += String.fromCharCode(((length - 192) >> 8) + 192); return new Uint8Array([((length - 192) >> 8) + 192, (length - 192) & 0xFF]);
result += String.fromCharCode((length - 192) & 0xFF);
} else { } else {
result += String.fromCharCode(255); return util.concatUint8Array([new Uint8Array([255]), util.writeNumber(length, 4)]);
result += util.writeNumber(length, 4);
} }
return result;
}, },
/** /**
@ -83,10 +80,7 @@ module.exports = {
*/ */
writeHeader: function(tag_type, length) { writeHeader: function(tag_type, length) {
/* we're only generating v4 packet headers here */ /* we're only generating v4 packet headers here */
var result = ""; return util.concatUint8Array([new Uint8Array([0xC0 | tag_type]), this.writeSimpleLength(length)]);
result += String.fromCharCode(0xC0 | tag_type);
result += this.writeSimpleLength(length);
return result;
}, },
/** /**
@ -98,18 +92,14 @@ module.exports = {
* @return {String} String of the header * @return {String} String of the header
*/ */
writeOldHeader: function(tag_type, length) { writeOldHeader: function(tag_type, length) {
var result = "";
if (length < 256) { if (length < 256) {
result += String.fromCharCode(0x80 | (tag_type << 2)); return new Uint8Array([0x80 | (tag_type << 2), length]);
result += String.fromCharCode(length);
} else if (length < 65536) { } else if (length < 65536) {
result += String.fromCharCode(0x80 | (tag_type << 2) | 1); return util.concatUint8Array([0x80 | (tag_type << 2) | 1, util.writeNumber(length, 2)]);
result += util.writeNumber(length, 2);
} else { } else {
result += String.fromCharCode(0x80 | (tag_type << 2) | 2); return util.concatUint8Array([0x80 | (tag_type << 2) | 2, util.writeNumber(length, 4)]);
result += util.writeNumber(length, 4);
} }
return result;
}, },
/** /**
@ -122,9 +112,9 @@ module.exports = {
*/ */
read: function(input, position, len) { read: function(input, position, len) {
// some sanity checks // some sanity checks
if (input === null || input.length <= position || input.substring(position).length < 2 || (input.charCodeAt(position) & if (input === null || input.length <= position || input.subarray(position, input.length).length < 2 || (input[position] &
0x80) === 0) { 0x80) === 0) {
throw new Error("Error during parsing. This message / key is probably not containing a valid OpenPGP format."); throw new Error("Error during parsing. This message / key probably does not conform to a valid OpenPGP format.");
} }
var mypos = position; var mypos = position;
var tag = -1; var tag = -1;
@ -132,18 +122,18 @@ module.exports = {
var packet_length; var packet_length;
format = 0; // 0 = old format; 1 = new format format = 0; // 0 = old format; 1 = new format
if ((input.charCodeAt(mypos) & 0x40) !== 0) { if ((input[mypos] & 0x40) !== 0) {
format = 1; format = 1;
} }
var packet_length_type; var packet_length_type;
if (format) { if (format) {
// new format header // new format header
tag = input.charCodeAt(mypos) & 0x3F; // bit 5-0 tag = input[mypos] & 0x3F; // bit 5-0
} else { } else {
// old format header // old format header
tag = (input.charCodeAt(mypos) & 0x3F) >> 2; // bit 5-2 tag = (input[mypos] & 0x3F) >> 2; // bit 5-2
packet_length_type = input.charCodeAt(mypos) & 0x03; // bit 1-0 packet_length_type = input[mypos] & 0x03; // bit 1-0
} }
// header octet parsing done // header octet parsing done
@ -160,18 +150,18 @@ module.exports = {
case 0: case 0:
// The packet has a one-octet length. The header is 2 octets // The packet has a one-octet length. The header is 2 octets
// long. // long.
packet_length = input.charCodeAt(mypos++); packet_length = input[mypos++];
break; break;
case 1: case 1:
// The packet has a two-octet length. The header is 3 octets // The packet has a two-octet length. The header is 3 octets
// long. // long.
packet_length = (input.charCodeAt(mypos++) << 8) | input.charCodeAt(mypos++); packet_length = (input[mypos++] << 8) | input[mypos++];
break; break;
case 2: case 2:
// The packet has a four-octet length. The header is 5 // The packet has a four-octet length. The header is 5
// octets long. // octets long.
packet_length = (input.charCodeAt(mypos++) << 24) | (input.charCodeAt(mypos++) << 16) | (input.charCodeAt(mypos++) << packet_length = (input[mypos++] << 24) | (input[mypos++] << 16) | (input[mypos++] <<
8) | input.charCodeAt(mypos++); 8) | input[mypos++];
break; break;
default: default:
// 3 - The packet is of indeterminate length. The header is 1 // 3 - The packet is of indeterminate length. The header is 1
@ -192,44 +182,43 @@ module.exports = {
{ {
// 4.2.2.1. One-Octet Lengths // 4.2.2.1. One-Octet Lengths
if (input.charCodeAt(mypos) < 192) { if (input[mypos] < 192) {
packet_length = input.charCodeAt(mypos++); packet_length = input[mypos++];
util.print_debug("1 byte length:" + packet_length); util.print_debug("1 byte length:" + packet_length);
// 4.2.2.2. Two-Octet Lengths // 4.2.2.2. Two-Octet Lengths
} else if (input.charCodeAt(mypos) >= 192 && input.charCodeAt(mypos) < 224) { } else if (input[mypos] >= 192 && input[mypos] < 224) {
packet_length = ((input.charCodeAt(mypos++) - 192) << 8) + (input.charCodeAt(mypos++)) + 192; packet_length = ((input[mypos++] - 192) << 8) + (input[mypos++]) + 192;
util.print_debug("2 byte length:" + packet_length); util.print_debug("2 byte length:" + packet_length);
// 4.2.2.4. Partial Body Lengths // 4.2.2.4. Partial Body Lengths
} else if (input.charCodeAt(mypos) > 223 && input.charCodeAt(mypos) < 255) { } else if (input[mypos] > 223 && input[mypos] < 255) {
packet_length = 1 << (input.charCodeAt(mypos++) & 0x1F); packet_length = 1 << (input[mypos++] & 0x1F);
util.print_debug("4 byte length:" + packet_length); util.print_debug("4 byte length:" + packet_length);
// EEEK, we're reading the full data here... // EEEK, we're reading the full data here...
var mypos2 = mypos + packet_length; var mypos2 = mypos + packet_length;
bodydata = input.substring(mypos, mypos + packet_length); bodydata = [input.subarray(mypos, mypos + packet_length)];
var tmplen; var tmplen;
while (true) { while (true) {
if (input.charCodeAt(mypos2) < 192) { if (input[mypos2] < 192) {
tmplen = input.charCodeAt(mypos2++); tmplen = input[mypos2++];
packet_length += tmplen; packet_length += tmplen;
bodydata += input.substring(mypos2, mypos2 + tmplen); bodydata.push(input.subarray(mypos2, mypos2 + tmplen));
mypos2 += tmplen; mypos2 += tmplen;
break; break;
} else if (input.charCodeAt(mypos2) >= 192 && input.charCodeAt(mypos2) < 224) { } else if (input[mypos2] >= 192 && input[mypos2] < 224) {
tmplen = ((input.charCodeAt(mypos2++) - 192) << 8) + (input.charCodeAt(mypos2++)) + 192; tmplen = ((input[mypos2++] - 192) << 8) + (input[mypos2++]) + 192;
packet_length += tmplen; packet_length += tmplen;
bodydata += input.substring(mypos2, mypos2 + tmplen); bodydata.push(input.subarray(mypos2, mypos2 + tmplen));
mypos2 += tmplen; mypos2 += tmplen;
break; break;
} else if (input.charCodeAt(mypos2) > 223 && input.charCodeAt(mypos2) < 255) { } else if (input[mypos2] > 223 && input[mypos2] < 255) {
tmplen = 1 << (input.charCodeAt(mypos2++) & 0x1F); tmplen = 1 << (input[mypos2++] & 0x1F);
packet_length += tmplen; packet_length += tmplen;
bodydata += input.substring(mypos2, mypos2 + tmplen); bodydata.push(input.subarray(mypos2, mypos2 + tmplen));
mypos2 += tmplen; mypos2 += tmplen;
} else { } else {
mypos2++; mypos2++;
tmplen = (input.charCodeAt(mypos2++) << 24) | (input.charCodeAt(mypos2++) << 16) | (input tmplen = (input[mypos2++] << 24) | (input[mypos2++] << 16) | (input[mypos2++] << 8) | input[mypos2++];
.charCodeAt(mypos2++) << 8) | input.charCodeAt(mypos2++); bodydata.push(input.subarray(mypos2, mypos2 + tmplen));
bodydata += input.substring(mypos2, mypos2 + tmplen);
packet_length += tmplen; packet_length += tmplen;
mypos2 += tmplen; mypos2 += tmplen;
break; break;
@ -239,8 +228,8 @@ module.exports = {
// 4.2.2.3. Five-Octet Lengths // 4.2.2.3. Five-Octet Lengths
} else { } else {
mypos++; mypos++;
packet_length = (input.charCodeAt(mypos++) << 24) | (input.charCodeAt(mypos++) << 16) | (input.charCodeAt(mypos++) << packet_length = (input[mypos++] << 24) | (input[mypos++] << 16) | (input[mypos++] <<
8) | input.charCodeAt(mypos++); 8) | input[mypos++];
} }
} }
@ -251,7 +240,10 @@ module.exports = {
} }
if (bodydata === null) { if (bodydata === null) {
bodydata = input.substring(mypos, mypos + real_packet_length); bodydata = input.subarray(mypos, mypos + real_packet_length);
}
else if(bodydata instanceof Array) {
bodydata = util.concatUint8Array(bodydata);
} }
return { return {

View File

@ -2,6 +2,7 @@
* This class represents a list of openpgp packets. * This class represents a list of openpgp packets.
* Take care when iterating over it - the packets themselves * Take care when iterating over it - the packets themselves
* are stored as numerical indices. * are stored as numerical indices.
* @requires util
* @requires enums * @requires enums
* @requires packet * @requires packet
* @requires packet/packet * @requires packet/packet
@ -10,7 +11,8 @@
module.exports = Packetlist; module.exports = Packetlist;
var packetParser = require('./packet.js'), var util = require('../util'),
packetParser = require('./packet.js'),
packets = require('./all_packets.js'), packets = require('./all_packets.js'),
enums = require('../enums.js'); enums = require('../enums.js');
@ -25,7 +27,7 @@ function Packetlist() {
} }
/** /**
* Reads a stream of binary data and interprents it as a list of packets. * Reads a stream of binary data and interprents it as a list of packets.
* @param {String} A binary string of bytes. * @param {Uint8Array} A Uint8Array of bytes.
*/ */
Packetlist.prototype.read = function (bytes) { Packetlist.prototype.read = function (bytes) {
var i = 0; var i = 0;
@ -46,18 +48,18 @@ Packetlist.prototype.read = function (bytes) {
/** /**
* Creates a binary representation of openpgp objects contained within the * Creates a binary representation of openpgp objects contained within the
* class instance. * class instance.
* @returns {String} A binary string of bytes containing valid openpgp packets. * @returns {Uint8Array} A Uint8Array containing valid openpgp packets.
*/ */
Packetlist.prototype.write = function () { Packetlist.prototype.write = function () {
var bytes = ''; var arr = [];
for (var i = 0; i < this.length; i++) { for (var i = 0; i < this.length; i++) {
var packetbytes = this[i].write(); var packetbytes = this[i].write();
bytes += packetParser.writeHeader(this[i].tag, packetbytes.length); arr.push(packetParser.writeHeader(this[i].tag, packetbytes.length));
bytes += packetbytes; arr.push(packetbytes);
} }
return bytes; return util.concatUint8Array(arr);
}; };
/** /**

View File

@ -70,40 +70,40 @@ function PublicKey() {
/** /**
* Internal Parser for public keys as specified in {@link http://tools.ietf.org/html/rfc4880#section-5.5.2|RFC 4880 section 5.5.2 Public-Key Packet Formats} * Internal Parser for public keys as specified in {@link http://tools.ietf.org/html/rfc4880#section-5.5.2|RFC 4880 section 5.5.2 Public-Key Packet Formats}
* called by read_tag&lt;num&gt; * called by read_tag&lt;num&gt;
* @param {String} input Input string to read the packet from * @param {Uint8Array} bytes Input array to read the packet from
* @return {Object} This object with attributes set by the parser * @return {Object} This object with attributes set by the parser
*/ */
PublicKey.prototype.read = function (bytes) { PublicKey.prototype.read = function (bytes) {
var pos = 0; var pos = 0;
// A one-octet version number (3 or 4). // A one-octet version number (3 or 4).
this.version = bytes.charCodeAt(pos++); this.version = bytes[pos++];
if (this.version == 3 || this.version == 4) { if (this.version == 3 || this.version == 4) {
// - A four-octet number denoting the time that the key was created. // - A four-octet number denoting the time that the key was created.
this.created = util.readDate(bytes.substr(pos, 4)); this.created = util.readDate(bytes.subarray(pos, pos + 4));
pos += 4; pos += 4;
if (this.version == 3) { if (this.version == 3) {
// - A two-octet number denoting the time in days that this key is // - A two-octet number denoting the time in days that this key is
// valid. If this number is zero, then it does not expire. // valid. If this number is zero, then it does not expire.
this.expirationTimeV3 = util.readNumber(bytes.substr(pos, 2)); this.expirationTimeV3 = util.readNumber(bytes.subarray(pos, pos + 2));
pos += 2; pos += 2;
} }
// - A one-octet number denoting the public-key algorithm of this key. // - A one-octet number denoting the public-key algorithm of this key.
this.algorithm = enums.read(enums.publicKey, bytes.charCodeAt(pos++)); this.algorithm = enums.read(enums.publicKey, bytes[pos++]);
var mpicount = crypto.getPublicMpiCount(this.algorithm); var mpicount = crypto.getPublicMpiCount(this.algorithm);
this.mpi = []; this.mpi = [];
var bmpi = bytes.substr(pos); var bmpi = bytes.subarray(pos, bytes.length);
var p = 0; var p = 0;
for (var i = 0; i < mpicount && p < bmpi.length; i++) { for (var i = 0; i < mpicount && p < bmpi.length; i++) {
this.mpi[i] = new type_mpi(); this.mpi[i] = new type_mpi();
p += this.mpi[i].read(bmpi.substr(p)); p += this.mpi[i].read(bmpi.subarray(p, bmpi.length));
if (p > bmpi.length) { if (p > bmpi.length) {
throw new Error('Error reading MPI @:' + p); throw new Error('Error reading MPI @:' + p);
@ -125,25 +125,26 @@ PublicKey.prototype.readPublicKey = PublicKey.prototype.read;
/** /**
* Same as write_private_key, but has less information because of * Same as write_private_key, but has less information because of
* public key. * public key.
* @return {Object} {body: [string]OpenPGP packet body contents, * @return {Uint8Array} OpenPGP packet body contents,
* header: [string] OpenPGP packet header, string: [string] header+body}
*/ */
PublicKey.prototype.write = function () { PublicKey.prototype.write = function () {
var arr = [];
// Version // Version
var result = String.fromCharCode(this.version); arr.push(new Uint8Array([this.version]));
result += util.writeDate(this.created); arr.push(util.writeDate(this.created));
if (this.version == 3) { if (this.version == 3) {
result += util.writeNumber(this.expirationTimeV3, 2); arr.push(util.writeNumber(this.expirationTimeV3, 2));
} }
result += String.fromCharCode(enums.write(enums.publicKey, this.algorithm)); arr.push(new Uint8Array([enums.write(enums.publicKey, this.algorithm)]));
var mpicount = crypto.getPublicMpiCount(this.algorithm); var mpicount = crypto.getPublicMpiCount(this.algorithm);
for (var i = 0; i < mpicount; i++) { for (var i = 0; i < mpicount; i++) {
result += this.mpi[i].write(); arr.push(this.mpi[i].write());
} }
return result; return util.concatUint8Array(arr);
}; };
/** /**
@ -158,9 +159,7 @@ PublicKey.prototype.writePublicKey = PublicKey.prototype.write;
PublicKey.prototype.writeOld = function () { PublicKey.prototype.writeOld = function () {
var bytes = this.writePublicKey(); var bytes = this.writePublicKey();
return String.fromCharCode(0x99) + return util.concatUint8Array([new Uint8Array([0x99]), util.writeNumber(bytes.length, 2), bytes]);
util.writeNumber(bytes.length, 2) +
bytes;
}; };
/** /**
@ -173,9 +172,10 @@ PublicKey.prototype.getKeyId = function () {
} }
this.keyid = new type_keyid(); this.keyid = new type_keyid();
if (this.version == 4) { if (this.version == 4) {
this.keyid.read(util.hex2bin(this.getFingerprint()).substr(12, 8)); this.keyid.read(util.str2Uint8Array(util.hex2bin(this.getFingerprint()).substr(12, 8)));
} else if (this.version == 3) { } else if (this.version == 3) {
this.keyid.read(this.mpi[0].write().substr(-8)); var arr = this.mpi[0].write();
this.keyid.read(arr.subarray(arr.length - 8, arr.length));
} }
return this.keyid; return this.keyid;
}; };
@ -191,7 +191,7 @@ PublicKey.prototype.getFingerprint = function () {
var toHash = ''; var toHash = '';
if (this.version == 4) { if (this.version == 4) {
toHash = this.writeOld(); toHash = this.writeOld();
this.fingerprint = crypto.hash.sha1(toHash); this.fingerprint = crypto.hash.sha1(util.Uint8Array2str(toHash));
} else if (this.version == 3) { } else if (this.version == 3) {
var mpicount = crypto.getPublicMpiCount(this.algorithm); var mpicount = crypto.getPublicMpiCount(this.algorithm);
for (var i = 0; i < mpicount; i++) { for (var i = 0; i < mpicount; i++) {

View File

@ -65,7 +65,7 @@ function PublicKeyEncryptedSessionKey() {
/** /**
* Parsing function for a publickey encrypted session key packet (tag 1). * Parsing function for a publickey encrypted session key packet (tag 1).
* *
* @param {String} input Payload of a tag 1 packet * @param {Uint8Array} input Payload of a tag 1 packet
* @param {Integer} position Position to start reading from the input string * @param {Integer} position Position to start reading from the input string
* @param {Integer} len Length of the packet or the remaining length of * @param {Integer} len Length of the packet or the remaining length of
* input at position * input at position
@ -73,9 +73,9 @@ function PublicKeyEncryptedSessionKey() {
*/ */
PublicKeyEncryptedSessionKey.prototype.read = function (bytes) { PublicKeyEncryptedSessionKey.prototype.read = function (bytes) {
this.version = bytes.charCodeAt(0); this.version = bytes[0];
this.publicKeyId.read(bytes.substr(1)); this.publicKeyId.read(bytes.subarray(1,bytes.length));
this.publicKeyAlgorithm = enums.read(enums.publicKey, bytes.charCodeAt(9)); this.publicKeyAlgorithm = enums.read(enums.publicKey, bytes[9]);
var i = 10; var i = 10;
@ -97,7 +97,7 @@ PublicKeyEncryptedSessionKey.prototype.read = function (bytes) {
for (var j = 0; j < integerCount; j++) { for (var j = 0; j < integerCount; j++) {
var mpi = new type_mpi(); var mpi = new type_mpi();
i += mpi.read(bytes.substr(i)); i += mpi.read(bytes.subarray(i, bytes.length));
this.encrypted.push(mpi); this.encrypted.push(mpi);
} }
}; };
@ -105,42 +105,26 @@ PublicKeyEncryptedSessionKey.prototype.read = function (bytes) {
/** /**
* Create a string representation of a tag 1 packet * Create a string representation of a tag 1 packet
* *
* @param {String} publicKeyId * @return {Uint8Array} The Uint8Array representation
* The public key id corresponding to publicMPIs key as string
* @param {Array<module:type/mpi>} publicMPIs
* Multiprecision integer objects describing the public key
* @param {module:enums.publicKey} pubalgo
* The corresponding public key algorithm // See {@link http://tools.ietf.org/html/rfc4880#section-9.1|RFC4880 9.1}
* @param {module:enums.symmetric} symmalgo
* The symmetric cipher algorithm used to encrypt the data
* within an encrypteddatapacket or encryptedintegrity-
* protecteddatapacket
* following this packet //See {@link http://tools.ietf.org/html/rfc4880#section-9.2|RFC4880 9.2}
* @param {String} sessionkey
* A string of randombytes representing the session key
* @return {String} The string representation
*/ */
PublicKeyEncryptedSessionKey.prototype.write = function () { PublicKeyEncryptedSessionKey.prototype.write = function () {
var result = String.fromCharCode(this.version); var arr = [new Uint8Array([this.version]), this.publicKeyId.write(), new Uint8Array([enums.write(enums.publicKey, this.publicKeyAlgorithm)])];
result += this.publicKeyId.write();
result += String.fromCharCode(
enums.write(enums.publicKey, this.publicKeyAlgorithm));
for (var i = 0; i < this.encrypted.length; i++) { for (var i = 0; i < this.encrypted.length; i++) {
result += this.encrypted[i].write(); arr.push(this.encrypted[i].write());
} }
return result; return util.concatUint8Array(arr);
}; };
PublicKeyEncryptedSessionKey.prototype.encrypt = function (key) { PublicKeyEncryptedSessionKey.prototype.encrypt = function (key) {
var data = String.fromCharCode( var data = String.fromCharCode(
enums.write(enums.symmetric, this.sessionKeyAlgorithm)); enums.write(enums.symmetric, this.sessionKeyAlgorithm));
data += this.sessionKey; data += util.Uint8Array2str(this.sessionKey);
var checksum = util.calc_checksum(this.sessionKey); var checksum = util.calc_checksum(this.sessionKey);
data += util.writeNumber(checksum, 2); data += util.Uint8Array2str(util.writeNumber(checksum, 2));
var mpi = new type_mpi(); var mpi = new type_mpi();
mpi.fromBytes(crypto.pkcs1.eme.encode( mpi.fromBytes(crypto.pkcs1.eme.encode(
@ -167,11 +151,11 @@ PublicKeyEncryptedSessionKey.prototype.decrypt = function (key) {
key.mpi, key.mpi,
this.encrypted).toBytes(); this.encrypted).toBytes();
var checksum = util.readNumber(result.substr(result.length - 2)); var checksum = util.readNumber(util.str2Uint8Array(result.substr(result.length - 2)));
var decoded = crypto.pkcs1.eme.decode(result); var decoded = crypto.pkcs1.eme.decode(result);
key = decoded.substring(1, decoded.length - 2); key = util.str2Uint8Array(decoded.substring(1, decoded.length - 2));
if (checksum != util.calc_checksum(key)) { if (checksum != util.calc_checksum(key)) {
throw new Error('Checksum mismatch'); throw new Error('Checksum mismatch');

View File

@ -68,7 +68,7 @@ function get_hash_fn(hash) {
return crypto.hash.sha1; return crypto.hash.sha1;
else else
return function(c) { return function(c) {
return util.writeNumber(util.calc_checksum(c), 2); return util.Uint8Array2str(util.writeNumber(util.calc_checksum(util.str2Uint8Array(c)), 2));
}; };
} }
@ -78,10 +78,10 @@ function parse_cleartext_mpi(hash_algorithm, cleartext, algorithm) {
var hashlen = get_hash_len(hash_algorithm), var hashlen = get_hash_len(hash_algorithm),
hashfn = get_hash_fn(hash_algorithm); hashfn = get_hash_fn(hash_algorithm);
var hashtext = cleartext.substr(cleartext.length - hashlen); var hashtext = util.Uint8Array2str(cleartext.subarray(cleartext.length - hashlen, cleartext.length));
cleartext = cleartext.substr(0, cleartext.length - hashlen); cleartext = cleartext.subarray(0, cleartext.length - hashlen);
var hash = hashfn(cleartext); var hash = hashfn(util.Uint8Array2str(cleartext));
if (hash != hashtext) if (hash != hashtext)
return new Error("Hash mismatch."); return new Error("Hash mismatch.");
@ -93,24 +93,25 @@ function parse_cleartext_mpi(hash_algorithm, cleartext, algorithm) {
for (var i = 0; i < mpis && j < cleartext.length; i++) { for (var i = 0; i < mpis && j < cleartext.length; i++) {
mpi[i] = new type_mpi(); mpi[i] = new type_mpi();
j += mpi[i].read(cleartext.substr(j)); j += mpi[i].read(cleartext.subarray(j, cleartext.length));
} }
return mpi; return mpi;
} }
function write_cleartext_mpi(hash_algorithm, algorithm, mpi) { function write_cleartext_mpi(hash_algorithm, algorithm, mpi) {
var bytes = ''; var arr = [];
var discard = crypto.getPublicMpiCount(algorithm); var discard = crypto.getPublicMpiCount(algorithm);
for (var i = discard; i < mpi.length; i++) { for (var i = discard; i < mpi.length; i++) {
bytes += mpi[i].write(); arr.push(mpi[i].write());
} }
var bytes = util.concatUint8Array(arr);
bytes += get_hash_fn(hash_algorithm)(bytes); var hash = get_hash_fn(hash_algorithm)(util.Uint8Array2str(bytes));
return bytes; return util.concatUint8Array([bytes, util.str2Uint8Array(hash)]);
} }
@ -124,23 +125,22 @@ SecretKey.prototype.read = function (bytes) {
// - A Public-Key or Public-Subkey packet, as described above. // - A Public-Key or Public-Subkey packet, as described above.
var len = this.readPublicKey(bytes); var len = this.readPublicKey(bytes);
bytes = bytes.substr(len); bytes = bytes.subarray(len, bytes.length);
// - One octet indicating string-to-key usage conventions. Zero // - One octet indicating string-to-key usage conventions. Zero
// indicates that the secret-key data is not encrypted. 255 or 254 // indicates that the secret-key data is not encrypted. 255 or 254
// indicates that a string-to-key specifier is being given. Any // indicates that a string-to-key specifier is being given. Any
// other value is a symmetric-key encryption algorithm identifier. // other value is a symmetric-key encryption algorithm identifier.
var isEncrypted = bytes.charCodeAt(0); var isEncrypted = bytes[0];
if (isEncrypted) { if (isEncrypted) {
this.encrypted = bytes; this.encrypted = bytes;
} else { } else {
// - Plain or encrypted multiprecision integers comprising the secret // - Plain or encrypted multiprecision integers comprising the secret
// key data. These algorithm-specific fields are as described // key data. These algorithm-specific fields are as described
// below. // below.
var parsedMPI = parse_cleartext_mpi('mod', bytes.substr(1), this.algorithm); var parsedMPI = parse_cleartext_mpi('mod', bytes.subarray(1, bytes.length), this.algorithm);
if (parsedMPI instanceof Error) if (parsedMPI instanceof Error)
throw parsedMPI; throw parsedMPI;
this.mpi = this.mpi.concat(parsedMPI); this.mpi = this.mpi.concat(parsedMPI);
@ -153,17 +153,16 @@ SecretKey.prototype.read = function (bytes) {
* @return {String} A string of bytes containing the secret key OpenPGP packet * @return {String} A string of bytes containing the secret key OpenPGP packet
*/ */
SecretKey.prototype.write = function () { SecretKey.prototype.write = function () {
var bytes = this.writePublicKey(); var arr = [this.writePublicKey()];
if (!this.encrypted) { if (!this.encrypted) {
bytes += String.fromCharCode(0); arr.push(new Uint8Array([0]));
arr.push(write_cleartext_mpi('mod', this.algorithm, this.mpi));
bytes += write_cleartext_mpi('mod', this.algorithm, this.mpi);
} else { } else {
bytes += this.encrypted; arr.push(this.encrypted);
} }
return bytes; return util.concatUint8Array(arr);
}; };
@ -190,13 +189,12 @@ SecretKey.prototype.encrypt = function (passphrase) {
blockLen = crypto.cipher[symmetric].blockSize, blockLen = crypto.cipher[symmetric].blockSize,
iv = crypto.random.getRandomBytes(blockLen); iv = crypto.random.getRandomBytes(blockLen);
this.encrypted = ''; var arr = [ new Uint8Array([254, enums.write(enums.symmetric, symmetric)]) ];
this.encrypted += String.fromCharCode(254); arr.push(s2k.write());
this.encrypted += String.fromCharCode(enums.write(enums.symmetric, symmetric)); arr.push(iv);
this.encrypted += s2k.write(); arr.push(crypto.cfb.normalEncrypt(symmetric, key, cleartext, iv));
this.encrypted += iv;
this.encrypted += crypto.cfb.normalEncrypt(symmetric, key, cleartext, iv); this.encrypted = util.concatUint8Array(arr);
}; };
function produceEncryptionKey(s2k, passphrase, algorithm) { function produceEncryptionKey(s2k, passphrase, algorithm) {
@ -222,38 +220,48 @@ SecretKey.prototype.decrypt = function (passphrase) {
symmetric, symmetric,
key; key;
var s2k_usage = this.encrypted.charCodeAt(i++); if(!Uint8Array.prototype.isPrototypeOf(this.encrypted)) {
if(Uint8Array.prototype.isPrototypeOf(this.encrypted.message)) {
throw new Error('this.encrypted.message is a typed array!');
}
if(this.encrypted === null) {
throw new Error('this.encrypted is null!');
}
throw new Error(Object.prototype.toString.call(this.encrypted));
}
var s2k_usage = this.encrypted[i++];
// - [Optional] If string-to-key usage octet was 255 or 254, a one- // - [Optional] If string-to-key usage octet was 255 or 254, a one-
// octet symmetric encryption algorithm. // octet symmetric encryption algorithm.
if (s2k_usage == 255 || s2k_usage == 254) { if (s2k_usage == 255 || s2k_usage == 254) {
symmetric = this.encrypted.charCodeAt(i++); symmetric = this.encrypted[i++];
symmetric = enums.read(enums.symmetric, symmetric); symmetric = enums.read(enums.symmetric, symmetric);
// - [Optional] If string-to-key usage octet was 255 or 254, a // - [Optional] If string-to-key usage octet was 255 or 254, a
// string-to-key specifier. The length of the string-to-key // string-to-key specifier. The length of the string-to-key
// specifier is implied by its type, as described above. // specifier is implied by its type, as described above.
var s2k = new type_s2k(); var s2k = new type_s2k();
i += s2k.read(this.encrypted.substr(i)); i += s2k.read(this.encrypted.subarray(i, this.encrypted.length));
key = produceEncryptionKey(s2k, passphrase, symmetric); key = produceEncryptionKey(s2k, passphrase, symmetric);
} else { } else {
symmetric = s2k_usage; symmetric = s2k_usage;
symmetric = enums.read(enums.symmetric, symmetric); symmetric = enums.read(enums.symmetric, symmetric);
key = crypto.hash.md5(passphrase); key = util.str2Uint8Array(crypto.hash.md5(passphrase));
} }
// - [Optional] If secret data is encrypted (string-to-key usage octet // - [Optional] If secret data is encrypted (string-to-key usage octet
// not zero), an Initial Vector (IV) of the same length as the // not zero), an Initial Vector (IV) of the same length as the
// cipher's block size. // cipher's block size.
var iv = this.encrypted.substr(i, var iv = this.encrypted.subarray(i,
crypto.cipher[symmetric].blockSize); i + crypto.cipher[symmetric].blockSize);
i += iv.length; i += iv.length;
var cleartext, var cleartext,
ciphertext = this.encrypted.substr(i); ciphertext = this.encrypted.subarray(i, this.encrypted.length);
cleartext = crypto.cfb.normalDecrypt(symmetric, key, ciphertext, iv); cleartext = crypto.cfb.normalDecrypt(symmetric, key, ciphertext, iv);

View File

@ -98,47 +98,46 @@ function Signature() {
*/ */
Signature.prototype.read = function (bytes) { Signature.prototype.read = function (bytes) {
var i = 0; var i = 0;
this.version = bytes[i++];
this.version = bytes.charCodeAt(i++);
// switch on version (3 and 4) // switch on version (3 and 4)
switch (this.version) { switch (this.version) {
case 3: case 3:
// One-octet length of following hashed material. MUST be 5. // One-octet length of following hashed material. MUST be 5.
if (bytes.charCodeAt(i++) != 5) if (bytes[i++] != 5)
util.print_debug("packet/signature.js\n" + util.print_debug("packet/signature.js\n" +
'invalid One-octet length of following hashed material.' + 'invalid One-octet length of following hashed material.' +
'MUST be 5. @:' + (i - 1)); 'MUST be 5. @:' + (i - 1));
var sigpos = i; var sigpos = i;
// One-octet signature type. // One-octet signature type.
this.signatureType = bytes.charCodeAt(i++); this.signatureType = bytes[i++];
// Four-octet creation time. // Four-octet creation time.
this.created = util.readDate(bytes.substr(i, 4)); this.created = util.readDate(bytes.subarray(i, i + 4));
i += 4; i += 4;
// storing data appended to data which gets verified // storing data appended to data which gets verified
this.signatureData = bytes.substring(sigpos, i); this.signatureData = bytes.subarray(sigpos, i);
// Eight-octet Key ID of signer. // Eight-octet Key ID of signer.
this.issuerKeyId.read(bytes.substring(i, i + 8)); this.issuerKeyId.read(bytes.subarray(i, i + 8));
i += 8; i += 8;
// One-octet public-key algorithm. // One-octet public-key algorithm.
this.publicKeyAlgorithm = bytes.charCodeAt(i++); this.publicKeyAlgorithm = bytes[i++];
// One-octet hash algorithm. // One-octet hash algorithm.
this.hashAlgorithm = bytes.charCodeAt(i++); this.hashAlgorithm = bytes[i++];
break; break;
case 4: case 4:
this.signatureType = bytes.charCodeAt(i++); this.signatureType = bytes[i++];
this.publicKeyAlgorithm = bytes.charCodeAt(i++); this.publicKeyAlgorithm = bytes[i++];
this.hashAlgorithm = bytes.charCodeAt(i++); this.hashAlgorithm = bytes[i++];
function subpackets(bytes) { function subpackets(bytes) {
// Two-octet scalar octet count for following subpacket data. // Two-octet scalar octet count for following subpacket data.
var subpacket_length = util.readNumber( var subpacket_length = util.readNumber(
bytes.substr(0, 2)); bytes.subarray(0, 2));
var i = 2; var i = 2;
@ -146,10 +145,10 @@ Signature.prototype.read = function (bytes) {
var subpacked_read = 0; var subpacked_read = 0;
while (i < 2 + subpacket_length) { while (i < 2 + subpacket_length) {
var len = packet.readSimpleLength(bytes.substr(i)); var len = packet.readSimpleLength(bytes.subarray(i, bytes.length));
i += len.offset; i += len.offset;
this.read_sub_packet(bytes.substr(i, len.len)); this.read_sub_packet(bytes.subarray(i, i + len.len));
i += len.len; i += len.len;
} }
@ -158,7 +157,7 @@ Signature.prototype.read = function (bytes) {
} }
// hashed subpackets // hashed subpackets
i += subpackets.call(this, bytes.substr(i), true); i += subpackets.call(this, bytes.subarray(i, bytes.length), true);
// A V4 signature hashes the packet body // A V4 signature hashes the packet body
// starting from its first field, the version number, through the end // starting from its first field, the version number, through the end
@ -166,12 +165,12 @@ Signature.prototype.read = function (bytes) {
// signature version, the signature type, the public-key algorithm, the // signature version, the signature type, the public-key algorithm, the
// hash algorithm, the hashed subpacket length, and the hashed // hash algorithm, the hashed subpacket length, and the hashed
// subpacket body. // subpacket body.
this.signatureData = bytes.substr(0, i); this.signatureData = bytes.subarray(0, i);
var sigDataLength = i; var sigDataLength = i;
// unhashed subpackets // unhashed subpackets
i += subpackets.call(this, bytes.substr(i), false); i += subpackets.call(this, bytes.subarray(i, bytes.length), false);
this.unhashedSubpackets = bytes.substr(sigDataLength, i - sigDataLength); this.unhashedSubpackets = bytes.subarray(sigDataLength, i);
break; break;
default: default:
@ -179,30 +178,29 @@ Signature.prototype.read = function (bytes) {
} }
// Two-octet field holding left 16 bits of signed hash value. // Two-octet field holding left 16 bits of signed hash value.
this.signedHashValue = bytes.substr(i, 2); this.signedHashValue = bytes.subarray(i, i + 2);
i += 2; i += 2;
this.signature = bytes.substr(i); this.signature = bytes.subarray(i, bytes.length);
}; };
Signature.prototype.write = function () { Signature.prototype.write = function () {
var result = ''; var arr = [];
switch (this.version) { switch (this.version) {
case 3: case 3:
result += String.fromCharCode(3); // version arr.push(new Uint8Array([3, 5])); // version, One-octet length of following hashed material. MUST be 5
result += String.fromCharCode(5); // One-octet length of following hashed material. MUST be 5 arr.push(this.signatureData);
result += this.signatureData; arr.push(this.issuerKeyId.write());
result += this.issuerKeyId.write(); arr.push(new Uint8Array([this.publicKeyAlgorithm, this.hashAlgorithm]));
result += String.fromCharCode(this.publicKeyAlgorithm);
result += String.fromCharCode(this.hashAlgorithm);
break; break;
case 4: case 4:
result += this.signatureData; arr.push(this.signatureData);
result += this.unhashedSubpackets ? this.unhashedSubpackets : util.writeNumber(0, 2); arr.push(this.unhashedSubpackets ? this.unhashedSubpackets : util.writeNumber(0, 2));
break; break;
} }
result += this.signedHashValue + this.signature; arr.push(this.signedHashValue);
return result; arr.push(this.signature);
return util.concatUint8Array(arr);
}; };
/** /**
@ -215,29 +213,25 @@ Signature.prototype.sign = function (key, data) {
publicKeyAlgorithm = enums.write(enums.publicKey, this.publicKeyAlgorithm), publicKeyAlgorithm = enums.write(enums.publicKey, this.publicKeyAlgorithm),
hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm); hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm);
var result = String.fromCharCode(4); var arr = [new Uint8Array([4, signatureType, publicKeyAlgorithm, hashAlgorithm])];
result += String.fromCharCode(signatureType);
result += String.fromCharCode(publicKeyAlgorithm);
result += String.fromCharCode(hashAlgorithm);
this.issuerKeyId = key.getKeyId(); this.issuerKeyId = key.getKeyId();
// Add hashed subpackets // Add hashed subpackets
result += this.write_all_sub_packets(); arr.push(this.write_all_sub_packets());
this.signatureData = result; this.signatureData = util.concatUint8Array(arr);
var trailer = this.calculateTrailer(); var trailer = this.calculateTrailer();
var toHash = this.toSign(signatureType, data) + var toHash = util.Uint8Array2str(util.concatUint8Array([this.toSign(signatureType, data), this.signatureData, trailer]));
this.signatureData + trailer;
var hash = crypto.hash.digest(hashAlgorithm, toHash); var hash = crypto.hash.digest(hashAlgorithm, toHash);
this.signedHashValue = hash.substr(0, 2); this.signedHashValue = util.str2Uint8Array(hash.substr(0, 2));
this.signature = crypto.signature.sign(hashAlgorithm, this.signature = util.str2Uint8Array(crypto.signature.sign(hashAlgorithm,
publicKeyAlgorithm, key.mpi, toHash); publicKeyAlgorithm, key.mpi, util.str2Uint8Array(toHash)));
}; };
/** /**
@ -246,108 +240,108 @@ Signature.prototype.sign = function (key, data) {
*/ */
Signature.prototype.write_all_sub_packets = function () { Signature.prototype.write_all_sub_packets = function () {
var sub = enums.signatureSubpacket; var sub = enums.signatureSubpacket;
var result = ''; var arr = [];
var bytes = ''; var bytes;
if (this.created !== null) { if (this.created !== null) {
result += write_sub_packet(sub.signature_creation_time, util.writeDate(this.created)); arr.push(write_sub_packet(sub.signature_creation_time, util.writeDate(this.created)));
} }
if (this.signatureExpirationTime !== null) { if (this.signatureExpirationTime !== null) {
result += write_sub_packet(sub.signature_expiration_time, util.writeNumber(this.signatureExpirationTime, 4)); arr.push(write_sub_packet(sub.signature_expiration_time, util.writeNumber(this.signatureExpirationTime, 4)));
} }
if (this.exportable !== null) { if (this.exportable !== null) {
result += write_sub_packet(sub.exportable_certification, String.fromCharCode(this.exportable ? 1 : 0)); arr.push(write_sub_packet(sub.exportable_certification, new Uint8Array([this.exportable ? 1 : 0])));
} }
if (this.trustLevel !== null) { if (this.trustLevel !== null) {
bytes = String.fromCharCode(this.trustLevel) + String.fromCharCode(this.trustAmount); bytes = new Uint8Array([this.trustLevel,this.trustAmount]);;
result += write_sub_packet(sub.trust_signature, bytes); arr.push(write_sub_packet(sub.trust_signature, bytes));
} }
if (this.regularExpression !== null) { if (this.regularExpression !== null) {
result += write_sub_packet(sub.regular_expression, this.regularExpression); arr.push(write_sub_packet(sub.regular_expression, this.regularExpression));
} }
if (this.revocable !== null) { if (this.revocable !== null) {
result += write_sub_packet(sub.revocable, String.fromCharCode(this.revocable ? 1 : 0)); arr.push(write_sub_packet(sub.revocable, new Uint8Array([this.revocable ? 1 : 0])));
} }
if (this.keyExpirationTime !== null) { if (this.keyExpirationTime !== null) {
result += write_sub_packet(sub.key_expiration_time, util.writeNumber(this.keyExpirationTime, 4)); arr.push(write_sub_packet(sub.key_expiration_time, util.writeNumber(this.keyExpirationTime, 4)));
} }
if (this.preferredSymmetricAlgorithms !== null) { if (this.preferredSymmetricAlgorithms !== null) {
bytes = util.bin2str(this.preferredSymmetricAlgorithms); bytes = util.str2Uint8Array(util.bin2str(this.preferredSymmetricAlgorithms));
result += write_sub_packet(sub.preferred_symmetric_algorithms, bytes); arr.push(write_sub_packet(sub.preferred_symmetric_algorithms, bytes));
} }
if (this.revocationKeyClass !== null) { if (this.revocationKeyClass !== null) {
bytes = String.fromCharCode(this.revocationKeyClass);
bytes += String.fromCharCode(this.revocationKeyAlgorithm); bytes = new Uint8Array([this.revocationKeyClass, this.revocationKeyAlgorithm]);
bytes += this.revocationKeyFingerprint; bytes = util.concatUint8Array([bytes, this.revocationKeyFingerprint]);
result += write_sub_packet(sub.revocation_key, bytes); arr.push(write_sub_packet(sub.revocation_key, bytes));
} }
if (!this.issuerKeyId.isNull()) { if (!this.issuerKeyId.isNull()) {
result += write_sub_packet(sub.issuer, this.issuerKeyId.write()); arr.push(write_sub_packet(sub.issuer, this.issuerKeyId.write()));
} }
if (this.notation !== null) { if (this.notation !== null) {
for (var name in this.notation) { for (var name in this.notation) {
if (this.notation.hasOwnProperty(name)) { if (this.notation.hasOwnProperty(name)) {
var value = this.notation[name]; var value = this.notation[name];
bytes = String.fromCharCode(0x80); bytes = [new Uint8Array([0x80, 0, 0, 0])];
bytes += String.fromCharCode(0);
bytes += String.fromCharCode(0);
bytes += String.fromCharCode(0);
// 2 octets of name length // 2 octets of name length
bytes += util.writeNumber(name.length, 2); bytes.push(util.writeNumber(name.length, 2));
// 2 octets of value length // 2 octets of value length
bytes += util.writeNumber(value.length, 2); bytes.push(util.writeNumber(value.length, 2));
bytes += name + value; bytes.push(util.str2Uint8Array(name + value));
result += write_sub_packet(sub.notation_data, bytes); bytes = concatUint8Array(bytes);
arr.push(write_sub_packet(sub.notation_data, bytes));
} }
} }
} }
if (this.preferredHashAlgorithms !== null) { if (this.preferredHashAlgorithms !== null) {
bytes = util.bin2str(this.preferredHashAlgorithms); bytes = util.str2Uint8Array(util.bin2str(this.preferredHashAlgorithms));
result += write_sub_packet(sub.preferred_hash_algorithms, bytes); arr.push(write_sub_packet(sub.preferred_hash_algorithms, bytes));
} }
if (this.preferredCompressionAlgorithms !== null) { if (this.preferredCompressionAlgorithms !== null) {
bytes = util.bin2str(this.preferredCompressionAlgorithms); bytes = util.str2Uint8Array(util.bin2str(this.preferredCompressionAlgorithms));
result += write_sub_packet(sub.preferred_compression_algorithms, bytes); arr.push(write_sub_packet(sub.preferred_compression_algorithms, bytes));
} }
if (this.keyServerPreferences !== null) { if (this.keyServerPreferences !== null) {
bytes = util.bin2str(this.keyServerPreferences); bytes = util.str2Uint8Array(util.bin2str(this.keyServerPreferences));
result += write_sub_packet(sub.key_server_preferences, bytes); arr.push(write_sub_packet(sub.key_server_preferences, bytes));
} }
if (this.preferredKeyServer !== null) { if (this.preferredKeyServer !== null) {
result += write_sub_packet(sub.preferred_key_server, this.preferredKeyServer); arr.push(write_sub_packet(sub.preferred_key_server, util.str2Uint8Array(this.preferredKeyServer)));
} }
if (this.isPrimaryUserID !== null) { if (this.isPrimaryUserID !== null) {
result += write_sub_packet(sub.primary_user_id, String.fromCharCode(this.isPrimaryUserID ? 1 : 0)); arr.push(write_sub_packet(sub.primary_user_id, new Uint8Array([this.isPrimaryUserID ? 1 : 0])));
} }
if (this.policyURI !== null) { if (this.policyURI !== null) {
result += write_sub_packet(sub.policy_uri, this.policyURI); arr.push(write_sub_packet(sub.policy_uri, util.str2Uint8Array(this.policyURI)));
} }
if (this.keyFlags !== null) { if (this.keyFlags !== null) {
bytes = util.bin2str(this.keyFlags); bytes = util.str2Uint8Array(util.bin2str(this.keyFlags));
result += write_sub_packet(sub.key_flags, bytes); arr.push(write_sub_packet(sub.key_flags, bytes));
} }
if (this.signersUserId !== null) { if (this.signersUserId !== null) {
result += write_sub_packet(sub.signers_user_id, this.signersUserId); arr.push(write_sub_packet(sub.signers_user_id, util.str2Uint8Array(this.signersUserId)));
} }
if (this.reasonForRevocationFlag !== null) { if (this.reasonForRevocationFlag !== null) {
bytes = String.fromCharCode(this.reasonForRevocationFlag); bytes = util.str2Uint8Array(String.fromCharCode(this.reasonForRevocationFlag) + this.reasonForRevocationString);
bytes += this.reasonForRevocationString; arr.push(write_sub_packet(sub.reason_for_revocation, bytes));
result += write_sub_packet(sub.reason_for_revocation, bytes);
} }
if (this.features !== null) { if (this.features !== null) {
bytes = util.bin2str(this.features); bytes = util.str2Uint8Array(util.bin2str(this.features));
result += write_sub_packet(sub.features, bytes); arr.push(write_sub_packet(sub.features, bytes));
} }
if (this.signatureTargetPublicKeyAlgorithm !== null) { if (this.signatureTargetPublicKeyAlgorithm !== null) {
bytes = String.fromCharCode(this.signatureTargetPublicKeyAlgorithm); bytes = [new Uint8Array([this.signatureTargetPublicKeyAlgorithm, this.signatureTargetHashAlgorithm])];
bytes += String.fromCharCode(this.signatureTargetHashAlgorithm); bytes.push(util.str2Uint8Array(this.signatureTargetHash));
bytes += this.signatureTargetHash; bytes = util.concatUint8Array(bytes);
result += write_sub_packet(sub.signature_target, bytes); arr.push(write_sub_packet(sub.signature_target, bytes));
} }
if (this.embeddedSignature !== null) { if (this.embeddedSignature !== null) {
result += write_sub_packet(sub.embedded_signature, this.embeddedSignature.write()); arr.push(write_sub_packet(sub.embedded_signature, this.embeddedSignature.write()));
} }
result = util.writeNumber(result.length, 2) + result;
return result; var result = util.concatUint8Array(arr);
var length = util.writeNumber(result.length, 2);
return util.concatUint8Array([length, result]);
}; };
/** /**
@ -358,11 +352,11 @@ Signature.prototype.write_all_sub_packets = function () {
* @return {String} a string-representation of a sub signature packet (See {@link http://tools.ietf.org/html/rfc4880#section-5.2.3.1|RFC 4880 5.2.3.1}) * @return {String} a string-representation of a sub signature packet (See {@link http://tools.ietf.org/html/rfc4880#section-5.2.3.1|RFC 4880 5.2.3.1})
*/ */
function write_sub_packet(type, data) { function write_sub_packet(type, data) {
var result = ""; var arr = [];
result += packet.writeSimpleLength(data.length + 1); arr.push(packet.writeSimpleLength(data.length + 1));
result += String.fromCharCode(type); arr.push(new Uint8Array([type]));
result += data; arr.push(data);
return result; return util.concatUint8Array(arr);
} }
// V4 signature sub packets // V4 signature sub packets
@ -374,23 +368,23 @@ Signature.prototype.read_sub_packet = function (bytes) {
this[prop] = []; this[prop] = [];
for (var i = 0; i < bytes.length; i++) { for (var i = 0; i < bytes.length; i++) {
this[prop].push(bytes.charCodeAt(i)); this[prop].push(bytes[i]);
} }
} }
// The leftwost bit denotes a "critical" packet, but we ignore it. // The leftwost bit denotes a "critical" packet, but we ignore it.
var type = bytes.charCodeAt(mypos++) & 0x7F; var type = bytes[mypos++] & 0x7F;
var seconds; var seconds;
// subpacket type // subpacket type
switch (type) { switch (type) {
case 2: case 2:
// Signature Creation Time // Signature Creation Time
this.created = util.readDate(bytes.substr(mypos)); this.created = util.readDate(bytes.subarray(mypos, bytes.length));
break; break;
case 3: case 3:
// Signature Expiration Time in seconds // Signature Expiration Time in seconds
seconds = util.readNumber(bytes.substr(mypos)); seconds = util.readNumber(bytes.subarray(mypos, bytes.length));
this.signatureNeverExpires = seconds === 0; this.signatureNeverExpires = seconds === 0;
this.signatureExpirationTime = seconds; this.signatureExpirationTime = seconds;
@ -398,24 +392,24 @@ Signature.prototype.read_sub_packet = function (bytes) {
break; break;
case 4: case 4:
// Exportable Certification // Exportable Certification
this.exportable = bytes.charCodeAt(mypos++) == 1; this.exportable = bytes[mypos++] == 1;
break; break;
case 5: case 5:
// Trust Signature // Trust Signature
this.trustLevel = bytes.charCodeAt(mypos++); this.trustLevel = bytes[mypos++];
this.trustAmount = bytes.charCodeAt(mypos++); this.trustAmount = bytes[mypos++];
break; break;
case 6: case 6:
// Regular Expression // Regular Expression
this.regularExpression = bytes.substr(mypos); this.regularExpression = bytes[mypos];
break; break;
case 7: case 7:
// Revocable // Revocable
this.revocable = bytes.charCodeAt(mypos++) == 1; this.revocable = bytes[mypos++] == 1;
break; break;
case 9: case 9:
// Key Expiration Time in seconds // Key Expiration Time in seconds
seconds = util.readNumber(bytes.substr(mypos)); seconds = util.readNumber(bytes.subarray(mypos, bytes.length));
this.keyExpirationTime = seconds; this.keyExpirationTime = seconds;
this.keyNeverExpires = seconds === 0; this.keyNeverExpires = seconds === 0;
@ -423,59 +417,59 @@ Signature.prototype.read_sub_packet = function (bytes) {
break; break;
case 11: case 11:
// Preferred Symmetric Algorithms // Preferred Symmetric Algorithms
read_array.call(this, 'preferredSymmetricAlgorithms', bytes.substr(mypos)); read_array.call(this, 'preferredSymmetricAlgorithms', bytes.subarray(mypos, bytes.length));
break; break;
case 12: case 12:
// Revocation Key // Revocation Key
// (1 octet of class, 1 octet of public-key algorithm ID, 20 // (1 octet of class, 1 octet of public-key algorithm ID, 20
// octets of // octets of
// fingerprint) // fingerprint)
this.revocationKeyClass = bytes.charCodeAt(mypos++); this.revocationKeyClass = bytes[mypos++];
this.revocationKeyAlgorithm = bytes.charCodeAt(mypos++); this.revocationKeyAlgorithm = bytes[mypos++];
this.revocationKeyFingerprint = bytes.substr(mypos, 20); this.revocationKeyFingerprint = bytes.subarray(mypos, 20);
break; break;
case 16: case 16:
// Issuer // Issuer
this.issuerKeyId.read(bytes.substr(mypos)); this.issuerKeyId.read(bytes.subarray(mypos, bytes.length));
break; break;
case 20: case 20:
// Notation Data // Notation Data
// We don't know how to handle anything but a text flagged data. // We don't know how to handle anything but a text flagged data.
if (bytes.charCodeAt(mypos) == 0x80) { if (bytes[mypos] == 0x80) {
// We extract key/value tuple from the byte stream. // We extract key/value tuple from the byte stream.
mypos += 4; mypos += 4;
var m = util.readNumber(bytes.substr(mypos, 2)); var m = util.readNumber(bytes.subarray(mypos, mypos + 2));
mypos += 2; mypos += 2;
var n = util.readNumber(bytes.substr(mypos, 2)); var n = util.readNumber(bytes.subarray(mypos, mypos + 2));
mypos += 2; mypos += 2;
var name = bytes.substr(mypos, m), var name = util.Uint8Array2str(bytes.subarray(mypos, mypos + m)),
value = bytes.substr(mypos + m, n); value = util.Uint8Array2str(bytes.subarray(mypos + m, mypos + m + n));
this.notation = this.notation || {}; this.notation = this.notation || {};
this.notation[name] = value; this.notation[name] = value;
} else { } else {
util.print_debug("Unsupported notation flag "+bytes.charCodeAt(mypos)); util.print_debug("Unsupported notation flag "+bytes[mypos]);
} }
break; break;
case 21: case 21:
// Preferred Hash Algorithms // Preferred Hash Algorithms
read_array.call(this, 'preferredHashAlgorithms', bytes.substr(mypos)); read_array.call(this, 'preferredHashAlgorithms', bytes.subarray(mypos, bytes.length));
break; break;
case 22: case 22:
// Preferred Compression Algorithms // Preferred Compression Algorithms
read_array.call(this, 'preferredCompressionAlgorithms', bytes.substr(mypos)); read_array.call(this, 'preferredCompressionAlgorithms', bytes.subarray(mypos, bytes.length));
break; break;
case 23: case 23:
// Key Server Preferences // Key Server Preferences
read_array.call(this, 'keyServerPreferencess', bytes.substr(mypos)); read_array.call(this, 'keyServerPreferencess', bytes.subarray(mypos, bytes.length));
break; break;
case 24: case 24:
// Preferred Key Server // Preferred Key Server
this.preferredKeyServer = bytes.substr(mypos); this.preferredKeyServer = util.Uint8Array2str(bytes.subarray(mypos, bytes.length));
break; break;
case 25: case 25:
// Primary User ID // Primary User ID
@ -483,39 +477,39 @@ Signature.prototype.read_sub_packet = function (bytes) {
break; break;
case 26: case 26:
// Policy URI // Policy URI
this.policyURI = bytes.substr(mypos); this.policyURI = util.Uint8Array2str(bytes.subarray(mypos, bytes.length));
break; break;
case 27: case 27:
// Key Flags // Key Flags
read_array.call(this, 'keyFlags', bytes.substr(mypos)); read_array.call(this, 'keyFlags', bytes.subarray(mypos, bytes.length));
break; break;
case 28: case 28:
// Signer's User ID // Signer's User ID
this.signersUserId += bytes.substr(mypos); this.signersUserId += util.Uint8Array2str(bytes.subarray(mypos, bytes.length));
break; break;
case 29: case 29:
// Reason for Revocation // Reason for Revocation
this.reasonForRevocationFlag = bytes.charCodeAt(mypos++); this.reasonForRevocationFlag = bytes[mypos++];
this.reasonForRevocationString = bytes.substr(mypos); this.reasonForRevocationString = util.Uint8Array2str(bytes.subarray(mypos, bytes.length));
break; break;
case 30: case 30:
// Features // Features
read_array.call(this, 'features', bytes.substr(mypos)); read_array.call(this, 'features', bytes.subarray(mypos, bytes.length));
break; break;
case 31: case 31:
// Signature Target // Signature Target
// (1 octet public-key algorithm, 1 octet hash algorithm, N octets hash) // (1 octet public-key algorithm, 1 octet hash algorithm, N octets hash)
this.signatureTargetPublicKeyAlgorithm = bytes.charCodeAt(mypos++); this.signatureTargetPublicKeyAlgorithm = bytes[mypos++];
this.signatureTargetHashAlgorithm = bytes.charCodeAt(mypos++); this.signatureTargetHashAlgorithm = bytes[mypos++];
var len = crypto.getHashByteLength(this.signatureTargetHashAlgorithm); var len = crypto.getHashByteLength(this.signatureTargetHashAlgorithm);
this.signatureTargetHash = bytes.substr(mypos, len); this.signatureTargetHash = util.Uint8Array2str(bytes.subarray(mypos, mypos + len));
break; break;
case 32: case 32:
// Embedded Signature // Embedded Signature
this.embeddedSignature = new Signature(); this.embeddedSignature = new Signature();
this.embeddedSignature.read(bytes.substr(mypos)); this.embeddedSignature.read(bytes.subarray(mypos, bytes.length));
break; break;
default: default:
util.print_debug("Unknown signature subpacket type " + type + " @:" + mypos); util.print_debug("Unknown signature subpacket type " + type + " @:" + mypos);
@ -532,7 +526,7 @@ Signature.prototype.toSign = function (type, data) {
return data.getBytes(); return data.getBytes();
case t.standalone: case t.standalone:
return ''; return new Uint8Array(0);
case t.cert_generic: case t.cert_generic:
case t.cert_persona: case t.cert_persona:
@ -553,33 +547,32 @@ Signature.prototype.toSign = function (type, data) {
var bytes = packet.write(); var bytes = packet.write();
if (this.version == 4) { if (this.version == 4) {
return this.toSign(t.key, data) + return util.concatUint8Array([this.toSign(t.key, data),
String.fromCharCode(tag) + new Uint8Array([tag]),
util.writeNumber(bytes.length, 4) + util.writeNumber(bytes.length, 4),
bytes; bytes]);
} else if (this.version == 3) { } else if (this.version == 3) {
return this.toSign(t.key, data) + return util.concatUint8Array([this.toSign(t.key, data),
bytes; bytes]);
} }
break; break;
case t.subkey_binding: case t.subkey_binding:
case t.subkey_revocation: case t.subkey_revocation:
case t.key_binding: case t.key_binding:
return this.toSign(t.key, data) + this.toSign(t.key, { return util.concatUint8Array([this.toSign(t.key, data),this.toSign(t.key, {
key: data.bind key: data.bind
}); })]);
case t.key: case t.key:
if (data.key === undefined) if (data.key === undefined)
throw new Error('Key packet is required for this signature.'); throw new Error('Key packet is required for this signature.');
return data.key.writeOld(); return data.key.writeOld();
case t.key_revocation: case t.key_revocation:
return this.toSign(t.key, data); return this.toSign(t.key, data);
case t.timestamp: case t.timestamp:
return ''; return new Uint8Array(0);
case t.third_party: case t.third_party:
throw new Error('Not implemented'); throw new Error('Not implemented');
default: default:
@ -590,13 +583,10 @@ Signature.prototype.toSign = function (type, data) {
Signature.prototype.calculateTrailer = function () { Signature.prototype.calculateTrailer = function () {
// calculating the trailer // calculating the trailer
var trailer = '';
// V3 signatures don't have a trailer // V3 signatures don't have a trailer
if (this.version == 3) return trailer; if (this.version == 3) return new Uint8Array(0);
trailer += String.fromCharCode(4); // Version var first = new Uint8Array([4, 0xFF]); //Version, ?
trailer += String.fromCharCode(0xFF); return util.concatUint8Array([first, util.writeNumber(this.signatureData.length, 4)]);
trailer += util.writeNumber(this.signatureData.length, 4);
return trailer;
}; };
@ -631,12 +621,12 @@ Signature.prototype.verify = function (key, data) {
i = 0; i = 0;
for (var j = 0; j < mpicount; j++) { for (var j = 0; j < mpicount; j++) {
mpi[j] = new type_mpi(); mpi[j] = new type_mpi();
i += mpi[j].read(this.signature.substr(i)); i += mpi[j].read(this.signature.subarray(i, this.signature.length));
} }
this.verified = crypto.signature.verify(publicKeyAlgorithm, this.verified = crypto.signature.verify(publicKeyAlgorithm,
hashAlgorithm, mpi, key.mpi, hashAlgorithm, mpi, key.mpi,
bytes + this.signatureData + trailer); util.concatUint8Array([bytes, this.signatureData, trailer]));
return this.verified; return this.verified;
}; };

View File

@ -56,7 +56,7 @@ function SymEncryptedIntegrityProtected() {
SymEncryptedIntegrityProtected.prototype.read = function (bytes) { SymEncryptedIntegrityProtected.prototype.read = function (bytes) {
// - A one-octet version number. The only currently defined value is 1. // - A one-octet version number. The only currently defined value is 1.
var version = bytes.charCodeAt(0); var version = bytes[0];
if (version != 1) { if (version != 1) {
throw new Error('Invalid packet version.'); throw new Error('Invalid packet version.');
@ -65,40 +65,35 @@ SymEncryptedIntegrityProtected.prototype.read = function (bytes) {
// - Encrypted data, the output of the selected symmetric-key cipher // - Encrypted data, the output of the selected symmetric-key cipher
// operating in Cipher Feedback mode with shift amount equal to the // operating in Cipher Feedback mode with shift amount equal to the
// block size of the cipher (CFB-n where n is the block size). // block size of the cipher (CFB-n where n is the block size).
this.encrypted = bytes.substr(1); this.encrypted = bytes.subarray(1, bytes.length);
}; };
SymEncryptedIntegrityProtected.prototype.write = function () { SymEncryptedIntegrityProtected.prototype.write = function () {
// 1 = Version // 1 = Version
return String.fromCharCode(1) + this.encrypted; return util.concatUint8Array([new Uint8Array([1]), this.encrypted]);
}; };
SymEncryptedIntegrityProtected.prototype.encrypt = function (sessionKeyAlgorithm, key) { SymEncryptedIntegrityProtected.prototype.encrypt = function (sessionKeyAlgorithm, key) {
var bytes = this.packets.write(); var bytes = this.packets.write();
var prefixrandom = crypto.getPrefixRandom(sessionKeyAlgorithm); var prefixrandom = crypto.getPrefixRandom(sessionKeyAlgorithm);
var prefix = prefixrandom + prefixrandom.charAt(prefixrandom.length - 2) + prefixrandom.charAt(prefixrandom.length - var repeat = new Uint8Array([prefixrandom[prefixrandom.length - 2], prefixrandom[prefixrandom.length - 1]]);
1); var prefix = util.concatUint8Array([prefixrandom, repeat]);
var tohash = bytes;
// Modification detection code packet. // Modification detection code packet.
tohash += String.fromCharCode(0xD3); var mdc = new Uint8Array([0xD3, 0x14]);
tohash += String.fromCharCode(0x14);
// This could probably be cleaned up to use less memory
var tohash = util.concatUint8Array([bytes, mdc]);
tohash += crypto.hash.sha1(prefix + tohash); var hash = util.str2Uint8Array(crypto.hash.sha1(util.Uint8Array2str(util.concatUint8Array([prefix, tohash]))));
tohash = util.concatUint8Array([tohash, hash]);
this.encrypted = crypto.cfb.encrypt(prefixrandom, this.encrypted = crypto.cfb.encrypt(prefixrandom,
sessionKeyAlgorithm, tohash, key, false); sessionKeyAlgorithm, tohash, key, false).subarray(0,
prefix.length + tohash.length);
if (prefix.length + tohash.length != this.encrypted.length)
{
this.encrypted = this.encrypted.substring(0, prefix.length + tohash.length);
}
}; };
/** /**
@ -114,20 +109,15 @@ SymEncryptedIntegrityProtected.prototype.decrypt = function (sessionKeyAlgorithm
var decrypted = crypto.cfb.decrypt( var decrypted = crypto.cfb.decrypt(
sessionKeyAlgorithm, key, this.encrypted, false); sessionKeyAlgorithm, key, this.encrypted, false);
var mdc = decrypted.slice(decrypted.length - 20, decrypted.length).join('');
decrypted.splice(decrypted.length - 20);
// there must be a modification detection code packet as the // there must be a modification detection code packet as the
// last packet and everything gets hashed except the hash itself // last packet and everything gets hashed except the hash itself
this.hash = crypto.hash.sha1( this.hash = crypto.hash.sha1(util.Uint8Array2str(util.concatUint8Array([crypto.cfb.mdc(sessionKeyAlgorithm, key, this.encrypted),
crypto.cfb.mdc(sessionKeyAlgorithm, key, this.encrypted) + decrypted.join('')); decrypted.subarray(0, decrypted.length - 20)])));
var mdc = util.Uint8Array2str(decrypted.subarray(decrypted.length - 20, decrypted.length));
if (this.hash != mdc) { if (this.hash != mdc) {
throw new Error('Modification detected.'); throw new Error('Modification detected.');
} else { } else
decrypted.splice(decrypted.length - 2); this.packets.read(decrypted.subarray(0, decrypted.length - 22));
this.packets.read(decrypted.join(''));
}
}; };

View File

@ -29,13 +29,15 @@
* The recipient of the message finds a session key that is encrypted to their * The recipient of the message finds a session key that is encrypted to their
* public key, decrypts the session key, and then uses the session key to * public key, decrypts the session key, and then uses the session key to
* decrypt the message. * decrypt the message.
* @requires util
* @requires crypto * @requires crypto
* @requires enums * @requires enums
* @requires type/s2k * @requires type/s2k
* @module packet/sym_encrypted_session_key * @module packet/sym_encrypted_session_key
*/ */
var type_s2k = require('../type/s2k.js'), var util = require('../util.js'),
type_s2k = require('../type/s2k.js'),
enums = require('../enums.js'), enums = require('../enums.js'),
crypto = require('../crypto'); crypto = require('../crypto');
@ -57,7 +59,7 @@ function SymEncryptedSessionKey() {
/** /**
* Parsing function for a symmetric encrypted session key packet (tag 3). * Parsing function for a symmetric encrypted session key packet (tag 3).
* *
* @param {String} input Payload of a tag 1 packet * @param {Uint8Array} input Payload of a tag 1 packet
* @param {Integer} position Position to start reading from the input string * @param {Integer} position Position to start reading from the input string
* @param {Integer} len * @param {Integer} len
* Length of the packet or the remaining length of * Length of the packet or the remaining length of
@ -66,20 +68,20 @@ function SymEncryptedSessionKey() {
*/ */
SymEncryptedSessionKey.prototype.read = function(bytes) { SymEncryptedSessionKey.prototype.read = function(bytes) {
// A one-octet version number. The only currently defined version is 4. // A one-octet version number. The only currently defined version is 4.
this.version = bytes.charCodeAt(0); this.version = bytes[0];
// A one-octet number describing the symmetric algorithm used. // A one-octet number describing the symmetric algorithm used.
var algo = enums.read(enums.symmetric, bytes.charCodeAt(1)); var algo = enums.read(enums.symmetric, bytes[1]);
// A string-to-key (S2K) specifier, length as defined above. // A string-to-key (S2K) specifier, length as defined above.
var s2klength = this.s2k.read(bytes.substr(2)); var s2klength = this.s2k.read(bytes.subarray(2, bytes.length));
// Optionally, the encrypted session key itself, which is decrypted // Optionally, the encrypted session key itself, which is decrypted
// with the string-to-key object. // with the string-to-key object.
var done = s2klength + 2; var done = s2klength + 2;
if (done < bytes.length) { if (done < bytes.length) {
this.encrypted = bytes.substr(done); this.encrypted = bytes.subarray(done, bytes.length);
this.sessionKeyEncryptionAlgorithm = algo; this.sessionKeyEncryptionAlgorithm = algo;
} else } else
this.sessionKeyAlgorithm = algo; this.sessionKeyAlgorithm = algo;
@ -90,12 +92,10 @@ SymEncryptedSessionKey.prototype.write = function() {
this.sessionKeyAlgorithm : this.sessionKeyAlgorithm :
this.sessionKeyEncryptionAlgorithm; this.sessionKeyEncryptionAlgorithm;
var bytes = String.fromCharCode(this.version) + var bytes = util.concatUint8Array([new Uint8Array([this.version, enums.write(enums.symmetric, algo)]), this.s2k.write()]);
String.fromCharCode(enums.write(enums.symmetric, algo)) +
this.s2k.write();
if (this.encrypted !== null) if (this.encrypted !== null)
bytes += this.encrypted; bytes = util.concatUint8Array([bytes, this.encrypted]);
return bytes; return bytes;
}; };
@ -103,7 +103,7 @@ SymEncryptedSessionKey.prototype.write = function() {
* Decrypts the session key (only for public key encrypted session key * Decrypts the session key (only for public key encrypted session key
* packets (tag 1) * packets (tag 1)
* *
* @return {String} The unencrypted session key * @return {Uint8Array} The unencrypted session key
*/ */
SymEncryptedSessionKey.prototype.decrypt = function(passphrase) { SymEncryptedSessionKey.prototype.decrypt = function(passphrase) {
var algo = this.sessionKeyEncryptionAlgorithm !== null ? var algo = this.sessionKeyEncryptionAlgorithm !== null ?
@ -122,9 +122,9 @@ SymEncryptedSessionKey.prototype.decrypt = function(passphrase) {
algo, key, this.encrypted, null); algo, key, this.encrypted, null);
this.sessionKeyAlgorithm = enums.read(enums.symmetric, this.sessionKeyAlgorithm = enums.read(enums.symmetric,
decrypted.charCodeAt(0)); decrypted[0]);
this.sessionKey = decrypted.substr(1); this.sessionKey = decrypted.subarray(1,decrypted.length);
} }
}; };
@ -138,14 +138,14 @@ SymEncryptedSessionKey.prototype.encrypt = function(passphrase) {
var length = crypto.cipher[algo].keySize; var length = crypto.cipher[algo].keySize;
var key = this.s2k.produce_key(passphrase, length); var key = this.s2k.produce_key(passphrase, length);
var algo_enum = String.fromCharCode( var algo_enum = new Uint8Array([
enums.write(enums.symmetric, this.sessionKeyAlgorithm)); enums.write(enums.symmetric, this.sessionKeyAlgorithm)]);
var private_key; var private_key;
if(this.sessionKey === null) { if(this.sessionKey === null) {
this.sessionKey = crypto.getRandomBytes(crypto.cipher[this.sessionKeyAlgorithm].keySize); this.sessionKey = crypto.getRandomBytes(crypto.cipher[this.sessionKeyAlgorithm].keySize);
} }
private_key = algo_enum + this.sessionKey; private_key = util.concatUint8Array([algo_enum, this.sessionKey]);
this.encrypted = crypto.cfb.normalEncrypt( this.encrypted = crypto.cfb.normalEncrypt(
algo, key, private_key, null); algo, key, private_key, null);

View File

@ -52,30 +52,30 @@ function UserAttribute() {
/** /**
* parsing function for a user attribute packet (tag 17). * parsing function for a user attribute packet (tag 17).
* @param {String} input payload of a tag 17 packet * @param {Uint8Array} input payload of a tag 17 packet
*/ */
UserAttribute.prototype.read = function(bytes) { UserAttribute.prototype.read = function(bytes) {
var i = 0; var i = 0;
while (i < bytes.length) { while (i < bytes.length) {
var len = packet.readSimpleLength(bytes.substr(i)); var len = packet.readSimpleLength(bytes.subarray(i, bytes.length));
i += len.offset; i += len.offset;
this.attributes.push(bytes.substr(i, len.len)); this.attributes.push(util.Uint8Array2str(bytes.subarray(i, i + len.len)));
i += len.len; i += len.len;
} }
}; };
/** /**
* Creates a string representation of the user attribute packet * Creates a binary representation of the user attribute packet
* @return {String} string representation * @return {Uint8Array} string representation
*/ */
UserAttribute.prototype.write = function() { UserAttribute.prototype.write = function() {
var result = ''; var arr = [];
for (var i = 0; i < this.attributes.length; i++) { for (var i = 0; i < this.attributes.length; i++) {
result += packet.writeSimpleLength(this.attributes[i].length); arr.push(packet.writeSimpleLength(this.attributes[i].length));
result += this.attributes[i]; arr.push(util.str2Uint8Array(this.attributes[i]));
} }
return result; return util.concatUint8Array(arr);
}; };
/** /**

View File

@ -47,16 +47,16 @@ function Userid() {
/** /**
* Parsing function for a user id packet (tag 13). * Parsing function for a user id packet (tag 13).
* @param {String} input payload of a tag 13 packet * @param {Uint8Array} input payload of a tag 13 packet
*/ */
Userid.prototype.read = function (bytes) { Userid.prototype.read = function (bytes) {
this.userid = util.decode_utf8(bytes); this.userid = util.decode_utf8(util.Uint8Array2str(bytes));
}; };
/** /**
* Creates a string representation of the user id packet * Creates a binary representation of the user id packet
* @return {String} string representation * @return {Uint8Array} binary representation
*/ */
Userid.prototype.write = function () { Userid.prototype.write = function () {
return util.encode_utf8(this.userid); return util.str2Uint8Array(util.encode_utf8(this.userid));
}; };

View File

@ -43,11 +43,11 @@ function Keyid() {
* @param {String} input Input to read the key id from * @param {String} input Input to read the key id from
*/ */
Keyid.prototype.read = function(bytes) { Keyid.prototype.read = function(bytes) {
this.bytes = bytes.substr(0, 8); this.bytes = util.Uint8Array2str(bytes.subarray(0, 8));
}; };
Keyid.prototype.write = function() { Keyid.prototype.write = function() {
return this.bytes; return util.str2Uint8Array(this.bytes);
}; };
Keyid.prototype.toHex = function() { Keyid.prototype.toHex = function() {

View File

@ -53,7 +53,12 @@ function MPI() {
* @return {Integer} Length of data read * @return {Integer} Length of data read
*/ */
MPI.prototype.read = function (bytes) { MPI.prototype.read = function (bytes) {
var bits = (bytes.charCodeAt(0) << 8) | bytes.charCodeAt(1);
if(typeof bytes === 'string' || String.prototype.isPrototypeOf(bytes)) {
bytes = util.str2Uint8Array(bytes);
}
var bits = (bytes[0] << 8) | bytes[1];
// Additional rules: // Additional rules:
// //
@ -67,7 +72,7 @@ MPI.prototype.read = function (bytes) {
// specified above is not applicable in JavaScript // specified above is not applicable in JavaScript
var bytelen = Math.ceil(bits / 8); var bytelen = Math.ceil(bits / 8);
var raw = bytes.substr(2, bytelen); var raw = util.Uint8Array2str(bytes.subarray(2, 2 + bytelen));
this.fromBytes(raw); this.fromBytes(raw);
return 2 + bytelen; return 2 + bytelen;
@ -78,7 +83,8 @@ MPI.prototype.fromBytes = function (bytes) {
}; };
MPI.prototype.toBytes = function () { MPI.prototype.toBytes = function () {
return this.write().substr(2); var bytes = util.Uint8Array2str(this.write());
return bytes.substr(2);
}; };
MPI.prototype.byteLength = function () { MPI.prototype.byteLength = function () {
@ -86,11 +92,11 @@ MPI.prototype.byteLength = function () {
}; };
/** /**
* Converts the mpi object to a string as specified in {@link http://tools.ietf.org/html/rfc4880#section-3.2|RFC4880 3.2} * Converts the mpi object to a bytes as specified in {@link http://tools.ietf.org/html/rfc4880#section-3.2|RFC4880 3.2}
* @return {String} mpi Byte representation * @return {Uint8Aray} mpi Byte representation
*/ */
MPI.prototype.write = function () { MPI.prototype.write = function () {
return this.data.toMPI(); return util.str2Uint8Array(this.data.toMPI());
}; };
MPI.prototype.toBigInteger = function () { MPI.prototype.toBigInteger = function () {

View File

@ -64,30 +64,30 @@ S2K.prototype.get_count = function () {
*/ */
S2K.prototype.read = function (bytes) { S2K.prototype.read = function (bytes) {
var i = 0; var i = 0;
this.type = enums.read(enums.s2k, bytes.charCodeAt(i++)); this.type = enums.read(enums.s2k, bytes[i++]);
this.algorithm = enums.read(enums.hash, bytes.charCodeAt(i++)); this.algorithm = enums.read(enums.hash, bytes[i++]);
switch (this.type) { switch (this.type) {
case 'simple': case 'simple':
break; break;
case 'salted': case 'salted':
this.salt = bytes.substr(i, 8); this.salt = bytes.subarray(i, i + 8);
i += 8; i += 8;
break; break;
case 'iterated': case 'iterated':
this.salt = bytes.substr(i, 8); this.salt = bytes.subarray(i, i + 8);
i += 8; i += 8;
// Octet 10: count, a one-octet, coded value // Octet 10: count, a one-octet, coded value
this.c = bytes.charCodeAt(i++); this.c = bytes[i++];
break; break;
case 'gnu': case 'gnu':
if (bytes.substr(i, 3) == "GNU") { if (util.Uint8Array2str(bytes.subarray(i, 3)) == "GNU") {
i += 3; // GNU i += 3; // GNU
var gnuExtType = 1000 + bytes.charCodeAt(i++); var gnuExtType = 1000 + bytes[i++];
if (gnuExtType == 1001) { if (gnuExtType == 1001) {
this.type = gnuExtType; this.type = gnuExtType;
// GnuPG extension mode 1001 -- don't write secret key at all // GnuPG extension mode 1001 -- don't write secret key at all
@ -108,22 +108,22 @@ S2K.prototype.read = function (bytes) {
/** /**
* writes an s2k hash based on the inputs. * Serializes s2k information
* @return {String} Produced key of hashAlgorithm hash length * @return {Uint8Array} binary representation of s2k
*/ */
S2K.prototype.write = function () { S2K.prototype.write = function () {
var bytes = String.fromCharCode(enums.write(enums.s2k, this.type));
bytes += String.fromCharCode(enums.write(enums.hash, this.algorithm)); var arr = [new Uint8Array([enums.write(enums.s2k, this.type), enums.write(enums.hash, this.algorithm)])];
switch (this.type) { switch (this.type) {
case 'simple': case 'simple':
break; break;
case 'salted': case 'salted':
bytes += this.salt; arr.push(this.salt);
break; break;
case 'iterated': case 'iterated':
bytes += this.salt; arr.push(this.salt);
bytes += String.fromCharCode(this.c); arr.push(new Uint8Array([this.c]));
break; break;
case 'gnu': case 'gnu':
throw new Error("GNU s2k type not supported."); throw new Error("GNU s2k type not supported.");
@ -131,14 +131,14 @@ S2K.prototype.write = function () {
throw new Error("Unknown s2k type."); throw new Error("Unknown s2k type.");
} }
return bytes; return util.concatUint8Array(arr);
}; };
/** /**
* Produces a key using the specified passphrase and the defined * Produces a key using the specified passphrase and the defined
* hashAlgorithm * hashAlgorithm
* @param {String} passphrase Passphrase containing user input * @param {String} passphrase Passphrase containing user input
* @return {String} Produced key with a length corresponding to * @return {Uint8Array} Produced key with a length corresponding to
* hashAlgorithm hash length * hashAlgorithm hash length
*/ */
S2K.prototype.produce_key = function (passphrase, numBytes) { S2K.prototype.produce_key = function (passphrase, numBytes) {
@ -149,16 +149,16 @@ S2K.prototype.produce_key = function (passphrase, numBytes) {
switch (s2k.type) { switch (s2k.type) {
case 'simple': case 'simple':
return crypto.hash.digest(algorithm, prefix + passphrase); return util.str2Uint8Array(crypto.hash.digest(algorithm, prefix + passphrase));
case 'salted': case 'salted':
return crypto.hash.digest(algorithm, return util.str2Uint8Array(crypto.hash.digest(algorithm,
prefix + s2k.salt + passphrase); prefix + util.Uint8Array2str(s2k.salt) + passphrase));
case 'iterated': case 'iterated':
var isp = [], var isp = [],
count = s2k.get_count(), count = s2k.get_count(),
data = s2k.salt + passphrase; data = util.Uint8Array2str(s2k.salt) + passphrase;
while (isp.length * data.length < count) while (isp.length * data.length < count)
isp.push(data); isp.push(data);
@ -168,7 +168,7 @@ S2K.prototype.produce_key = function (passphrase, numBytes) {
if (isp.length > count) if (isp.length > count)
isp = isp.substr(0, count); isp = isp.substr(0, count);
return crypto.hash.digest(algorithm, prefix + isp); return util.str2Uint8Array(crypto.hash.digest(algorithm, prefix + isp));
case 'gnu': case 'gnu':
throw new Error("GNU s2k type not supported."); throw new Error("GNU s2k type not supported.");
@ -178,15 +178,18 @@ S2K.prototype.produce_key = function (passphrase, numBytes) {
} }
} }
var result = '', var arr = [],
rlength = 0,
prefix = ''; prefix = '';
while (result.length <= numBytes) { while (rlength <= numBytes) {
result += round(prefix, this); var result = round(prefix, this);
arr.push(result);
rlength += result.length;
prefix += String.fromCharCode(0); prefix += String.fromCharCode(0);
} }
return result.substr(0, numBytes); return util.concatUint8Array(arr).subarray(0, numBytes);
}; };
module.exports.fromClone = function (clone) { module.exports.fromClone = function (clone) {

View File

@ -31,16 +31,16 @@ module.exports = {
for (var i = 0; i < bytes.length; i++) { for (var i = 0; i < bytes.length; i++) {
n <<= 8; n <<= 8;
n += bytes.charCodeAt(i); n += bytes[i];
} }
return n; return n;
}, },
writeNumber: function (n, bytes) { writeNumber: function (n, bytes) {
var b = ''; var b = new Uint8Array(bytes);
for (var i = 0; i < bytes; i++) { for (var i = 0; i < bytes; i++) {
b += String.fromCharCode((n >> (8 * (bytes - i - 1))) & 0xFF); b[i] = (n >> (8 * (bytes - i - 1))) & 0xFF;
} }
return b; return b;
@ -187,6 +187,12 @@ module.exports = {
* @return {Uint8Array} The array of (binary) integers * @return {Uint8Array} The array of (binary) integers
*/ */
str2Uint8Array: function (str) { str2Uint8Array: function (str) {
// Uncomment for debugging
if(!(typeof str === 'string') && !String.prototype.isPrototypeOf(str)) {
throw new Error('Data must be in the form of a string');
}
var result = new Uint8Array(str.length); var result = new Uint8Array(str.length);
for (var i = 0; i < str.length; i++) { for (var i = 0; i < str.length; i++) {
result[i] = str.charCodeAt(i); result[i] = str.charCodeAt(i);
@ -202,6 +208,12 @@ module.exports = {
* @return {String} String representation of the array * @return {String} String representation of the array
*/ */
Uint8Array2str: function (bin) { Uint8Array2str: function (bin) {
// Uncomment for debugging
if(!Uint8Array.prototype.isPrototypeOf(bin)) {
throw new Error('Data must be in the form of a Uint8Array');
}
var result = []; var result = [];
for (var i = 0; i < bin.length; i++) { for (var i = 0; i < bin.length; i++) {
result[i] = String.fromCharCode(bin[i]); result[i] = String.fromCharCode(bin[i]);
@ -210,9 +222,82 @@ module.exports = {
}, },
/** /**
* Calculates a 16bit sum of a string by adding each character * Concat Uint8arrays
* @function module:util.concatUint8Array
* @param {Array<Uint8array>} Array of Uint8Arrays to concatenate
* @return {Uint8array} Concatenated array
*/
concatUint8Array: function (arrays) {
var totalLength = 0;
arrays.forEach(function (element) {
// Uncomment for debugging
if(!Uint8Array.prototype.isPrototypeOf(element)) {
throw new Error('Data must be in the form of a Uint8Array');
}
totalLength += element.length;
});
var result = new Uint8Array(totalLength);
var pos = 0;
arrays.forEach(function (element) {
result.set(element,pos);
pos += element.length;
});
return result;
},
/**
* Deep copy Uint8Array
* @function module:util.copyUint8Array
* @param {Uint8Array} Array to copy
* @return {Uint8Array} new Uint8Array
*/
copyUint8Array: function (array) {
// Uncomment for debugging
if(!Uint8Array.prototype.isPrototypeOf(array)) {
throw new Error('Data must be in the form of a Uint8Array');
}
var copy = new Uint8Array(array.length);
copy.set(array);
return copy;
},
/**
* Check Uint8Array equality
* @function module:util.equalsUint8Array
* @param {Uint8Array} first array
* @param {Uint8Array} second array
* @return {Boolean} equality
*/
equalsUint8Array: function (array1, array2) {
// Uncomment for debugging
if(!Uint8Array.prototype.isPrototypeOf(array1) || !Uint8Array.prototype.isPrototypeOf(array2)) {
throw new Error('Data must be in the form of a Uint8Array');
}
if(array1.length !== array2.length) {
return false;
}
for(var i = 0; i < array1.length; i++) {
if(array1[i] !== array2[i]) {
return false;
}
}
return true;
},
/**
* Calculates a 16bit sum of a Uint8Array by adding each character
* codes modulus 65535 * codes modulus 65535
* @param {String} text String to create a sum of * @param {Uint8Array} Uint8Array to create a sum of
* @return {Integer} An integer containing the sum of all character * @return {Integer} An integer containing the sum of all character
* codes % 65535 * codes % 65535
*/ */
@ -224,7 +309,7 @@ module.exports = {
} }
}; };
for (var i = 0; i < text.length; i++) { for (var i = 0; i < text.length; i++) {
checksum.add(text.charCodeAt(i)); checksum.add(text[i]);
} }
return checksum.s; return checksum.s;
}, },

View File

@ -132,7 +132,7 @@ AsyncProxy.prototype.terminate = function() {
/** /**
* Encrypts message text/data with keys or passwords * Encrypts message text/data with keys or passwords
* @param {(Array<module:key~Key>|module:key~Key)} keys array of keys or single key, used to encrypt the message * @param {(Array<module:key~Key>|module:key~Key)} keys array of keys or single key, used to encrypt the message
* @param {String} data text/data message as native JavaScript string/binary string * @param {Uint8Array} data message as Uint8Array
* @param {(Array<String>|String)} passwords passwords for the message * @param {(Array<String>|String)} passwords passwords for the message
* @param {Object} params parameter object with optional properties binary {Boolean}, * @param {Object} params parameter object with optional properties binary {Boolean},
* filename {String}, and packets {Boolean} * filename {String}, and packets {Boolean}
@ -161,7 +161,7 @@ AsyncProxy.prototype.encryptMessage = function(keys, data, passwords, params) {
/** /**
* Encrypts session key with keys or passwords * Encrypts session key with keys or passwords
* @param {String} sessionKey sessionKey as a binary string * @param {Uint8Array} sessionKey sessionKey as Uint8Array
* @param {String} algo algorithm of sessionKey * @param {String} algo algorithm of sessionKey
* @param {(Array<module:key~Key>|module:key~Key)} keys array of keys or single key, used to encrypt the key * @param {(Array<module:key~Key>|module:key~Key)} keys array of keys or single key, used to encrypt the key
* @param {(Array<String>|String)} passwords passwords for the message * @param {(Array<String>|String)} passwords passwords for the message
@ -192,7 +192,7 @@ AsyncProxy.prototype.encryptSessionKey = function(sessionKey, algo, keys, passwo
* Signs message text and encrypts it * Signs message text and encrypts it
* @param {(Array<module:key~Key>|module:key~Key)} publicKeys array of keys or single key, used to encrypt the message * @param {(Array<module:key~Key>|module:key~Key)} publicKeys array of keys or single key, used to encrypt the message
* @param {module:key~Key} privateKey private key with decrypted secret key data for signing * @param {module:key~Key} privateKey private key with decrypted secret key data for signing
* @param {String} text message as native JavaScript string * @param {Uint8Array} text message as Uint8Array
*/ */
AsyncProxy.prototype.signAndEncryptMessage = function(publicKeys, privateKey, text) { AsyncProxy.prototype.signAndEncryptMessage = function(publicKeys, privateKey, text) {
var self = this; var self = this;
@ -299,7 +299,7 @@ AsyncProxy.prototype.decryptAndVerifyMessage = function(privateKey, publicKeys,
/** /**
* Signs a cleartext message * Signs a cleartext message
* @param {(Array<module:key~Key>|module:key~Key)} privateKeys array of keys or single key, with decrypted secret key data to sign cleartext * @param {(Array<module:key~Key>|module:key~Key)} privateKeys array of keys or single key, with decrypted secret key data to sign cleartext
* @param {String} text cleartext * @param {Uint8Array} text cleartext
*/ */
AsyncProxy.prototype.signClearMessage = function(privateKeys, text) { AsyncProxy.prototype.signClearMessage = function(privateKeys, text) {
var self = this; var self = this;

View File

@ -8,7 +8,7 @@ var util = openpgp.util,
describe('AES Rijndael cipher test with test vectors from ecb_tbl.txt', function() { describe('AES Rijndael cipher test with test vectors from ecb_tbl.txt', function() {
function test_aes(input, key, output) { function test_aes(input, key, output) {
var aes = new openpgp.crypto.cipher.aes128(util.bin2str(key)); var aes = new openpgp.crypto.cipher.aes128(key);
var result = util.bin2str(aes.encrypt(new Uint8Array(input))); var result = util.bin2str(aes.encrypt(new Uint8Array(input)));

View File

@ -8,7 +8,7 @@ var util = openpgp.util,
it('CAST-128 cipher test with test vectors from RFC2144', function (done) { it('CAST-128 cipher test with test vectors from RFC2144', function (done) {
function test_cast(input, key, output) { function test_cast(input, key, output) {
var cast5 = new openpgp.crypto.cipher.cast5(util.bin2str(key)); var cast5 = new openpgp.crypto.cipher.cast5(key);
var result = util.bin2str(cast5.encrypt(input)); var result = util.bin2str(cast5.encrypt(input));
return util.hexstrdump(result) == util.hexstrdump(util.bin2str(output)); return util.hexstrdump(result) == util.hexstrdump(util.bin2str(output));

View File

@ -7,7 +7,7 @@ var util = openpgp.util,
expect = chai.expect; expect = chai.expect;
describe('TripleDES (EDE) cipher test with test vectors from http://csrc.nist.gov/publications/nistpubs/800-20/800-20.pdf', function() { describe('TripleDES (EDE) cipher test with test vectors from http://csrc.nist.gov/publications/nistpubs/800-20/800-20.pdf', function() {
var key = util.bin2str([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]); var key = new Uint8Array([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]);
var testvectors = [[[0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x95,0xF8,0xA5,0xE5,0xDD,0x31,0xD9,0x00]], var testvectors = [[[0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x95,0xF8,0xA5,0xE5,0xDD,0x31,0xD9,0x00]],
[[0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0xDD,0x7F,0x12,0x1C,0xA5,0x01,0x56,0x19]], [[0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0xDD,0x7F,0x12,0x1C,0xA5,0x01,0x56,0x19]],
[[0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x2E,0x86,0x53,0x10,0x4F,0x38,0x34,0xEA]], [[0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x2E,0x86,0x53,0x10,0x4F,0x38,0x34,0xEA]],
@ -80,7 +80,7 @@ describe('TripleDES (EDE) cipher test with test vectors from http://csrc.nist.go
var encr = util.bin2str(des.encrypt(testvectors[i][0], key)); var encr = util.bin2str(des.encrypt(testvectors[i][0], key));
expect(encr, 'vector with block ' + util.hexidump(testvectors[i][0]) + expect(encr, 'vector with block ' + util.hexidump(testvectors[i][0]) +
' and key ' + util.hexstrdump(key) + ' and key ' + util.hexstrdump(util.Uint8Array2str(key)) +
' should be ' + util.hexidump(testvectors[i][1]) + ' should be ' + util.hexidump(testvectors[i][1]) +
' != ' + util.hexidump(encr)).to.be.equal(util.bin2str(testvectors[i][1])); ' != ' + util.hexidump(encr)).to.be.equal(util.bin2str(testvectors[i][1]));
} }
@ -88,7 +88,7 @@ describe('TripleDES (EDE) cipher test with test vectors from http://csrc.nist.go
}); });
it('DES encrypt/decrypt padding tests', function (done) { it('DES encrypt/decrypt padding tests', function (done) {
var key = util.bin2str([0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF]); var key = new Uint8Array([0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF]);
var testvectors = new Array(); var testvectors = new Array();
testvectors[0] = [[[0x01], [0x24, 0xC7, 0x4A, 0x9A, 0x79, 0x75, 0x4B, 0xC7]], testvectors[0] = [[[0x01], [0x24, 0xC7, 0x4A, 0x9A, 0x79, 0x75, 0x4B, 0xC7]],
[[0x02, 0x03], [0xA7, 0x7A, 0x9A, 0x59, 0x8A, 0x86, 0x85, 0xC5]], [[0x02, 0x03], [0xA7, 0x7A, 0x9A, 0x59, 0x8A, 0x86, 0x85, 0xC5]],
@ -125,13 +125,13 @@ describe('TripleDES (EDE) cipher test with test vectors from http://csrc.nist.go
var decrypted = des.decrypt(encrypted, padding); var decrypted = des.decrypt(encrypted, padding);
expect(util.bin2str(encrypted), 'vector with block [' + util.hexidump(thisVectorSet[i][0]) + expect(util.bin2str(encrypted), 'vector with block [' + util.hexidump(thisVectorSet[i][0]) +
'] and key [' + util.hexstrdump(key) + '] and key [' + util.hexstrdump(util.Uint8Array2str(key)) +
'] and padding [' + padding + '] and padding [' + padding +
'] should be ' + util.hexidump(thisVectorSet[i][1]) + '] should be ' + util.hexidump(thisVectorSet[i][1]) +
' - Actually [' + util.hexidump(encrypted) + ' - Actually [' + util.hexidump(encrypted) +
']').to.equal(util.bin2str(thisVectorSet[i][1])); ']').to.equal(util.bin2str(thisVectorSet[i][1]));
expect(util.bin2str(decrypted), 'vector with block [' + util.hexidump(thisVectorSet[i][0]) + expect(util.bin2str(decrypted), 'vector with block [' + util.hexidump(thisVectorSet[i][0]) +
'] and key [' + util.hexstrdump(key) + '] and key [' + util.hexstrdump(util.Uint8Array2str(key)) +
'] and padding [' + padding + '] and padding [' + padding +
'] should be ' + util.hexidump(thisVectorSet[i][0]) + '] should be ' + util.hexidump(thisVectorSet[i][0]) +
' - Actually [' + util.hexidump(decrypted) + ' - Actually [' + util.hexidump(decrypted) +

View File

@ -8,7 +8,7 @@ var util = openpgp.util,
it('Twofish with test vectors from http://www.schneier.com/code/ecb_ival.txt', function(done) { it('Twofish with test vectors from http://www.schneier.com/code/ecb_ival.txt', function(done) {
function TFencrypt(block, key) { function TFencrypt(block, key) {
var tf = new openpgp.crypto.cipher.twofish(key); var tf = new openpgp.crypto.cipher.twofish(util.str2Uint8Array(key));
return tf.encrypt(block); return tf.encrypt(block);
} }

View File

@ -8,7 +8,7 @@ var chai = require('chai'),
describe('API functional testing', function() { describe('API functional testing', function() {
var util = openpgp.util; var util = openpgp.util;
var RSApubMPIstrs = [ var RSApubMPIstrs = [
util.bin2str([0x08,0x00,0xac,0x15,0xb3,0xd6,0xd2,0x0f,0xf0,0x7a,0xdd,0x21,0xb7, new Uint8Array([0x08,0x00,0xac,0x15,0xb3,0xd6,0xd2,0x0f,0xf0,0x7a,0xdd,0x21,0xb7,
0xbf,0x61,0xfa,0xca,0x93,0x86,0xc8,0x55,0x5a,0x4b,0xa6,0xa4,0x1a, 0xbf,0x61,0xfa,0xca,0x93,0x86,0xc8,0x55,0x5a,0x4b,0xa6,0xa4,0x1a,
0x60,0xa2,0x3a,0x37,0x06,0x08,0xd8,0x15,0x8e,0x85,0x45,0xaa,0xb7, 0x60,0xa2,0x3a,0x37,0x06,0x08,0xd8,0x15,0x8e,0x85,0x45,0xaa,0xb7,
0x1d,0x7b,0x0b,0x73,0x94,0x55,0x0c,0x5c,0xec,0xc0,0x22,0x4b,0xa1, 0x1d,0x7b,0x0b,0x73,0x94,0x55,0x0c,0x5c,0xec,0xc0,0x22,0x4b,0xa1,
@ -28,9 +28,9 @@ describe('API functional testing', function() {
0x29,0xc1,0xf3,0xa9,0x0b,0xfc,0x31,0x75,0x58,0x74,0x2a,0x88,0xaf, 0x29,0xc1,0xf3,0xa9,0x0b,0xfc,0x31,0x75,0x58,0x74,0x2a,0x88,0xaf,
0xee,0xc9,0xa4,0xcd,0x15,0xdc,0x1b,0x8d,0x64,0xc1,0x36,0x17,0xc4, 0xee,0xc9,0xa4,0xcd,0x15,0xdc,0x1b,0x8d,0x64,0xc1,0x36,0x17,0xc4,
0x8d,0x5e,0x99,0x7a,0x5b,0x9f,0x39,0xd0,0x00,0x6e,0xf9]), 0x8d,0x5e,0x99,0x7a,0x5b,0x9f,0x39,0xd0,0x00,0x6e,0xf9]),
util.bin2str([0x00,0x11,0x01,0x00,0x01])]; new Uint8Array([0x00,0x11,0x01,0x00,0x01])];
var RSAsecMPIstrs = [ var RSAsecMPIstrs = [
util.bin2str([0x07,0xfe,0x23,0xff,0xce,0x45,0x6c,0x60,0x65,0x40,0x6e,0xae,0x35, new Uint8Array([0x07,0xfe,0x23,0xff,0xce,0x45,0x6c,0x60,0x65,0x40,0x6e,0xae,0x35,
0x10,0x56,0x60,0xee,0xab,0xfa,0x10,0x42,0xba,0xc7,0x04,0xaf,0x63, 0x10,0x56,0x60,0xee,0xab,0xfa,0x10,0x42,0xba,0xc7,0x04,0xaf,0x63,
0xcd,0x3f,0x62,0xca,0x4b,0xfa,0xe1,0xa9,0x70,0xcd,0x34,0x8b,0xc8, 0xcd,0x3f,0x62,0xca,0x4b,0xfa,0xe1,0xa9,0x70,0xcd,0x34,0x8b,0xc8,
0x0e,0xe4,0xc4,0xba,0x83,0x17,0x5f,0xa4,0xb8,0xea,0x60,0xc2,0x4d, 0x0e,0xe4,0xc4,0xba,0x83,0x17,0x5f,0xa4,0xb8,0xea,0x60,0xc2,0x4d,
@ -50,7 +50,7 @@ describe('API functional testing', function() {
0xf2,0xad,0xda,0xc2,0xc7,0x39,0x78,0x99,0xde,0x57,0x14,0x45,0x7f, 0xf2,0xad,0xda,0xc2,0xc7,0x39,0x78,0x99,0xde,0x57,0x14,0x45,0x7f,
0x32,0x38,0xa3,0x44,0x0f,0xe7,0x39,0x4c,0x6f,0x0f,0x32,0x7e,0xf1, 0x32,0x38,0xa3,0x44,0x0f,0xe7,0x39,0x4c,0x6f,0x0f,0x32,0x7e,0xf1,
0x5c,0x84,0x97,0xdd,0xa0,0x0c,0x87,0x66,0x7d,0x75,0x79]), 0x5c,0x84,0x97,0xdd,0xa0,0x0c,0x87,0x66,0x7d,0x75,0x79]),
util.bin2str([0x04,0x00,0xc2,0xbc,0x71,0xf7,0x41,0x4a,0x09,0x66,0x70,0x02,0x68, new Uint8Array([0x04,0x00,0xc2,0xbc,0x71,0xf7,0x41,0x4a,0x09,0x66,0x70,0x02,0x68,
0x8b,0xeb,0xe2,0x34,0xd1,0x12,0x83,0x93,0x75,0xe9,0x71,0x32,0xe2, 0x8b,0xeb,0xe2,0x34,0xd1,0x12,0x83,0x93,0x75,0xe9,0x71,0x32,0xe2,
0xed,0x18,0x6f,0x8e,0x3a,0xff,0x22,0x70,0x28,0x01,0xbf,0x4a,0x39, 0xed,0x18,0x6f,0x8e,0x3a,0xff,0x22,0x70,0x28,0x01,0xbf,0x4a,0x39,
0x41,0xbb,0x3c,0x4a,0xbc,0xb8,0x13,0xfc,0x14,0xf6,0x71,0xa1,0x44, 0x41,0xbb,0x3c,0x4a,0xbc,0xb8,0x13,0xfc,0x14,0xf6,0x71,0xa1,0x44,
@ -60,7 +60,7 @@ describe('API functional testing', function() {
0x01,0x24,0xec,0x7d,0xca,0xf6,0xa2,0xb3,0xbb,0xad,0x2e,0x60,0xfb, 0x01,0x24,0xec,0x7d,0xca,0xf6,0xa2,0xb3,0xbb,0xad,0x2e,0x60,0xfb,
0x1c,0xee,0x49,0xd0,0x4e,0x5c,0xe3,0x1f,0x88,0x48,0xe4,0x68,0x14, 0x1c,0xee,0x49,0xd0,0x4e,0x5c,0xe3,0x1f,0x88,0x48,0xe4,0x68,0x14,
0x3d,0x71,0xba,0xd7,0x4d,0x35,0x10,0x86,0x37,0x62,0xe0,0xa5,0x0b]), 0x3d,0x71,0xba,0xd7,0x4d,0x35,0x10,0x86,0x37,0x62,0xe0,0xa5,0x0b]),
util.bin2str([0x04,0x00,0xe2,0x38,0xf9,0xc8,0x3c,0xd1,0xcf,0x62,0x93,0xc3,0x77, new Uint8Array([0x04,0x00,0xe2,0x38,0xf9,0xc8,0x3c,0xd1,0xcf,0x62,0x93,0xc3,0x77,
0x76,0x97,0x44,0xe8,0xc8,0xca,0x93,0x9a,0xef,0xf0,0x63,0x76,0x25, 0x76,0x97,0x44,0xe8,0xc8,0xca,0x93,0x9a,0xef,0xf0,0x63,0x76,0x25,
0x3b,0x1c,0x46,0xff,0x90,0x13,0x91,0x15,0x97,0x7e,0x88,0x95,0xd4, 0x3b,0x1c,0x46,0xff,0x90,0x13,0x91,0x15,0x97,0x7e,0x88,0x95,0xd4,
0x7f,0x2f,0x52,0x6e,0x0d,0x55,0x55,0x2e,0xf1,0x58,0x5c,0x7e,0x56, 0x7f,0x2f,0x52,0x6e,0x0d,0x55,0x55,0x2e,0xf1,0x58,0x5c,0x7e,0x56,
@ -70,7 +70,7 @@ describe('API functional testing', function() {
0x4a,0x47,0x2f,0xe1,0xba,0x5e,0x32,0xd4,0x52,0x04,0x88,0x9d,0x63, 0x4a,0x47,0x2f,0xe1,0xba,0x5e,0x32,0xd4,0x52,0x04,0x88,0x9d,0x63,
0x3e,0xba,0x71,0x2d,0xf7,0x61,0xd5,0xfc,0x26,0xbf,0xd8,0x60,0x92, 0x3e,0xba,0x71,0x2d,0xf7,0x61,0xd5,0xfc,0x26,0xbf,0xd8,0x60,0x92,
0x7b,0x94,0xf8,0x6f,0x3d,0x97,0x0b,0x0c,0x52,0x8c,0xb3,0xb6,0x8b]), 0x7b,0x94,0xf8,0x6f,0x3d,0x97,0x0b,0x0c,0x52,0x8c,0xb3,0xb6,0x8b]),
util.bin2str([0x04,0x00,0xb7,0xc5,0x4d,0x6e,0x2f,0xdd,0xef,0xec,0x07,0x70,0xa2, new Uint8Array([0x04,0x00,0xb7,0xc5,0x4d,0x6e,0x2f,0xdd,0xef,0xec,0x07,0x70,0xa2,
0x7c,0x1c,0x9d,0x8e,0x66,0x60,0x7c,0x61,0x1e,0x45,0xe9,0xdc,0x82, 0x7c,0x1c,0x9d,0x8e,0x66,0x60,0x7c,0x61,0x1e,0x45,0xe9,0xdc,0x82,
0x2f,0xc5,0x7e,0x1a,0xc6,0xd0,0x92,0xc5,0x22,0x9b,0x9a,0xfb,0x73, 0x2f,0xc5,0x7e,0x1a,0xc6,0xd0,0x92,0xc5,0x22,0x9b,0x9a,0xfb,0x73,
0x95,0x99,0xf2,0x7c,0xdb,0x2a,0x93,0x7b,0x5a,0x29,0x73,0x24,0x16, 0x95,0x99,0xf2,0x7c,0xdb,0x2a,0x93,0x7b,0x5a,0x29,0x73,0x24,0x16,
@ -82,7 +82,7 @@ describe('API functional testing', function() {
0xe7,0xd6,0x76,0xea,0x0e,0x1a,0x90,0x30,0xf5,0x98,0x01,0xc5,0x73])]; 0xe7,0xd6,0x76,0xea,0x0e,0x1a,0x90,0x30,0xf5,0x98,0x01,0xc5,0x73])];
var DSApubMPIstrs = [ var DSApubMPIstrs = [
util.bin2str([0x08,0x00,0xa8,0x85,0x5c,0x28,0x05,0x94,0x03,0xbe,0x07,0x6c,0x13,0x3e,0x65, new Uint8Array([0x08,0x00,0xa8,0x85,0x5c,0x28,0x05,0x94,0x03,0xbe,0x07,0x6c,0x13,0x3e,0x65,
0xfb,0xb5,0xe1,0x99,0x7c,0xfa,0x84,0xe3,0xac,0x47,0xa5,0xc4,0x46,0xd8,0x5f, 0xfb,0xb5,0xe1,0x99,0x7c,0xfa,0x84,0xe3,0xac,0x47,0xa5,0xc4,0x46,0xd8,0x5f,
0x44,0xe9,0xc1,0x6b,0x69,0xf7,0x10,0x76,0x49,0xa7,0x25,0x85,0xf4,0x1b,0xed, 0x44,0xe9,0xc1,0x6b,0x69,0xf7,0x10,0x76,0x49,0xa7,0x25,0x85,0xf4,0x1b,0xed,
0xc6,0x60,0xc4,0x5b,0xaa,0xd4,0x87,0xd6,0x8f,0x92,0x56,0x7d,0x55,0x3f,0x45, 0xc6,0x60,0xc4,0x5b,0xaa,0xd4,0x87,0xd6,0x8f,0x92,0x56,0x7d,0x55,0x3f,0x45,
@ -100,10 +100,10 @@ describe('API functional testing', function() {
0x11,0xf1,0xcb,0x1a,0xb6,0x4e,0x05,0x54,0xf7,0xe9,0xbe,0x4c,0x25,0x59,0x08, 0x11,0xf1,0xcb,0x1a,0xb6,0x4e,0x05,0x54,0xf7,0xe9,0xbe,0x4c,0x25,0x59,0x08,
0x9f,0xf8,0xea,0x25,0x97,0x33,0xd6,0xc9,0x0f,0x59,0x0e,0xfd,0x9f,0xdc,0xe2, 0x9f,0xf8,0xea,0x25,0x97,0x33,0xd6,0xc9,0x0f,0x59,0x0e,0xfd,0x9f,0xdc,0xe2,
0xc0,0xcf,0x2f]), 0xc0,0xcf,0x2f]),
util.bin2str([0x01,0x00,0xe1,0x72,0x2c,0xd0,0xbb,0x1a,0x4f,0xb6,0xb6,0x95,0x77,0x71,0x2e, new Uint8Array([0x01,0x00,0xe1,0x72,0x2c,0xd0,0xbb,0x1a,0x4f,0xb6,0xb6,0x95,0x77,0x71,0x2e,
0x01,0x48,0x3e,0x35,0x54,0x64,0x2b,0xed,0x40,0x5f,0x65,0x0c,0x57,0x28,0x5f, 0x01,0x48,0x3e,0x35,0x54,0x64,0x2b,0xed,0x40,0x5f,0x65,0x0c,0x57,0x28,0x5f,
0xfd,0xfd,0xff,0xd7]), 0xfd,0xfd,0xff,0xd7]),
util.bin2str([0x07,0xff,0x5d,0x9f,0xc4,0xb5,0x63,0x25,0x9d,0x72,0x88,0xe5,0x53,0x46,0x98, new Uint8Array([0x07,0xff,0x5d,0x9f,0xc4,0xb5,0x63,0x25,0x9d,0x72,0x88,0xe5,0x53,0x46,0x98,
0xe3,0xe9,0x62,0xcb,0x0c,0xa1,0xb7,0x75,0x9f,0x18,0x41,0x94,0x32,0x28,0x29, 0xe3,0xe9,0x62,0xcb,0x0c,0xa1,0xb7,0x75,0x9f,0x18,0x41,0x94,0x32,0x28,0x29,
0x6d,0x69,0xe0,0x3f,0x7d,0x7b,0x2b,0x06,0x5a,0x33,0x5c,0xd4,0x36,0x31,0x09, 0x6d,0x69,0xe0,0x3f,0x7d,0x7b,0x2b,0x06,0x5a,0x33,0x5c,0xd4,0x36,0x31,0x09,
0x54,0x85,0x9d,0xb8,0x20,0xfe,0xda,0xfc,0xcd,0x1f,0xb1,0x2c,0x15,0x08,0x9d, 0x54,0x85,0x9d,0xb8,0x20,0xfe,0xda,0xfc,0xcd,0x1f,0xb1,0x2c,0x15,0x08,0x9d,
@ -121,7 +121,7 @@ describe('API functional testing', function() {
0x67,0x69,0xd1,0xfc,0x97,0x4d,0xa2,0xce,0xad,0xbb,0x6f,0xab,0xa5,0xd6,0x18, 0x67,0x69,0xd1,0xfc,0x97,0x4d,0xa2,0xce,0xad,0xbb,0x6f,0xab,0xa5,0xd6,0x18,
0xb3,0x1a,0x96,0x02,0xbc,0x31,0x42,0xa2,0xad,0x77,0xe8,0xe2,0x4c,0x99,0xf9, 0xb3,0x1a,0x96,0x02,0xbc,0x31,0x42,0xa2,0xad,0x77,0xe8,0xe2,0x4c,0x99,0xf9,
0xdd,0xbe,0xcd]), 0xdd,0xbe,0xcd]),
util.bin2str([0x07,0xff,0x5d,0xfe,0x9c,0x98,0xef,0x3a,0xa6,0x49,0xf0,0x10,0x67,0x79,0x2a, new Uint8Array([0x07,0xff,0x5d,0xfe,0x9c,0x98,0xef,0x3a,0xa6,0x49,0xf0,0x10,0x67,0x79,0x2a,
0x9d,0x79,0x43,0x06,0xa4,0xa8,0x6b,0x1a,0x6d,0x1f,0x77,0x6e,0x00,0x31,0xb9, 0x9d,0x79,0x43,0x06,0xa4,0xa8,0x6b,0x1a,0x6d,0x1f,0x77,0x6e,0x00,0x31,0xb9,
0xed,0xc9,0x66,0xff,0xf1,0x21,0x32,0xfa,0x62,0x43,0xcd,0x97,0xd3,0x3d,0xaf, 0xed,0xc9,0x66,0xff,0xf1,0x21,0x32,0xfa,0x62,0x43,0xcd,0x97,0xd3,0x3d,0xaf,
0xb4,0x29,0x29,0x26,0x4e,0x1c,0xa0,0xad,0x1c,0x07,0x28,0x3f,0xe5,0x43,0x10, 0xb4,0x29,0x29,0x26,0x4e,0x1c,0xa0,0xad,0x1c,0x07,0x28,0x3f,0xe5,0x43,0x10,
@ -140,12 +140,12 @@ describe('API functional testing', function() {
0xc3,0x26,0xae,0x9f,0xa9,0x67,0x49,0x96,0x5c,0x07,0x3e,0x47,0x5c,0xed,0x60, 0xc3,0x26,0xae,0x9f,0xa9,0x67,0x49,0x96,0x5c,0x07,0x3e,0x47,0x5c,0xed,0x60,
0x07,0xac,0x6a])]; 0x07,0xac,0x6a])];
var DSAsecMPIstrs = [ var DSAsecMPIstrs = [
util.bin2str([0x01,0x00,0x9b,0x58,0xa8,0xf4,0x04,0xb1,0xd5,0x14,0x09,0xe1,0xe1,0xa1,0x8a, new Uint8Array([0x01,0x00,0x9b,0x58,0xa8,0xf4,0x04,0xb1,0xd5,0x14,0x09,0xe1,0xe1,0xa1,0x8a,
0x0b,0xa3,0xc3,0xa3,0x66,0xaa,0x27,0x99,0x50,0x1c,0x4d,0xba,0x24,0xee,0xdf, 0x0b,0xa3,0xc3,0xa3,0x66,0xaa,0x27,0x99,0x50,0x1c,0x4d,0xba,0x24,0xee,0xdf,
0xdf,0xb8,0x8e,0x8e])]; 0xdf,0xb8,0x8e,0x8e])];
var ElgamalpubMPIstrs = [ var ElgamalpubMPIstrs = [
util.bin2str([0x08,0x00,0xea,0xcc,0xbe,0xe2,0xe4,0x5a,0x51,0x18,0x93,0xa1,0x12,0x2f,0x00, new Uint8Array([0x08,0x00,0xea,0xcc,0xbe,0xe2,0xe4,0x5a,0x51,0x18,0x93,0xa1,0x12,0x2f,0x00,
0x99,0x42,0xd8,0x5c,0x1c,0x2f,0xb6,0x3c,0xd9,0x94,0x61,0xb4,0x55,0x8d,0x4e, 0x99,0x42,0xd8,0x5c,0x1c,0x2f,0xb6,0x3c,0xd9,0x94,0x61,0xb4,0x55,0x8d,0x4e,
0x73,0xe6,0x69,0xbc,0x1d,0x33,0xe3,0x2d,0x91,0x23,0x69,0x95,0x98,0xd7,0x18, 0x73,0xe6,0x69,0xbc,0x1d,0x33,0xe3,0x2d,0x91,0x23,0x69,0x95,0x98,0xd7,0x18,
0x5a,0xaf,0xa7,0x93,0xc6,0x05,0x93,0x3a,0xc7,0xea,0xd0,0xb1,0xa9,0xc7,0xab, 0x5a,0xaf,0xa7,0x93,0xc6,0x05,0x93,0x3a,0xc7,0xea,0xd0,0xb1,0xa9,0xc7,0xab,
@ -163,8 +163,8 @@ describe('API functional testing', function() {
0x6e,0x03,0xd9,0x41,0xdd,0x2d,0x1a,0xdd,0x07,0x74,0x8b,0xb7,0xa2,0xfa,0xb2, 0x6e,0x03,0xd9,0x41,0xdd,0x2d,0x1a,0xdd,0x07,0x74,0x8b,0xb7,0xa2,0xfa,0xb2,
0x59,0x0e,0x0e,0x94,0x7c,0x00,0xad,0x95,0x23,0x42,0x91,0x18,0x4c,0x97,0xf1, 0x59,0x0e,0x0e,0x94,0x7c,0x00,0xad,0x95,0x23,0x42,0x91,0x18,0x4c,0x97,0xf1,
0x27,0x62,0x77]), 0x27,0x62,0x77]),
util.bin2str([0x00,0x03,0x05]), new Uint8Array([0x00,0x03,0x05]),
util.bin2str([0x07,0xff,0x57,0x19,0x76,0xfc,0x09,0x6a,0x7a,0xf7,0xba,0xb2,0x42,0xbf,0xcd, new Uint8Array([0x07,0xff,0x57,0x19,0x76,0xfc,0x09,0x6a,0x7a,0xf7,0xba,0xb2,0x42,0xbf,0xcd,
0x2b,0xc1,0x1a,0x79,0x25,0x8c,0xad,0xf4,0x3a,0x0a,0x7a,0x9b,0x4c,0x46,0x3c, 0x2b,0xc1,0x1a,0x79,0x25,0x8c,0xad,0xf4,0x3a,0x0a,0x7a,0x9b,0x4c,0x46,0x3c,
0xe0,0x4f,0xcc,0x6e,0xe5,0x7a,0x33,0x3a,0x4e,0x80,0xcb,0xd3,0x62,0xd7,0x8f, 0xe0,0x4f,0xcc,0x6e,0xe5,0x7a,0x33,0x3a,0x4e,0x80,0xcb,0xd3,0x62,0xd7,0x8f,
0xe2,0xc8,0xb0,0xd0,0xcb,0x49,0xc9,0x9e,0x2d,0x97,0x16,0x3a,0x7d,0xb1,0xe1, 0xe2,0xc8,0xb0,0xd0,0xcb,0x49,0xc9,0x9e,0x2d,0x97,0x16,0x3a,0x7d,0xb1,0xe1,
@ -184,7 +184,7 @@ describe('API functional testing', function() {
0xda,0x6b,0xca])]; 0xda,0x6b,0xca])];
var ElgamalsecMPIstrs = [ var ElgamalsecMPIstrs = [
util.bin2str([0x01,0x52,0x02,0x80,0x87,0xf6,0xe4,0x49,0xd7,0x2e,0x3e,0xfe,0x60,0xb9,0xa3, new Uint8Array([0x01,0x52,0x02,0x80,0x87,0xf6,0xe4,0x49,0xd7,0x2e,0x3e,0xfe,0x60,0xb9,0xa3,
0x2a,0xf0,0x67,0x58,0xe9,0xf6,0x47,0x83,0xde,0x7e,0xfb,0xbb,0xbd,0xdf,0x48, 0x2a,0xf0,0x67,0x58,0xe9,0xf6,0x47,0x83,0xde,0x7e,0xfb,0xbb,0xbd,0xdf,0x48,
0x12,0x1b,0x06,0x7d,0x13,0xbc,0x3b,0x49,0xf9,0x86,0xd4,0x53,0xed,0x2d,0x68])]; 0x12,0x1b,0x06,0x7d,0x13,0xbc,0x3b,0x49,0xf9,0x86,0xd4,0x53,0xed,0x2d,0x68])];
@ -224,28 +224,30 @@ describe('API functional testing', function() {
ElgamalpubMPIs[i].read(ElgamalpubMPIstrs[i]); ElgamalpubMPIs[i].read(ElgamalpubMPIstrs[i]);
} }
var data = util.str2Uint8Array("foobar");
describe('Sign and verify', function () { describe('Sign and verify', function () {
it('RSA', function (done) { it('RSA', function (done) {
//Originally we passed public and secret MPI separately, now they are joined. Is this what we want to do long term? //Originally we passed public and secret MPI separately, now they are joined. Is this what we want to do long term?
// RSA // RSA
var RSAsignedData = openpgp.crypto.signature.sign(2, 1, RSApubMPIs.concat(RSAsecMPIs), "foobar"); var RSAsignedData = openpgp.crypto.signature.sign(2, 1, RSApubMPIs.concat(RSAsecMPIs), data);
var RSAsignedDataMPI = new openpgp.MPI(); var RSAsignedDataMPI = new openpgp.MPI();
RSAsignedDataMPI.read(RSAsignedData); RSAsignedDataMPI.read(RSAsignedData);
var success = openpgp.crypto.signature.verify(1, 2, [RSAsignedDataMPI], RSApubMPIs, "foobar"); var success = openpgp.crypto.signature.verify(1, 2, [RSAsignedDataMPI], RSApubMPIs, data);
expect(success).to.be.true; expect(success).to.be.true;
done(); done();
}); });
it('DSA', function (done) { it('DSA', function (done) {
// DSA // DSA
var DSAsignedData = openpgp.crypto.signature.sign(2, 17, DSApubMPIs.concat(DSAsecMPIs), "foobar"); var DSAsignedData = openpgp.crypto.signature.sign(2, 17, DSApubMPIs.concat(DSAsecMPIs), data);
var DSAmsgMPIs = []; var DSAmsgMPIs = [];
DSAmsgMPIs[0] = new openpgp.MPI(); DSAmsgMPIs[0] = new openpgp.MPI();
DSAmsgMPIs[1] = new openpgp.MPI(); DSAmsgMPIs[1] = new openpgp.MPI();
DSAmsgMPIs[0].read(DSAsignedData.substring(0,34)); DSAmsgMPIs[0].read(DSAsignedData.substring(0,34));
DSAmsgMPIs[1].read(DSAsignedData.substring(34,68)); DSAmsgMPIs[1].read(DSAsignedData.substring(34,68));
var success = openpgp.crypto.signature.verify(17, 2, DSAmsgMPIs, DSApubMPIs, "foobar"); var success = openpgp.crypto.signature.verify(17, 2, DSAmsgMPIs, DSApubMPIs, data);
expect(success).to.be.true; expect(success).to.be.true;
done(); done();
}); });
@ -260,8 +262,8 @@ describe('API functional testing', function() {
function testCFB(plaintext, resync) { function testCFB(plaintext, resync) {
symmAlgos.forEach(function(algo) { symmAlgos.forEach(function(algo) {
var symmKey = openpgp.crypto.generateSessionKey(algo); var symmKey = openpgp.crypto.generateSessionKey(algo);
var symmencData = openpgp.crypto.cfb.encrypt(openpgp.crypto.getPrefixRandom(algo), algo, plaintext, symmKey, resync); var symmencData = openpgp.crypto.cfb.encrypt(openpgp.crypto.getPrefixRandom(algo), algo, util.str2Uint8Array(plaintext), symmKey, resync);
var text = openpgp.crypto.cfb.decrypt(algo, symmKey, symmencData, resync).join(''); var text = util.Uint8Array2str(openpgp.crypto.cfb.decrypt(algo, symmKey, symmencData, resync));
expect(text).to.equal(plaintext); expect(text).to.equal(plaintext);
}); });
} }
@ -281,23 +283,29 @@ describe('API functional testing', function() {
}); });
it('Asymmetric using RSA with eme_pkcs1 padding', function (done) { it('Asymmetric using RSA with eme_pkcs1 padding', function (done) {
var symmKey = openpgp.crypto.generateSessionKey('aes256'); var symmKey = util.Uint8Array2str(openpgp.crypto.generateSessionKey('aes256'));
var RSAUnencryptedData = new openpgp.MPI(); var RSAUnencryptedData = new openpgp.MPI();
RSAUnencryptedData.fromBytes(openpgp.crypto.pkcs1.eme.encode(symmKey, RSApubMPIs[0].byteLength())); RSAUnencryptedData.fromBytes(openpgp.crypto.pkcs1.eme.encode(symmKey, RSApubMPIs[0].byteLength()));
var RSAEncryptedData = openpgp.crypto.publicKeyEncrypt("rsa_encrypt_sign", RSApubMPIs, RSAUnencryptedData); var RSAEncryptedData = openpgp.crypto.publicKeyEncrypt("rsa_encrypt_sign", RSApubMPIs, RSAUnencryptedData);
var result = openpgp.crypto.pkcs1.eme.decode(openpgp.crypto.publicKeyDecrypt("rsa_encrypt_sign", RSApubMPIs.concat(RSAsecMPIs), RSAEncryptedData).write().substring(2), RSApubMPIs[0].byteLength()); var data = openpgp.crypto.publicKeyDecrypt("rsa_encrypt_sign", RSApubMPIs.concat(RSAsecMPIs), RSAEncryptedData).write();
data = util.Uint8Array2str(data.subarray(2, data.length));
var result = openpgp.crypto.pkcs1.eme.decode(data, RSApubMPIs[0].byteLength());
expect(result).to.equal(symmKey); expect(result).to.equal(symmKey);
done(); done();
}); });
it('Asymmetric using Elgamal with eme_pkcs1 padding', function (done) { it('Asymmetric using Elgamal with eme_pkcs1 padding', function (done) {
var symmKey = openpgp.crypto.generateSessionKey('aes256'); var symmKey = util.Uint8Array2str(openpgp.crypto.generateSessionKey('aes256'));
var ElgamalUnencryptedData = new openpgp.MPI(); var ElgamalUnencryptedData = new openpgp.MPI();
ElgamalUnencryptedData.fromBytes(openpgp.crypto.pkcs1.eme.encode(symmKey, ElgamalpubMPIs[0].byteLength())); ElgamalUnencryptedData.fromBytes(openpgp.crypto.pkcs1.eme.encode(symmKey, ElgamalpubMPIs[0].byteLength()));
var ElgamalEncryptedData = openpgp.crypto.publicKeyEncrypt("elgamal", ElgamalpubMPIs, ElgamalUnencryptedData); var ElgamalEncryptedData = openpgp.crypto.publicKeyEncrypt("elgamal", ElgamalpubMPIs, ElgamalUnencryptedData);
var result = openpgp.crypto.pkcs1.eme.decode(openpgp.crypto.publicKeyDecrypt("elgamal", ElgamalpubMPIs.concat(ElgamalsecMPIs), ElgamalEncryptedData).write().substring(2), ElgamalpubMPIs[0].byteLength()); var data = openpgp.crypto.publicKeyDecrypt("elgamal", ElgamalpubMPIs.concat(ElgamalsecMPIs), ElgamalEncryptedData).write();
data = util.Uint8Array2str(data.subarray(2, data.length));
var result = openpgp.crypto.pkcs1.eme.decode(data, ElgamalpubMPIs[0].byteLength());
expect(result).to.equal(symmKey); expect(result).to.equal(symmKey);
done(); done();
}); });

View File

@ -122,7 +122,7 @@ describe('Basic', function() {
} }
return result; return result;
} }
var message = randomString(1024*1024*3, '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'); var message = 'HI there';//randomString(1024*1024*3, '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ');
var userid = 'Test McTestington <test@example.com>'; var userid = 'Test McTestington <test@example.com>';
var passphrase = 'password'; var passphrase = 'password';
@ -147,7 +147,7 @@ describe('Basic', function() {
// sign and encrypt // sign and encrypt
var msg, encrypted; var msg, encrypted;
msg = openpgp.message.fromBinary(message, "test.txt"); msg = openpgp.message.fromText(message, "test.txt");
msg = msg.sign([privKey]); msg = msg.sign([privKey]);
msg = msg.encrypt([pubKey]); msg = msg.encrypt([pubKey]);
encrypted = openpgp.armor.encode(openpgp.enums.armor.message, msg.packets.write()); encrypted = openpgp.armor.encode(openpgp.enums.armor.message, msg.packets.write());
@ -171,6 +171,9 @@ describe('Basic', function() {
expect(decrypted.text).to.equal(message); expect(decrypted.text).to.equal(message);
done(); done();
}).catch(function (err) {
console.log(err.message);
console.log(err.stack);
}); });
}); });
}); });
@ -266,7 +269,7 @@ describe('Basic', function() {
openpgp.encryptMessage([pubKey], plaintext, [password1, password2], params).then(function(encrypted) { openpgp.encryptMessage([pubKey], plaintext, [password1, password2], params).then(function(encrypted) {
expect(encrypted).to.exist; expect(encrypted).to.exist;
encrypted = encrypted.keys+encrypted.data; encrypted = openpgp.util.concatUint8Array([encrypted.keys,encrypted.data]);
encrypted = openpgp.armor.encode(openpgp.enums.armor.message, encrypted); encrypted = openpgp.armor.encode(openpgp.enums.armor.message, encrypted);
message = openpgp.message.readArmored(encrypted); message = openpgp.message.readArmored(encrypted);

View File

@ -2,6 +2,18 @@
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('../../dist/openpgp'); var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('../../dist/openpgp');
function stringify(array) {
if(!Uint8Array.prototype.isPrototypeOf(array)) {
throw new Error('Data must be in the form of a Uint8Array');
}
var result = [];
for (var i = 0; i < array.length; i++) {
result[i] = String.fromCharCode(array[i]);
}
return result.join('');
}
var chai = require('chai'), var chai = require('chai'),
expect = chai.expect; expect = chai.expect;
@ -53,8 +65,8 @@ describe("Packet", function() {
message.push(enc); message.push(enc);
enc.packets.push(literal); enc.packets.push(literal);
var key = '123456789012345678901234', var key = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]),
algo = 'tripledes'; algo = 'aes256';
enc.encrypt(algo, key); enc.encrypt(algo, key);
@ -62,7 +74,7 @@ describe("Packet", function() {
msg2.read(message.write()); msg2.read(message.write());
msg2[0].decrypt(algo, key); msg2[0].decrypt(algo, key);
expect(msg2[0].packets[0].data).to.equal(literal.data); expect(stringify(msg2[0].packets[0].data)).to.equal(stringify(literal.data));
done(); done();
}); });
@ -87,7 +99,7 @@ describe("Packet", function() {
}); });
it('Sym. encrypted integrity protected packet', function(done) { it('Sym. encrypted integrity protected packet', function(done) {
var key = '12345678901234567890123456789012', var key = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]),
algo = 'aes256'; algo = 'aes256';
var literal = new openpgp.packet.Literal(), var literal = new openpgp.packet.Literal(),
@ -104,7 +116,7 @@ describe("Packet", function() {
msg2[0].decrypt(algo, key); msg2[0].decrypt(algo, key);
expect(msg2[0].packets[0].data).to.equal(literal.data); expect(stringify(msg2[0].packets[0].data)).to.equal(stringify(literal.data));
done(); done();
}); });
@ -129,7 +141,7 @@ describe("Packet", function() {
parsed[1].decrypt(parsed[0].sessionKeyAlgorithm, key); parsed[1].decrypt(parsed[0].sessionKeyAlgorithm, key);
var compressed = parsed[1].packets[0]; var compressed = parsed[1].packets[0];
var result = compressed.packets[0].data; var result = stringify(compressed.packets[0].data);
expect(result).to.equal('Hello world!\n'); expect(result).to.equal('Hello world!\n');
done(); done();
@ -152,7 +164,7 @@ describe("Packet", function() {
msg = new openpgp.packet.List(), msg = new openpgp.packet.List(),
msg2 = new openpgp.packet.List(); msg2 = new openpgp.packet.List();
enc.sessionKey = '12345678901234567890123456789012'; enc.sessionKey = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]);
enc.publicKeyAlgorithm = 'rsa_encrypt'; enc.publicKeyAlgorithm = 'rsa_encrypt';
enc.sessionKeyAlgorithm = 'aes256'; enc.sessionKeyAlgorithm = 'aes256';
enc.publicKeyId.bytes = '12345678'; enc.publicKeyId.bytes = '12345678';
@ -164,13 +176,13 @@ describe("Packet", function() {
msg2[0].decrypt({ mpi: mpi }); msg2[0].decrypt({ mpi: mpi });
expect(msg2[0].sessionKey).to.equal(enc.sessionKey); expect(stringify(msg2[0].sessionKey)).to.equal(stringify(enc.sessionKey));
expect(msg2[0].sessionKeyAlgorithm).to.equal(enc.sessionKeyAlgorithm); expect(msg2[0].sessionKeyAlgorithm).to.equal(enc.sessionKeyAlgorithm);
done(); done();
}); });
}); });
it('Secret key packet (reading, unencrpted)', function(done) { it('Secret key packet (reading, unencrypted)', function(done) {
var armored_key = var armored_key =
'-----BEGIN PGP PRIVATE KEY BLOCK-----\n' + '-----BEGIN PGP PRIVATE KEY BLOCK-----\n' +
'Version: GnuPG v2.0.19 (GNU/Linux)\n' + 'Version: GnuPG v2.0.19 (GNU/Linux)\n' +
@ -198,7 +210,7 @@ describe("Packet", function() {
key = key[0]; key = key[0];
var enc = new openpgp.packet.PublicKeyEncryptedSessionKey(), var enc = new openpgp.packet.PublicKeyEncryptedSessionKey(),
secret = '12345678901234567890123456789012'; secret = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]);
enc.sessionKey = secret; enc.sessionKey = secret;
enc.publicKeyAlgorithm = 'rsa_encrypt'; enc.publicKeyAlgorithm = 'rsa_encrypt';
@ -209,7 +221,7 @@ describe("Packet", function() {
enc.decrypt(key); enc.decrypt(key);
expect(enc.sessionKey).to.equal(secret); expect(stringify(enc.sessionKey)).to.equal(stringify(secret));
done(); done();
}); });
@ -271,7 +283,7 @@ describe("Packet", function() {
msg[0].decrypt(key); msg[0].decrypt(key);
msg[1].decrypt(msg[0].sessionKeyAlgorithm, msg[0].sessionKey); msg[1].decrypt(msg[0].sessionKeyAlgorithm, msg[0].sessionKey);
var text = msg[1].packets[0].packets[0].data; var text = stringify(msg[1].packets[0].packets[0].data);
expect(text).to.equal('Hello world!'); expect(text).to.equal('Hello world!');
done(); done();
@ -306,7 +318,7 @@ describe("Packet", function() {
var key2 = msg2[0].sessionKey; var key2 = msg2[0].sessionKey;
msg2[1].decrypt(msg2[0].sessionKeyAlgorithm, key2); msg2[1].decrypt(msg2[0].sessionKeyAlgorithm, key2);
expect(msg2[1].packets[0].data).to.equal(literal.data); expect(stringify(msg2[1].packets[0].data)).to.equal(stringify(literal.data));
done(); done();
}); });
@ -334,7 +346,7 @@ describe("Packet", function() {
msg[0].decrypt(key); msg[0].decrypt(key);
msg[1].decrypt(msg[0].sessionKeyAlgorithm, msg[0].sessionKey); msg[1].decrypt(msg[0].sessionKeyAlgorithm, msg[0].sessionKey);
var text = msg[1].packets[0].packets[0].data; var text = stringify(msg[1].packets[0].packets[0].data);
expect(text).to.equal('Hello world!'); expect(text).to.equal('Hello world!');
done(); done();

View File

@ -189,7 +189,11 @@ describe('Init Worker', function() {
openpgp.getWorker().decryptKeyPacket(privKeyRSA, [privKeyRSA.primaryKey.getKeyId()], 'hello world').then(function(key) { openpgp.getWorker().decryptKeyPacket(privKeyRSA, [privKeyRSA.primaryKey.getKeyId()], 'hello world').then(function(key) {
expect(key.primaryKey.isDecrypted).to.be.true; expect(key.primaryKey.isDecrypted).to.be.true;
done(); done();
}).catch(done); }).catch(function(err) {
console.log(err);
done();
});
//}).catch(done);
}); });
}); });
@ -320,7 +324,7 @@ describe('High level API', function() {
openpgp.decryptSessionKey(password1, msgAES).then(function(sk) { openpgp.decryptSessionKey(password1, msgAES).then(function(sk) {
return openpgp.encryptSessionKey(sk.key, sk.algo, pubKeyRSA); return openpgp.encryptSessionKey(sk.key, sk.algo, pubKeyRSA);
}).then(function(keypacket) { }).then(function(keypacket) {
var msg = openpgp.message.read([keypacket, data].join('')); var msg = openpgp.message.read(openpgp.util.concatUint8Array([keypacket, data]));
return openpgp.decryptMessage(privKeyRSA, msg); return openpgp.decryptMessage(privKeyRSA, msg);
}).then(function(data) { }).then(function(data) {
expect(data).to.exist; expect(data).to.exist;
@ -333,7 +337,7 @@ describe('High level API', function() {
openpgp.decryptSessionKey(password1, msgAES).then(function(sk) { openpgp.decryptSessionKey(password1, msgAES).then(function(sk) {
return openpgp.encryptSessionKey(sk.key, sk.algo, [], password2); return openpgp.encryptSessionKey(sk.key, sk.algo, [], password2);
}).then(function(keypacket) { }).then(function(keypacket) {
var msg = openpgp.message.read([keypacket, data].join('')); var msg = openpgp.message.read(openpgp.util.concatUint8Array([keypacket, data]));
return openpgp.decryptMessage(password2, msg); return openpgp.decryptMessage(password2, msg);
}).then(function(data) { }).then(function(data) {
expect(data).to.exist; expect(data).to.exist;