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

View File

@ -12,14 +12,11 @@
*/
/**
* @requires util
* @module crypto/cipher/aes
*/
'use strict';
var util = require('../../util.js');
// The round constants used in subkey expansion
var Rcon = new Uint8Array([
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) {
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--) {

View File

@ -391,19 +391,17 @@ Blowfish.prototype.init = function(key) {
}
};
var util = require('../../util.js');
// added by Recurity Labs
function BFencrypt(block, key) {
var bf = new Blowfish();
bf.init(util.str2bin(key));
bf.init(key);
return bf.encrypt_block(block);
}
function BF(key) {
this.bf = new Blowfish();
this.bf.init(util.str2bin(key));
this.bf.init(key);
this.encrypt = function(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);
}
var util = require('../../util.js');
function cast5(key) {
this.cast5 = new openpgp_symenc_cast5();
this.cast5.setKey(util.str2bin(key));
this.cast5.setKey(key);
this.encrypt = function(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 endloop, loopinc;
var len = message.length;
var chunk = 0;
//set up the loops for single and triple des
var iterations = keys.length == 32 ? 3 : 9; //single or triple des
if (iterations == 3) {
@ -102,21 +102,19 @@ function des(keys, message, encrypt, mode, iv, padding) {
}
//store the result here
var result = "";
var tempresult = "";
var result = new Uint8Array(len);
var k = 0;
if (mode == 1) { //CBC mode
cbcleft = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++);
cbcright = (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[m++] << 24) | (iv[m++] << 16) | (iv[m++] << 8) | iv[m++];
m = 0;
}
//loop through each 64 bit chunk of the message
while (m < len) {
left = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) | message
.charCodeAt(m++);
right = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) |
message.charCodeAt(m++);
left = (message[m++] << 24) | (message[m++] << 16) | (message[m++] << 8) | message[m++];
right = (message[m++] << 24) | (message[m++] << 16) | (message[m++] << 8) | message[m++];
//for Cipher Block Chaining mode, xor the message with the previous result
if (mode == 1) {
@ -202,20 +200,17 @@ function des(keys, message, encrypt, mode, iv, padding) {
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;
if (chunk == 512) {
result += tempresult;
tempresult = "";
chunk = 0;
}
result[k++] = (left >>> 24);
result[k++] = ((left >>> 16) & 0xff);
result[k++] = ((left >>> 8) & 0xff);
result[k++] = (left & 0xff);
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
//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
if (!encrypt) {
result = des_removePadding(result, padding);
@ -272,8 +267,8 @@ function des_createKeys(key) {
temp;
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 right = (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[m++] << 24) | (key[m++] << 16) | (key[m++] << 8) | key[m++];
temp = ((left >>> 4) ^ right) & 0x0f0f0f0f;
right ^= temp;
@ -338,27 +333,55 @@ function des_createKeys(key) {
function des_addPadding(message, padding) {
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
message += String.fromCharCode(padLength, padLength, padLength, padLength, padLength, padLength, padLength,
padLength).substr(0, padLength);
pad = padLength;
} 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) {
var padLength = null;
var pad;
if (padding == 2) { // space padded
message = message.replace(/ *$/g, "");
pad = " ".charCodeAt(0);
} else if (padding == 1) { // PKCS7
var padCount = message.charCodeAt(message.length - 1);
message = message.substr(0, message.length - padCount);
padLength = message[message.length - 1];
} 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 = [];
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) {
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[0]),
util.bin2str(block), true, 0, null, null),
false, 0, null, null), true, 0, null, null));
block, true, 0, null, null),
false, 0, null, null), true, 0, null, null);
};
}
@ -393,12 +416,12 @@ function OriginalDes(key) {
this.encrypt = function(block, padding) {
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) {
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
function TFencrypt(block, key) {
var block_copy = toArray(block);
var tf = createTwofish();
tf.open(util.str2bin(key), 0);
tf.open(toArray(key), 0);
var result = tf.encrypt(block_copy, 0);
tf.close();
return result;
@ -347,7 +345,7 @@ function TFencrypt(block, key) {
function TF(key) {
this.tf = createTwofish();
this.tf.open(util.str2bin(key), 0);
this.tf.open(toArray(key), 0);
this.encrypt = function(block) {
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
* @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
*/
getPrefixRandom: function(algo) {
@ -222,7 +222,7 @@ module.exports = {
/**
* 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})
* @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) {
return random.getRandomBytes(cipher[algo].keySize);

View File

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

View File

@ -1,10 +1,12 @@
/**
* @requires util
* @requires crypto/hash
* @requires crypto/pkcs1
* @requires crypto/public_key
* @module crypto/signature */
var publicKey = require('./public_key'),
var util = require('../util'),
publicKey = require('./public_key'),
pkcs1 = require('./pkcs1.js'),
hashModule = require('./hash');
@ -15,11 +17,13 @@ module.exports = {
* @param {module:enums.hash} hash_algo Hash algorithm
* @param {Array<module:type/mpi>} msg_MPIs Signature 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)
*/
verify: function(algo, hash_algo, msg_MPIs, publickey_MPIs, data) {
data = util.Uint8Array2str(data);
switch (algo) {
case 1:
// RSA (Encrypt or Sign) [HAC]
@ -63,11 +67,13 @@ module.exports = {
* of the private key
* @param {Array<module:type/mpi>} secretMPIs Private key multiprecision
* 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>}
*/
sign: function(hash_algo, algo, keyIntegers, data) {
data = util.Uint8Array2str(data);
var m;
switch (algo) {
@ -82,7 +88,6 @@ module.exports = {
var n = keyIntegers[0].toBigInteger();
m = pkcs1.emsa.encode(hash_algo,
data, keyIntegers[0].byteLength());
return rsa.sign(m, d, n).toMPI();
case 17:

View File

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

View File

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

View File

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

View File

@ -26,7 +26,8 @@
'use strict';
var packet = require('./packet'),
var util = require('./util.js'),
packet = require('./packet'),
enums = require('./enums.js'),
armor = require('./encoding/armor.js'),
config = require('./config'),
@ -463,11 +464,11 @@ function read(input) {
/**
* 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} detachedSignature The detached ascii armored PGP signarure
* @param {String} detachedSignature The detached ascii armored PGP signature
*/
function readSignedContent(content, detachedSignature) {
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();
packetlist.push(literalDataPacket);
var input = armor.decode(detachedSignature).data;
@ -496,12 +497,16 @@ function fromText(text, filename) {
/**
* creates new message object from binary data
* @param {String} bytes
* @param {Uint8Array} bytes
* @param {String} filename (optional)
* @return {module:message~Message} new message object
* @static
*/
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();
if (filename) {
literalDataPacket.setFilename(filename);

View File

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

View File

@ -70,10 +70,10 @@ function Compressed() {
*/
Compressed.prototype.read = function (bytes) {
// 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.
this.compressed = bytes.substr(1);
this.compressed = bytes.subarray(1, bytes.length);
this.decompress();
};
@ -88,7 +88,7 @@ Compressed.prototype.write = function () {
if (this.compressed === null)
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;
case 'zip':
var inflate = new RawInflate.Zlib.RawInflate(util.str2Uint8Array(this.compressed));
decompressed = util.Uint8Array2str(inflate.decompress());
var inflate = new RawInflate.Zlib.RawInflate(this.compressed);
decompressed = inflate.decompress();
break;
case 'zlib':
var inflate = new Zlib.Zlib.Inflate(util.str2Uint8Array(this.compressed));
decompressed = util.Uint8Array2str(inflate.decompress());
var inflate = new Zlib.Zlib.Inflate(this.compressed);
decompressed = inflate.decompress();
break;
case 'bzip2':
@ -141,14 +141,14 @@ Compressed.prototype.compress = function () {
case 'zip':
// - ZIP [RFC1951]
deflate = new RawDeflate.Zlib.RawDeflate(util.str2Uint8Array(uncompressed));
this.compressed = util.Uint8Array2str(deflate.compress());
deflate = new RawDeflate.Zlib.RawDeflate(uncompressed);
this.compressed = deflate.compress();
break;
case 'zlib':
// - ZLIB [RFC1950]
deflate = new Zlib.Zlib.Deflate(util.str2Uint8Array(uncompressed));
this.compressed = util.Uint8Array2str(deflate.compress());
deflate = new Zlib.Zlib.Deflate(uncompressed);
this.compressed = deflate.compress();
break;
case 'bzip2':

View File

@ -36,8 +36,8 @@ var util = require('../util.js'),
function Literal() {
this.tag = enums.packet.literal;
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.data = new Uint8Array(0); // literal data representation
this.filename = 'msg.txt';
}
@ -50,7 +50,7 @@ Literal.prototype.setText = function (text) {
// normalize EOL to \r\n
text = text.replace(/\r/g, '').replace(/\n/g, '\r\n');
// 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 () {
// decode UTF8
var text = util.decode_utf8(this.data);
var text = util.decode_utf8(util.Uint8Array2str(this.data));
// normalize EOL to \n
return text.replace(/\r\n/g, '\n');
};
/**
* 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
*/
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
* @returns {String} A sequence of bytes
* @returns {Uint8Array} A sequence of bytes
*/
Literal.prototype.getBytes = function () {
return this.data;
@ -106,25 +106,20 @@ Literal.prototype.getFilename = function() {
/**
* Parsing function for a literal data packet (tag 11).
*
* @param {String} input Payload of a tag 11 packet
* @param {Integer} position
* Position to start reading from the input string
* @param {Integer} len
* Length of the packet or the remaining length of
* input at position
* @param {Uint8Array} input Payload of a tag 11 packet
* @return {module:packet/literal} object representation
*/
Literal.prototype.read = function (bytes) {
// - 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.filename = util.decode_utf8(bytes.substr(2, filename_len));
this.date = util.readDate(bytes.subarray(2 + filename_len, 2 + filename_len + 4));
this.date = util.readDate(bytes.substr(2 + filename_len, 4));
var data = bytes.substring(6 + filename_len);
var data = bytes.subarray(6 + filename_len, bytes.length);
this.setBytes(data, format);
};
@ -132,19 +127,15 @@ Literal.prototype.read = function (bytes) {
/**
* Creates a string representation of the packet
*
* @param {String} data The data to be inserted as body
* @return {String} string-representation of the packet
* @return {Uint8Array} Uint8Array representation of the packet
*/
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 result = '';
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;
return util.concatUint8Array([format, filename_length, filename, date, data]);
};

View File

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

View File

@ -23,6 +23,7 @@
* hashes needed to verify the signature. It allows the Signature
* packet to be placed at the end of the message, so that the signer
* can compute the entire signed message in one pass.
* @requires util
* @requires enums
* @requires type/keyid
* @module packet/one_pass_signature
@ -30,7 +31,8 @@
module.exports = OnePassSignature;
var enums = require('../enums.js'),
var util = require('../util.js'),
enums = require('../enums.js'),
type_keyid = require('../type/keyid.js');
/**
@ -48,52 +50,50 @@ function OnePassSignature() {
/**
* 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
*/
OnePassSignature.prototype.read = function (bytes) {
var mypos = 0;
// 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
// 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.
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.
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.
this.signingKeyId = new type_keyid();
this.signingKeyId.read(bytes.substr(mypos));
this.signingKeyId.read(bytes.subarray(mypos, mypos + 8));
mypos += 8;
// A one-octet number holding a flag showing whether the signature
// is nested. A zero value indicates that the next packet is
// another One-Pass Signature packet that describes another
// signature to be applied to the same message data.
this.flags = bytes.charCodeAt(mypos++);
this.flags = bytes[mypos++];
return this;
};
/**
* 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 () {
var result = "";
result += String.fromCharCode(3);
result += String.fromCharCode(enums.write(enums.signature, this.type));
result += String.fromCharCode(enums.write(enums.hash, this.hashAlgorithm));
result += String.fromCharCode(enums.write(enums.publicKey, this.publicKeyAlgorithm));
result += this.signingKeyId.write();
result += String.fromCharCode(this.flags);
var start = new Uint8Array([3, enums.write(enums.signature, this.type),
enums.write(enums.hash, this.hashAlgorithm),
enums.write(enums.publicKey, this.publicKeyAlgorithm)]);
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) {
var len = 0,
offset,
type = bytes.charCodeAt(0);
type = bytes[0];
if (type < 192) {
len = bytes.charCodeAt(0);
len = bytes[0];
offset = 1;
} else if (type < 255) {
len = ((bytes.charCodeAt(0) - 192) << 8) + (bytes.charCodeAt(1)) + 192;
len = ((bytes[0] - 192) << 8) + (bytes[1]) + 192;
offset = 2;
} else if (type == 255) {
len = util.readNumber(bytes.substr(1, 4));
len = util.readNumber(bytes.subarray(1, 1 + 4));
offset = 5;
}
@ -53,24 +53,21 @@ module.exports = {
* string
*
* @param {Integer} length The length to encode
* @return {String} String with openpgp length representation
* @return {Uint8Array} String with openpgp length representation
*/
writeSimpleLength: function(length) {
var result = "";
if (length < 192) {
result += String.fromCharCode(length);
return new Uint8Array([length]);
} else if (length > 191 && length < 8384) {
/*
* let a = (total data packet length) - 192 let bc = two octet
* representation of a let d = b + 192
*/
result += String.fromCharCode(((length - 192) >> 8) + 192);
result += String.fromCharCode((length - 192) & 0xFF);
return new Uint8Array([((length - 192) >> 8) + 192, (length - 192) & 0xFF]);
} else {
result += String.fromCharCode(255);
result += util.writeNumber(length, 4);
return util.concatUint8Array([new Uint8Array([255]), util.writeNumber(length, 4)]);
}
return result;
},
/**
@ -83,10 +80,7 @@ module.exports = {
*/
writeHeader: function(tag_type, length) {
/* we're only generating v4 packet headers here */
var result = "";
result += String.fromCharCode(0xC0 | tag_type);
result += this.writeSimpleLength(length);
return result;
return util.concatUint8Array([new Uint8Array([0xC0 | tag_type]), this.writeSimpleLength(length)]);
},
/**
@ -98,18 +92,14 @@ module.exports = {
* @return {String} String of the header
*/
writeOldHeader: function(tag_type, length) {
var result = "";
if (length < 256) {
result += String.fromCharCode(0x80 | (tag_type << 2));
result += String.fromCharCode(length);
return new Uint8Array([0x80 | (tag_type << 2), length]);
} else if (length < 65536) {
result += String.fromCharCode(0x80 | (tag_type << 2) | 1);
result += util.writeNumber(length, 2);
return util.concatUint8Array([0x80 | (tag_type << 2) | 1, util.writeNumber(length, 2)]);
} else {
result += String.fromCharCode(0x80 | (tag_type << 2) | 2);
result += util.writeNumber(length, 4);
return util.concatUint8Array([0x80 | (tag_type << 2) | 2, util.writeNumber(length, 4)]);
}
return result;
},
/**
@ -122,9 +112,9 @@ module.exports = {
*/
read: function(input, position, len) {
// 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) {
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 tag = -1;
@ -132,18 +122,18 @@ module.exports = {
var packet_length;
format = 0; // 0 = old format; 1 = new format
if ((input.charCodeAt(mypos) & 0x40) !== 0) {
if ((input[mypos] & 0x40) !== 0) {
format = 1;
}
var packet_length_type;
if (format) {
// new format header
tag = input.charCodeAt(mypos) & 0x3F; // bit 5-0
tag = input[mypos] & 0x3F; // bit 5-0
} else {
// old format header
tag = (input.charCodeAt(mypos) & 0x3F) >> 2; // bit 5-2
packet_length_type = input.charCodeAt(mypos) & 0x03; // bit 1-0
tag = (input[mypos] & 0x3F) >> 2; // bit 5-2
packet_length_type = input[mypos] & 0x03; // bit 1-0
}
// header octet parsing done
@ -160,18 +150,18 @@ module.exports = {
case 0:
// The packet has a one-octet length. The header is 2 octets
// long.
packet_length = input.charCodeAt(mypos++);
packet_length = input[mypos++];
break;
case 1:
// The packet has a two-octet length. The header is 3 octets
// long.
packet_length = (input.charCodeAt(mypos++) << 8) | input.charCodeAt(mypos++);
packet_length = (input[mypos++] << 8) | input[mypos++];
break;
case 2:
// The packet has a four-octet length. The header is 5
// octets long.
packet_length = (input.charCodeAt(mypos++) << 24) | (input.charCodeAt(mypos++) << 16) | (input.charCodeAt(mypos++) <<
8) | input.charCodeAt(mypos++);
packet_length = (input[mypos++] << 24) | (input[mypos++] << 16) | (input[mypos++] <<
8) | input[mypos++];
break;
default:
// 3 - The packet is of indeterminate length. The header is 1
@ -192,44 +182,43 @@ module.exports = {
{
// 4.2.2.1. One-Octet Lengths
if (input.charCodeAt(mypos) < 192) {
packet_length = input.charCodeAt(mypos++);
if (input[mypos] < 192) {
packet_length = input[mypos++];
util.print_debug("1 byte length:" + packet_length);
// 4.2.2.2. Two-Octet Lengths
} else if (input.charCodeAt(mypos) >= 192 && input.charCodeAt(mypos) < 224) {
packet_length = ((input.charCodeAt(mypos++) - 192) << 8) + (input.charCodeAt(mypos++)) + 192;
} else if (input[mypos] >= 192 && input[mypos] < 224) {
packet_length = ((input[mypos++] - 192) << 8) + (input[mypos++]) + 192;
util.print_debug("2 byte length:" + packet_length);
// 4.2.2.4. Partial Body Lengths
} else if (input.charCodeAt(mypos) > 223 && input.charCodeAt(mypos) < 255) {
packet_length = 1 << (input.charCodeAt(mypos++) & 0x1F);
} else if (input[mypos] > 223 && input[mypos] < 255) {
packet_length = 1 << (input[mypos++] & 0x1F);
util.print_debug("4 byte length:" + packet_length);
// EEEK, we're reading the full data here...
var mypos2 = mypos + packet_length;
bodydata = input.substring(mypos, mypos + packet_length);
bodydata = [input.subarray(mypos, mypos + packet_length)];
var tmplen;
while (true) {
if (input.charCodeAt(mypos2) < 192) {
tmplen = input.charCodeAt(mypos2++);
if (input[mypos2] < 192) {
tmplen = input[mypos2++];
packet_length += tmplen;
bodydata += input.substring(mypos2, mypos2 + tmplen);
bodydata.push(input.subarray(mypos2, mypos2 + tmplen));
mypos2 += tmplen;
break;
} else if (input.charCodeAt(mypos2) >= 192 && input.charCodeAt(mypos2) < 224) {
tmplen = ((input.charCodeAt(mypos2++) - 192) << 8) + (input.charCodeAt(mypos2++)) + 192;
} else if (input[mypos2] >= 192 && input[mypos2] < 224) {
tmplen = ((input[mypos2++] - 192) << 8) + (input[mypos2++]) + 192;
packet_length += tmplen;
bodydata += input.substring(mypos2, mypos2 + tmplen);
bodydata.push(input.subarray(mypos2, mypos2 + tmplen));
mypos2 += tmplen;
break;
} else if (input.charCodeAt(mypos2) > 223 && input.charCodeAt(mypos2) < 255) {
tmplen = 1 << (input.charCodeAt(mypos2++) & 0x1F);
} else if (input[mypos2] > 223 && input[mypos2] < 255) {
tmplen = 1 << (input[mypos2++] & 0x1F);
packet_length += tmplen;
bodydata += input.substring(mypos2, mypos2 + tmplen);
bodydata.push(input.subarray(mypos2, mypos2 + tmplen));
mypos2 += tmplen;
} else {
mypos2++;
tmplen = (input.charCodeAt(mypos2++) << 24) | (input.charCodeAt(mypos2++) << 16) | (input
.charCodeAt(mypos2++) << 8) | input.charCodeAt(mypos2++);
bodydata += input.substring(mypos2, mypos2 + tmplen);
tmplen = (input[mypos2++] << 24) | (input[mypos2++] << 16) | (input[mypos2++] << 8) | input[mypos2++];
bodydata.push(input.subarray(mypos2, mypos2 + tmplen));
packet_length += tmplen;
mypos2 += tmplen;
break;
@ -239,8 +228,8 @@ module.exports = {
// 4.2.2.3. Five-Octet Lengths
} else {
mypos++;
packet_length = (input.charCodeAt(mypos++) << 24) | (input.charCodeAt(mypos++) << 16) | (input.charCodeAt(mypos++) <<
8) | input.charCodeAt(mypos++);
packet_length = (input[mypos++] << 24) | (input[mypos++] << 16) | (input[mypos++] <<
8) | input[mypos++];
}
}
@ -251,7 +240,10 @@ module.exports = {
}
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 {

View File

@ -2,6 +2,7 @@
* This class represents a list of openpgp packets.
* Take care when iterating over it - the packets themselves
* are stored as numerical indices.
* @requires util
* @requires enums
* @requires packet
* @requires packet/packet
@ -10,7 +11,8 @@
module.exports = Packetlist;
var packetParser = require('./packet.js'),
var util = require('../util'),
packetParser = require('./packet.js'),
packets = require('./all_packets.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.
* @param {String} A binary string of bytes.
* @param {Uint8Array} A Uint8Array of bytes.
*/
Packetlist.prototype.read = function (bytes) {
var i = 0;
@ -46,18 +48,18 @@ Packetlist.prototype.read = function (bytes) {
/**
* Creates a binary representation of openpgp objects contained within the
* 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 () {
var bytes = '';
var arr = [];
for (var i = 0; i < this.length; i++) {
var packetbytes = this[i].write();
bytes += packetParser.writeHeader(this[i].tag, packetbytes.length);
bytes += packetbytes;
arr.push(packetParser.writeHeader(this[i].tag, packetbytes.length));
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}
* 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
*/
PublicKey.prototype.read = function (bytes) {
var pos = 0;
// A one-octet version number (3 or 4).
this.version = bytes.charCodeAt(pos++);
this.version = bytes[pos++];
if (this.version == 3 || this.version == 4) {
// - 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;
if (this.version == 3) {
// - A two-octet number denoting the time in days that this key is
// 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;
}
// - 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);
this.mpi = [];
var bmpi = bytes.substr(pos);
var bmpi = bytes.subarray(pos, bytes.length);
var p = 0;
for (var i = 0; i < mpicount && p < bmpi.length; i++) {
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) {
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
* public key.
* @return {Object} {body: [string]OpenPGP packet body contents,
* header: [string] OpenPGP packet header, string: [string] header+body}
* @return {Uint8Array} OpenPGP packet body contents,
*/
PublicKey.prototype.write = function () {
var arr = [];
// Version
var result = String.fromCharCode(this.version);
result += util.writeDate(this.created);
arr.push(new Uint8Array([this.version]));
arr.push(util.writeDate(this.created));
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);
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 () {
var bytes = this.writePublicKey();
return String.fromCharCode(0x99) +
util.writeNumber(bytes.length, 2) +
bytes;
return util.concatUint8Array([new Uint8Array([0x99]), util.writeNumber(bytes.length, 2), bytes]);
};
/**
@ -173,9 +172,10 @@ PublicKey.prototype.getKeyId = function () {
}
this.keyid = new type_keyid();
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) {
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;
};
@ -191,7 +191,7 @@ PublicKey.prototype.getFingerprint = function () {
var toHash = '';
if (this.version == 4) {
toHash = this.writeOld();
this.fingerprint = crypto.hash.sha1(toHash);
this.fingerprint = crypto.hash.sha1(util.Uint8Array2str(toHash));
} else if (this.version == 3) {
var mpicount = crypto.getPublicMpiCount(this.algorithm);
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).
*
* @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} len Length of the packet or the remaining length of
* input at position
@ -73,9 +73,9 @@ function PublicKeyEncryptedSessionKey() {
*/
PublicKeyEncryptedSessionKey.prototype.read = function (bytes) {
this.version = bytes.charCodeAt(0);
this.publicKeyId.read(bytes.substr(1));
this.publicKeyAlgorithm = enums.read(enums.publicKey, bytes.charCodeAt(9));
this.version = bytes[0];
this.publicKeyId.read(bytes.subarray(1,bytes.length));
this.publicKeyAlgorithm = enums.read(enums.publicKey, bytes[9]);
var i = 10;
@ -97,7 +97,7 @@ PublicKeyEncryptedSessionKey.prototype.read = function (bytes) {
for (var j = 0; j < integerCount; j++) {
var mpi = new type_mpi();
i += mpi.read(bytes.substr(i));
i += mpi.read(bytes.subarray(i, bytes.length));
this.encrypted.push(mpi);
}
};
@ -105,42 +105,26 @@ PublicKeyEncryptedSessionKey.prototype.read = function (bytes) {
/**
* Create a string representation of a tag 1 packet
*
* @param {String} publicKeyId
* 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
* @return {Uint8Array} The Uint8Array representation
*/
PublicKeyEncryptedSessionKey.prototype.write = function () {
var result = String.fromCharCode(this.version);
result += this.publicKeyId.write();
result += String.fromCharCode(
enums.write(enums.publicKey, this.publicKeyAlgorithm));
var arr = [new Uint8Array([this.version]), this.publicKeyId.write(), new Uint8Array([enums.write(enums.publicKey, this.publicKeyAlgorithm)])];
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) {
var data = String.fromCharCode(
enums.write(enums.symmetric, this.sessionKeyAlgorithm));
data += this.sessionKey;
data += util.Uint8Array2str(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();
mpi.fromBytes(crypto.pkcs1.eme.encode(
@ -167,11 +151,11 @@ PublicKeyEncryptedSessionKey.prototype.decrypt = function (key) {
key.mpi,
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);
key = decoded.substring(1, decoded.length - 2);
key = util.str2Uint8Array(decoded.substring(1, decoded.length - 2));
if (checksum != util.calc_checksum(key)) {
throw new Error('Checksum mismatch');

View File

@ -68,7 +68,7 @@ function get_hash_fn(hash) {
return crypto.hash.sha1;
else
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),
hashfn = get_hash_fn(hash_algorithm);
var hashtext = cleartext.substr(cleartext.length - hashlen);
cleartext = cleartext.substr(0, cleartext.length - hashlen);
var hashtext = util.Uint8Array2str(cleartext.subarray(cleartext.length - hashlen, cleartext.length));
cleartext = cleartext.subarray(0, cleartext.length - hashlen);
var hash = hashfn(cleartext);
var hash = hashfn(util.Uint8Array2str(cleartext));
if (hash != hashtext)
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++) {
mpi[i] = new type_mpi();
j += mpi[i].read(cleartext.substr(j));
j += mpi[i].read(cleartext.subarray(j, cleartext.length));
}
return mpi;
}
function write_cleartext_mpi(hash_algorithm, algorithm, mpi) {
var bytes = '';
var arr = [];
var discard = crypto.getPublicMpiCount(algorithm);
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.
var len = this.readPublicKey(bytes);
bytes = bytes.substr(len);
bytes = bytes.subarray(len, bytes.length);
// - One octet indicating string-to-key usage conventions. Zero
// indicates that the secret-key data is not encrypted. 255 or 254
// indicates that a string-to-key specifier is being given. Any
// other value is a symmetric-key encryption algorithm identifier.
var isEncrypted = bytes.charCodeAt(0);
var isEncrypted = bytes[0];
if (isEncrypted) {
this.encrypted = bytes;
} else {
// - Plain or encrypted multiprecision integers comprising the secret
// key data. These algorithm-specific fields are as described
// 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)
throw 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
*/
SecretKey.prototype.write = function () {
var bytes = this.writePublicKey();
var arr = [this.writePublicKey()];
if (!this.encrypted) {
bytes += String.fromCharCode(0);
bytes += write_cleartext_mpi('mod', this.algorithm, this.mpi);
arr.push(new Uint8Array([0]));
arr.push(write_cleartext_mpi('mod', this.algorithm, this.mpi));
} 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,
iv = crypto.random.getRandomBytes(blockLen);
this.encrypted = '';
this.encrypted += String.fromCharCode(254);
this.encrypted += String.fromCharCode(enums.write(enums.symmetric, symmetric));
this.encrypted += s2k.write();
this.encrypted += iv;
var arr = [ new Uint8Array([254, enums.write(enums.symmetric, symmetric)]) ];
arr.push(s2k.write());
arr.push(iv);
arr.push(crypto.cfb.normalEncrypt(symmetric, key, cleartext, iv));
this.encrypted += crypto.cfb.normalEncrypt(symmetric, key, cleartext, iv);
this.encrypted = util.concatUint8Array(arr);
};
function produceEncryptionKey(s2k, passphrase, algorithm) {
@ -222,38 +220,48 @@ SecretKey.prototype.decrypt = function (passphrase) {
symmetric,
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-
// octet symmetric encryption algorithm.
if (s2k_usage == 255 || s2k_usage == 254) {
symmetric = this.encrypted.charCodeAt(i++);
symmetric = this.encrypted[i++];
symmetric = enums.read(enums.symmetric, symmetric);
// - [Optional] If string-to-key usage octet was 255 or 254, a
// string-to-key specifier. The length of the string-to-key
// specifier is implied by its type, as described above.
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);
} else {
symmetric = s2k_usage;
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
// not zero), an Initial Vector (IV) of the same length as the
// cipher's block size.
var iv = this.encrypted.substr(i,
crypto.cipher[symmetric].blockSize);
var iv = this.encrypted.subarray(i,
i + crypto.cipher[symmetric].blockSize);
i += iv.length;
var cleartext,
ciphertext = this.encrypted.substr(i);
ciphertext = this.encrypted.subarray(i, this.encrypted.length);
cleartext = crypto.cfb.normalDecrypt(symmetric, key, ciphertext, iv);

View File

@ -98,47 +98,46 @@ function Signature() {
*/
Signature.prototype.read = function (bytes) {
var i = 0;
this.version = bytes.charCodeAt(i++);
this.version = bytes[i++];
// switch on version (3 and 4)
switch (this.version) {
case 3:
// 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" +
'invalid One-octet length of following hashed material.' +
'MUST be 5. @:' + (i - 1));
var sigpos = i;
// One-octet signature type.
this.signatureType = bytes.charCodeAt(i++);
this.signatureType = bytes[i++];
// Four-octet creation time.
this.created = util.readDate(bytes.substr(i, 4));
this.created = util.readDate(bytes.subarray(i, i + 4));
i += 4;
// 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.
this.issuerKeyId.read(bytes.substring(i, i + 8));
this.issuerKeyId.read(bytes.subarray(i, i + 8));
i += 8;
// One-octet public-key algorithm.
this.publicKeyAlgorithm = bytes.charCodeAt(i++);
this.publicKeyAlgorithm = bytes[i++];
// One-octet hash algorithm.
this.hashAlgorithm = bytes.charCodeAt(i++);
this.hashAlgorithm = bytes[i++];
break;
case 4:
this.signatureType = bytes.charCodeAt(i++);
this.publicKeyAlgorithm = bytes.charCodeAt(i++);
this.hashAlgorithm = bytes.charCodeAt(i++);
this.signatureType = bytes[i++];
this.publicKeyAlgorithm = bytes[i++];
this.hashAlgorithm = bytes[i++];
function subpackets(bytes) {
// Two-octet scalar octet count for following subpacket data.
var subpacket_length = util.readNumber(
bytes.substr(0, 2));
bytes.subarray(0, 2));
var i = 2;
@ -146,10 +145,10 @@ Signature.prototype.read = function (bytes) {
var subpacked_read = 0;
while (i < 2 + subpacket_length) {
var len = packet.readSimpleLength(bytes.substr(i));
var len = packet.readSimpleLength(bytes.subarray(i, bytes.length));
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;
}
@ -158,7 +157,7 @@ Signature.prototype.read = function (bytes) {
}
// 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
// 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
// hash algorithm, the hashed subpacket length, and the hashed
// subpacket body.
this.signatureData = bytes.substr(0, i);
this.signatureData = bytes.subarray(0, i);
var sigDataLength = i;
// unhashed subpackets
i += subpackets.call(this, bytes.substr(i), false);
this.unhashedSubpackets = bytes.substr(sigDataLength, i - sigDataLength);
i += subpackets.call(this, bytes.subarray(i, bytes.length), false);
this.unhashedSubpackets = bytes.subarray(sigDataLength, i);
break;
default:
@ -179,30 +178,29 @@ Signature.prototype.read = function (bytes) {
}
// 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;
this.signature = bytes.substr(i);
this.signature = bytes.subarray(i, bytes.length);
};
Signature.prototype.write = function () {
var result = '';
var arr = [];
switch (this.version) {
case 3:
result += String.fromCharCode(3); // version
result += String.fromCharCode(5); // One-octet length of following hashed material. MUST be 5
result += this.signatureData;
result += this.issuerKeyId.write();
result += String.fromCharCode(this.publicKeyAlgorithm);
result += String.fromCharCode(this.hashAlgorithm);
arr.push(new Uint8Array([3, 5])); // version, One-octet length of following hashed material. MUST be 5
arr.push(this.signatureData);
arr.push(this.issuerKeyId.write());
arr.push(new Uint8Array([this.publicKeyAlgorithm, this.hashAlgorithm]));
break;
case 4:
result += this.signatureData;
result += this.unhashedSubpackets ? this.unhashedSubpackets : util.writeNumber(0, 2);
arr.push(this.signatureData);
arr.push(this.unhashedSubpackets ? this.unhashedSubpackets : util.writeNumber(0, 2));
break;
}
result += this.signedHashValue + this.signature;
return result;
arr.push(this.signedHashValue);
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),
hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm);
var result = String.fromCharCode(4);
result += String.fromCharCode(signatureType);
result += String.fromCharCode(publicKeyAlgorithm);
result += String.fromCharCode(hashAlgorithm);
var arr = [new Uint8Array([4, signatureType, publicKeyAlgorithm, hashAlgorithm])];
this.issuerKeyId = key.getKeyId();
// 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 toHash = this.toSign(signatureType, data) +
this.signatureData + trailer;
var toHash = util.Uint8Array2str(util.concatUint8Array([this.toSign(signatureType, data), this.signatureData, trailer]));
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,
publicKeyAlgorithm, key.mpi, toHash);
this.signature = util.str2Uint8Array(crypto.signature.sign(hashAlgorithm,
publicKeyAlgorithm, key.mpi, util.str2Uint8Array(toHash)));
};
/**
@ -246,108 +240,108 @@ Signature.prototype.sign = function (key, data) {
*/
Signature.prototype.write_all_sub_packets = function () {
var sub = enums.signatureSubpacket;
var result = '';
var bytes = '';
var arr = [];
var bytes;
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) {
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) {
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) {
bytes = String.fromCharCode(this.trustLevel) + String.fromCharCode(this.trustAmount);
result += write_sub_packet(sub.trust_signature, bytes);
bytes = new Uint8Array([this.trustLevel,this.trustAmount]);;
arr.push(write_sub_packet(sub.trust_signature, bytes));
}
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) {
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) {
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) {
bytes = util.bin2str(this.preferredSymmetricAlgorithms);
result += write_sub_packet(sub.preferred_symmetric_algorithms, bytes);
bytes = util.str2Uint8Array(util.bin2str(this.preferredSymmetricAlgorithms));
arr.push(write_sub_packet(sub.preferred_symmetric_algorithms, bytes));
}
if (this.revocationKeyClass !== null) {
bytes = String.fromCharCode(this.revocationKeyClass);
bytes += String.fromCharCode(this.revocationKeyAlgorithm);
bytes += this.revocationKeyFingerprint;
result += write_sub_packet(sub.revocation_key, bytes);
bytes = new Uint8Array([this.revocationKeyClass, this.revocationKeyAlgorithm]);
bytes = util.concatUint8Array([bytes, this.revocationKeyFingerprint]);
arr.push(write_sub_packet(sub.revocation_key, bytes));
}
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) {
for (var name in this.notation) {
if (this.notation.hasOwnProperty(name)) {
var value = this.notation[name];
bytes = String.fromCharCode(0x80);
bytes += String.fromCharCode(0);
bytes += String.fromCharCode(0);
bytes += String.fromCharCode(0);
bytes = [new Uint8Array([0x80, 0, 0, 0])];
// 2 octets of name length
bytes += util.writeNumber(name.length, 2);
bytes.push(util.writeNumber(name.length, 2));
// 2 octets of value length
bytes += util.writeNumber(value.length, 2);
bytes += name + value;
result += write_sub_packet(sub.notation_data, bytes);
bytes.push(util.writeNumber(value.length, 2));
bytes.push(util.str2Uint8Array(name + value));
bytes = concatUint8Array(bytes);
arr.push(write_sub_packet(sub.notation_data, bytes));
}
}
}
if (this.preferredHashAlgorithms !== null) {
bytes = util.bin2str(this.preferredHashAlgorithms);
result += write_sub_packet(sub.preferred_hash_algorithms, bytes);
bytes = util.str2Uint8Array(util.bin2str(this.preferredHashAlgorithms));
arr.push(write_sub_packet(sub.preferred_hash_algorithms, bytes));
}
if (this.preferredCompressionAlgorithms !== null) {
bytes = util.bin2str(this.preferredCompressionAlgorithms);
result += write_sub_packet(sub.preferred_compression_algorithms, bytes);
bytes = util.str2Uint8Array(util.bin2str(this.preferredCompressionAlgorithms));
arr.push(write_sub_packet(sub.preferred_compression_algorithms, bytes));
}
if (this.keyServerPreferences !== null) {
bytes = util.bin2str(this.keyServerPreferences);
result += write_sub_packet(sub.key_server_preferences, bytes);
bytes = util.str2Uint8Array(util.bin2str(this.keyServerPreferences));
arr.push(write_sub_packet(sub.key_server_preferences, bytes));
}
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) {
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) {
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) {
bytes = util.bin2str(this.keyFlags);
result += write_sub_packet(sub.key_flags, bytes);
bytes = util.str2Uint8Array(util.bin2str(this.keyFlags));
arr.push(write_sub_packet(sub.key_flags, bytes));
}
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) {
bytes = String.fromCharCode(this.reasonForRevocationFlag);
bytes += this.reasonForRevocationString;
result += write_sub_packet(sub.reason_for_revocation, bytes);
bytes = util.str2Uint8Array(String.fromCharCode(this.reasonForRevocationFlag) + this.reasonForRevocationString);
arr.push(write_sub_packet(sub.reason_for_revocation, bytes));
}
if (this.features !== null) {
bytes = util.bin2str(this.features);
result += write_sub_packet(sub.features, bytes);
bytes = util.str2Uint8Array(util.bin2str(this.features));
arr.push(write_sub_packet(sub.features, bytes));
}
if (this.signatureTargetPublicKeyAlgorithm !== null) {
bytes = String.fromCharCode(this.signatureTargetPublicKeyAlgorithm);
bytes += String.fromCharCode(this.signatureTargetHashAlgorithm);
bytes += this.signatureTargetHash;
result += write_sub_packet(sub.signature_target, bytes);
bytes = [new Uint8Array([this.signatureTargetPublicKeyAlgorithm, this.signatureTargetHashAlgorithm])];
bytes.push(util.str2Uint8Array(this.signatureTargetHash));
bytes = util.concatUint8Array(bytes);
arr.push(write_sub_packet(sub.signature_target, bytes));
}
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})
*/
function write_sub_packet(type, data) {
var result = "";
result += packet.writeSimpleLength(data.length + 1);
result += String.fromCharCode(type);
result += data;
return result;
var arr = [];
arr.push(packet.writeSimpleLength(data.length + 1));
arr.push(new Uint8Array([type]));
arr.push(data);
return util.concatUint8Array(arr);
}
// V4 signature sub packets
@ -374,23 +368,23 @@ Signature.prototype.read_sub_packet = function (bytes) {
this[prop] = [];
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.
var type = bytes.charCodeAt(mypos++) & 0x7F;
var type = bytes[mypos++] & 0x7F;
var seconds;
// subpacket type
switch (type) {
case 2:
// Signature Creation Time
this.created = util.readDate(bytes.substr(mypos));
this.created = util.readDate(bytes.subarray(mypos, bytes.length));
break;
case 3:
// Signature Expiration Time in seconds
seconds = util.readNumber(bytes.substr(mypos));
seconds = util.readNumber(bytes.subarray(mypos, bytes.length));
this.signatureNeverExpires = seconds === 0;
this.signatureExpirationTime = seconds;
@ -398,24 +392,24 @@ Signature.prototype.read_sub_packet = function (bytes) {
break;
case 4:
// Exportable Certification
this.exportable = bytes.charCodeAt(mypos++) == 1;
this.exportable = bytes[mypos++] == 1;
break;
case 5:
// Trust Signature
this.trustLevel = bytes.charCodeAt(mypos++);
this.trustAmount = bytes.charCodeAt(mypos++);
this.trustLevel = bytes[mypos++];
this.trustAmount = bytes[mypos++];
break;
case 6:
// Regular Expression
this.regularExpression = bytes.substr(mypos);
this.regularExpression = bytes[mypos];
break;
case 7:
// Revocable
this.revocable = bytes.charCodeAt(mypos++) == 1;
this.revocable = bytes[mypos++] == 1;
break;
case 9:
// Key Expiration Time in seconds
seconds = util.readNumber(bytes.substr(mypos));
seconds = util.readNumber(bytes.subarray(mypos, bytes.length));
this.keyExpirationTime = seconds;
this.keyNeverExpires = seconds === 0;
@ -423,59 +417,59 @@ Signature.prototype.read_sub_packet = function (bytes) {
break;
case 11:
// Preferred Symmetric Algorithms
read_array.call(this, 'preferredSymmetricAlgorithms', bytes.substr(mypos));
read_array.call(this, 'preferredSymmetricAlgorithms', bytes.subarray(mypos, bytes.length));
break;
case 12:
// Revocation Key
// (1 octet of class, 1 octet of public-key algorithm ID, 20
// octets of
// fingerprint)
this.revocationKeyClass = bytes.charCodeAt(mypos++);
this.revocationKeyAlgorithm = bytes.charCodeAt(mypos++);
this.revocationKeyFingerprint = bytes.substr(mypos, 20);
this.revocationKeyClass = bytes[mypos++];
this.revocationKeyAlgorithm = bytes[mypos++];
this.revocationKeyFingerprint = bytes.subarray(mypos, 20);
break;
case 16:
// Issuer
this.issuerKeyId.read(bytes.substr(mypos));
this.issuerKeyId.read(bytes.subarray(mypos, bytes.length));
break;
case 20:
// Notation 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.
mypos += 4;
var m = util.readNumber(bytes.substr(mypos, 2));
var m = util.readNumber(bytes.subarray(mypos, mypos + 2));
mypos += 2;
var n = util.readNumber(bytes.substr(mypos, 2));
var n = util.readNumber(bytes.subarray(mypos, mypos + 2));
mypos += 2;
var name = bytes.substr(mypos, m),
value = bytes.substr(mypos + m, n);
var name = util.Uint8Array2str(bytes.subarray(mypos, mypos + m)),
value = util.Uint8Array2str(bytes.subarray(mypos + m, mypos + m + n));
this.notation = this.notation || {};
this.notation[name] = value;
} else {
util.print_debug("Unsupported notation flag "+bytes.charCodeAt(mypos));
util.print_debug("Unsupported notation flag "+bytes[mypos]);
}
break;
case 21:
// Preferred Hash Algorithms
read_array.call(this, 'preferredHashAlgorithms', bytes.substr(mypos));
read_array.call(this, 'preferredHashAlgorithms', bytes.subarray(mypos, bytes.length));
break;
case 22:
// Preferred Compression Algorithms
read_array.call(this, 'preferredCompressionAlgorithms', bytes.substr(mypos));
read_array.call(this, 'preferredCompressionAlgorithms', bytes.subarray(mypos, bytes.length));
break;
case 23:
// Key Server Preferences
read_array.call(this, 'keyServerPreferencess', bytes.substr(mypos));
read_array.call(this, 'keyServerPreferencess', bytes.subarray(mypos, bytes.length));
break;
case 24:
// Preferred Key Server
this.preferredKeyServer = bytes.substr(mypos);
this.preferredKeyServer = util.Uint8Array2str(bytes.subarray(mypos, bytes.length));
break;
case 25:
// Primary User ID
@ -483,39 +477,39 @@ Signature.prototype.read_sub_packet = function (bytes) {
break;
case 26:
// Policy URI
this.policyURI = bytes.substr(mypos);
this.policyURI = util.Uint8Array2str(bytes.subarray(mypos, bytes.length));
break;
case 27:
// Key Flags
read_array.call(this, 'keyFlags', bytes.substr(mypos));
read_array.call(this, 'keyFlags', bytes.subarray(mypos, bytes.length));
break;
case 28:
// Signer's User ID
this.signersUserId += bytes.substr(mypos);
this.signersUserId += util.Uint8Array2str(bytes.subarray(mypos, bytes.length));
break;
case 29:
// Reason for Revocation
this.reasonForRevocationFlag = bytes.charCodeAt(mypos++);
this.reasonForRevocationString = bytes.substr(mypos);
this.reasonForRevocationFlag = bytes[mypos++];
this.reasonForRevocationString = util.Uint8Array2str(bytes.subarray(mypos, bytes.length));
break;
case 30:
// Features
read_array.call(this, 'features', bytes.substr(mypos));
read_array.call(this, 'features', bytes.subarray(mypos, bytes.length));
break;
case 31:
// Signature Target
// (1 octet public-key algorithm, 1 octet hash algorithm, N octets hash)
this.signatureTargetPublicKeyAlgorithm = bytes.charCodeAt(mypos++);
this.signatureTargetHashAlgorithm = bytes.charCodeAt(mypos++);
this.signatureTargetPublicKeyAlgorithm = bytes[mypos++];
this.signatureTargetHashAlgorithm = bytes[mypos++];
var len = crypto.getHashByteLength(this.signatureTargetHashAlgorithm);
this.signatureTargetHash = bytes.substr(mypos, len);
this.signatureTargetHash = util.Uint8Array2str(bytes.subarray(mypos, mypos + len));
break;
case 32:
// Embedded Signature
this.embeddedSignature = new Signature();
this.embeddedSignature.read(bytes.substr(mypos));
this.embeddedSignature.read(bytes.subarray(mypos, bytes.length));
break;
default:
util.print_debug("Unknown signature subpacket type " + type + " @:" + mypos);
@ -532,7 +526,7 @@ Signature.prototype.toSign = function (type, data) {
return data.getBytes();
case t.standalone:
return '';
return new Uint8Array(0);
case t.cert_generic:
case t.cert_persona:
@ -553,33 +547,32 @@ Signature.prototype.toSign = function (type, data) {
var bytes = packet.write();
if (this.version == 4) {
return this.toSign(t.key, data) +
String.fromCharCode(tag) +
util.writeNumber(bytes.length, 4) +
bytes;
return util.concatUint8Array([this.toSign(t.key, data),
new Uint8Array([tag]),
util.writeNumber(bytes.length, 4),
bytes]);
} else if (this.version == 3) {
return this.toSign(t.key, data) +
bytes;
return util.concatUint8Array([this.toSign(t.key, data),
bytes]);
}
break;
case t.subkey_binding:
case t.subkey_revocation:
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
});
})]);
case t.key:
if (data.key === undefined)
throw new Error('Key packet is required for this signature.');
return data.key.writeOld();
case t.key_revocation:
return this.toSign(t.key, data);
case t.timestamp:
return '';
return new Uint8Array(0);
case t.third_party:
throw new Error('Not implemented');
default:
@ -590,13 +583,10 @@ Signature.prototype.toSign = function (type, data) {
Signature.prototype.calculateTrailer = function () {
// calculating the trailer
var trailer = '';
// V3 signatures don't have a trailer
if (this.version == 3) return trailer;
trailer += String.fromCharCode(4); // Version
trailer += String.fromCharCode(0xFF);
trailer += util.writeNumber(this.signatureData.length, 4);
return trailer;
if (this.version == 3) return new Uint8Array(0);
var first = new Uint8Array([4, 0xFF]); //Version, ?
return util.concatUint8Array([first, util.writeNumber(this.signatureData.length, 4)]);
};
@ -631,12 +621,12 @@ Signature.prototype.verify = function (key, data) {
i = 0;
for (var j = 0; j < mpicount; j++) {
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,
hashAlgorithm, mpi, key.mpi,
bytes + this.signatureData + trailer);
util.concatUint8Array([bytes, this.signatureData, trailer]));
return this.verified;
};

View File

@ -56,7 +56,7 @@ function SymEncryptedIntegrityProtected() {
SymEncryptedIntegrityProtected.prototype.read = function (bytes) {
// - A one-octet version number. The only currently defined value is 1.
var version = bytes.charCodeAt(0);
var version = bytes[0];
if (version != 1) {
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
// operating in Cipher Feedback mode with shift amount equal to the
// block size of the cipher (CFB-n where n is the block size).
this.encrypted = bytes.substr(1);
this.encrypted = bytes.subarray(1, bytes.length);
};
SymEncryptedIntegrityProtected.prototype.write = function () {
// 1 = Version
return String.fromCharCode(1) + this.encrypted;
return util.concatUint8Array([new Uint8Array([1]), this.encrypted]);
};
SymEncryptedIntegrityProtected.prototype.encrypt = function (sessionKeyAlgorithm, key) {
var bytes = this.packets.write();
var prefixrandom = crypto.getPrefixRandom(sessionKeyAlgorithm);
var prefix = prefixrandom + prefixrandom.charAt(prefixrandom.length - 2) + prefixrandom.charAt(prefixrandom.length -
1);
var tohash = bytes;
var repeat = new Uint8Array([prefixrandom[prefixrandom.length - 2], prefixrandom[prefixrandom.length - 1]]);
var prefix = util.concatUint8Array([prefixrandom, repeat]);
// Modification detection code packet.
tohash += String.fromCharCode(0xD3);
tohash += String.fromCharCode(0x14);
var mdc = new Uint8Array([0xD3, 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,
sessionKeyAlgorithm, tohash, key, false);
if (prefix.length + tohash.length != this.encrypted.length)
{
this.encrypted = this.encrypted.substring(0, prefix.length + tohash.length);
}
sessionKeyAlgorithm, tohash, key, false).subarray(0,
prefix.length + tohash.length);
};
/**
@ -114,20 +109,15 @@ SymEncryptedIntegrityProtected.prototype.decrypt = function (sessionKeyAlgorithm
var decrypted = crypto.cfb.decrypt(
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
// last packet and everything gets hashed except the hash itself
this.hash = crypto.hash.sha1(
crypto.cfb.mdc(sessionKeyAlgorithm, key, this.encrypted) + decrypted.join(''));
this.hash = crypto.hash.sha1(util.Uint8Array2str(util.concatUint8Array([crypto.cfb.mdc(sessionKeyAlgorithm, key, this.encrypted),
decrypted.subarray(0, decrypted.length - 20)])));
var mdc = util.Uint8Array2str(decrypted.subarray(decrypted.length - 20, decrypted.length));
if (this.hash != mdc) {
throw new Error('Modification detected.');
} else {
decrypted.splice(decrypted.length - 2);
this.packets.read(decrypted.join(''));
}
} else
this.packets.read(decrypted.subarray(0, decrypted.length - 22));
};

View File

@ -29,13 +29,15 @@
* 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
* decrypt the message.
* @requires util
* @requires crypto
* @requires enums
* @requires type/s2k
* @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'),
crypto = require('../crypto');
@ -57,7 +59,7 @@ function SymEncryptedSessionKey() {
/**
* 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} len
* Length of the packet or the remaining length of
@ -66,20 +68,20 @@ function SymEncryptedSessionKey() {
*/
SymEncryptedSessionKey.prototype.read = function(bytes) {
// 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.
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.
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
// with the string-to-key object.
var done = s2klength + 2;
if (done < bytes.length) {
this.encrypted = bytes.substr(done);
this.encrypted = bytes.subarray(done, bytes.length);
this.sessionKeyEncryptionAlgorithm = algo;
} else
this.sessionKeyAlgorithm = algo;
@ -90,12 +92,10 @@ SymEncryptedSessionKey.prototype.write = function() {
this.sessionKeyAlgorithm :
this.sessionKeyEncryptionAlgorithm;
var bytes = String.fromCharCode(this.version) +
String.fromCharCode(enums.write(enums.symmetric, algo)) +
this.s2k.write();
var bytes = util.concatUint8Array([new Uint8Array([this.version, enums.write(enums.symmetric, algo)]), this.s2k.write()]);
if (this.encrypted !== null)
bytes += this.encrypted;
bytes = util.concatUint8Array([bytes, this.encrypted]);
return bytes;
};
@ -103,7 +103,7 @@ SymEncryptedSessionKey.prototype.write = function() {
* Decrypts the session key (only for public key encrypted session key
* packets (tag 1)
*
* @return {String} The unencrypted session key
* @return {Uint8Array} The unencrypted session key
*/
SymEncryptedSessionKey.prototype.decrypt = function(passphrase) {
var algo = this.sessionKeyEncryptionAlgorithm !== null ?
@ -122,9 +122,9 @@ SymEncryptedSessionKey.prototype.decrypt = function(passphrase) {
algo, key, this.encrypted, null);
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 key = this.s2k.produce_key(passphrase, length);
var algo_enum = String.fromCharCode(
enums.write(enums.symmetric, this.sessionKeyAlgorithm));
var algo_enum = new Uint8Array([
enums.write(enums.symmetric, this.sessionKeyAlgorithm)]);
var private_key;
if(this.sessionKey === null) {
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(
algo, key, private_key, null);

View File

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

View File

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

View File

@ -64,30 +64,30 @@ S2K.prototype.get_count = function () {
*/
S2K.prototype.read = function (bytes) {
var i = 0;
this.type = enums.read(enums.s2k, bytes.charCodeAt(i++));
this.algorithm = enums.read(enums.hash, bytes.charCodeAt(i++));
this.type = enums.read(enums.s2k, bytes[i++]);
this.algorithm = enums.read(enums.hash, bytes[i++]);
switch (this.type) {
case 'simple':
break;
case 'salted':
this.salt = bytes.substr(i, 8);
this.salt = bytes.subarray(i, i + 8);
i += 8;
break;
case 'iterated':
this.salt = bytes.substr(i, 8);
this.salt = bytes.subarray(i, i + 8);
i += 8;
// Octet 10: count, a one-octet, coded value
this.c = bytes.charCodeAt(i++);
this.c = bytes[i++];
break;
case 'gnu':
if (bytes.substr(i, 3) == "GNU") {
if (util.Uint8Array2str(bytes.subarray(i, 3)) == "GNU") {
i += 3; // GNU
var gnuExtType = 1000 + bytes.charCodeAt(i++);
var gnuExtType = 1000 + bytes[i++];
if (gnuExtType == 1001) {
this.type = gnuExtType;
// 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.
* @return {String} Produced key of hashAlgorithm hash length
* Serializes s2k information
* @return {Uint8Array} binary representation of s2k
*/
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) {
case 'simple':
break;
case 'salted':
bytes += this.salt;
arr.push(this.salt);
break;
case 'iterated':
bytes += this.salt;
bytes += String.fromCharCode(this.c);
arr.push(this.salt);
arr.push(new Uint8Array([this.c]));
break;
case 'gnu':
throw new Error("GNU s2k type not supported.");
@ -131,14 +131,14 @@ S2K.prototype.write = function () {
throw new Error("Unknown s2k type.");
}
return bytes;
return util.concatUint8Array(arr);
};
/**
* Produces a key using the specified passphrase and the defined
* hashAlgorithm
* @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
*/
S2K.prototype.produce_key = function (passphrase, numBytes) {
@ -149,16 +149,16 @@ S2K.prototype.produce_key = function (passphrase, numBytes) {
switch (s2k.type) {
case 'simple':
return crypto.hash.digest(algorithm, prefix + passphrase);
return util.str2Uint8Array(crypto.hash.digest(algorithm, prefix + passphrase));
case 'salted':
return crypto.hash.digest(algorithm,
prefix + s2k.salt + passphrase);
return util.str2Uint8Array(crypto.hash.digest(algorithm,
prefix + util.Uint8Array2str(s2k.salt) + passphrase));
case 'iterated':
var isp = [],
count = s2k.get_count(),
data = s2k.salt + passphrase;
data = util.Uint8Array2str(s2k.salt) + passphrase;
while (isp.length * data.length < count)
isp.push(data);
@ -168,7 +168,7 @@ S2K.prototype.produce_key = function (passphrase, numBytes) {
if (isp.length > count)
isp = isp.substr(0, count);
return crypto.hash.digest(algorithm, prefix + isp);
return util.str2Uint8Array(crypto.hash.digest(algorithm, prefix + isp));
case 'gnu':
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 = '';
while (result.length <= numBytes) {
result += round(prefix, this);
while (rlength <= numBytes) {
var result = round(prefix, this);
arr.push(result);
rlength += result.length;
prefix += String.fromCharCode(0);
}
return result.substr(0, numBytes);
return util.concatUint8Array(arr).subarray(0, numBytes);
};
module.exports.fromClone = function (clone) {

View File

@ -31,16 +31,16 @@ module.exports = {
for (var i = 0; i < bytes.length; i++) {
n <<= 8;
n += bytes.charCodeAt(i);
n += bytes[i];
}
return n;
},
writeNumber: function (n, bytes) {
var b = '';
var b = new Uint8Array(bytes);
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;
@ -187,6 +187,12 @@ module.exports = {
* @return {Uint8Array} The array of (binary) integers
*/
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);
for (var i = 0; i < str.length; i++) {
result[i] = str.charCodeAt(i);
@ -202,6 +208,12 @@ module.exports = {
* @return {String} String representation of the array
*/
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 = [];
for (var i = 0; i < bin.length; 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
* @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
* codes % 65535
*/
@ -224,7 +309,7 @@ module.exports = {
}
};
for (var i = 0; i < text.length; i++) {
checksum.add(text.charCodeAt(i));
checksum.add(text[i]);
}
return checksum.s;
},

View File

@ -132,7 +132,7 @@ AsyncProxy.prototype.terminate = function() {
/**
* 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 {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 {Object} params parameter object with optional properties binary {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
* @param {String} sessionKey sessionKey as a binary string
* @param {Uint8Array} sessionKey sessionKey as Uint8Array
* @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<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
* @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 {String} text message as native JavaScript string
* @param {Uint8Array} text message as Uint8Array
*/
AsyncProxy.prototype.signAndEncryptMessage = function(publicKeys, privateKey, text) {
var self = this;
@ -299,7 +299,7 @@ AsyncProxy.prototype.decryptAndVerifyMessage = function(privateKey, publicKeys,
/**
* 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 {String} text cleartext
* @param {Uint8Array} text cleartext
*/
AsyncProxy.prototype.signClearMessage = function(privateKeys, text) {
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() {
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)));

View File

@ -8,7 +8,7 @@ var util = openpgp.util,
it('CAST-128 cipher test with test vectors from RFC2144', function (done) {
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));
return util.hexstrdump(result) == util.hexstrdump(util.bin2str(output));

View File

@ -7,7 +7,7 @@ var util = openpgp.util,
expect = chai.expect;
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]],
[[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]],
@ -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));
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]) +
' != ' + 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) {
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();
testvectors[0] = [[[0x01], [0x24, 0xC7, 0x4A, 0x9A, 0x79, 0x75, 0x4B, 0xC7]],
[[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);
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 +
'] should be ' + util.hexidump(thisVectorSet[i][1]) +
' - Actually [' + util.hexidump(encrypted) +
']').to.equal(util.bin2str(thisVectorSet[i][1]));
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 +
'] should be ' + util.hexidump(thisVectorSet[i][0]) +
' - 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) {
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);
}

View File

@ -8,7 +8,7 @@ var chai = require('chai'),
describe('API functional testing', function() {
var util = openpgp.util;
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,
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,
@ -28,9 +28,9 @@ describe('API functional testing', function() {
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,
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 = [
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,
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,
@ -50,7 +50,7 @@ describe('API functional testing', function() {
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,
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,
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,
@ -60,7 +60,7 @@ describe('API functional testing', function() {
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,
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,
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,
@ -70,7 +70,7 @@ describe('API functional testing', function() {
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,
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,
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,
@ -82,7 +82,7 @@ describe('API functional testing', function() {
0xe7,0xd6,0x76,0xea,0x0e,0x1a,0x90,0x30,0xf5,0x98,0x01,0xc5,0x73])];
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,
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,
@ -100,10 +100,10 @@ describe('API functional testing', function() {
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,
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,
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,
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,
@ -121,7 +121,7 @@ describe('API functional testing', function() {
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,
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,
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,
@ -140,12 +140,12 @@ describe('API functional testing', function() {
0xc3,0x26,0xae,0x9f,0xa9,0x67,0x49,0x96,0x5c,0x07,0x3e,0x47,0x5c,0xed,0x60,
0x07,0xac,0x6a])];
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,
0xdf,0xb8,0x8e,0x8e])];
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,
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,
@ -163,8 +163,8 @@ describe('API functional testing', function() {
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,
0x27,0x62,0x77]),
util.bin2str([0x00,0x03,0x05]),
util.bin2str([0x07,0xff,0x57,0x19,0x76,0xfc,0x09,0x6a,0x7a,0xf7,0xba,0xb2,0x42,0xbf,0xcd,
new Uint8Array([0x00,0x03,0x05]),
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,
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,
@ -184,7 +184,7 @@ describe('API functional testing', function() {
0xda,0x6b,0xca])];
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,
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]);
}
var data = util.str2Uint8Array("foobar");
describe('Sign and verify', function () {
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?
// 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();
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;
done();
});
it('DSA', function (done) {
// 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 = [];
DSAmsgMPIs[0] = new openpgp.MPI();
DSAmsgMPIs[1] = new openpgp.MPI();
DSAmsgMPIs[0].read(DSAsignedData.substring(0,34));
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;
done();
});
@ -260,8 +262,8 @@ describe('API functional testing', function() {
function testCFB(plaintext, resync) {
symmAlgos.forEach(function(algo) {
var symmKey = openpgp.crypto.generateSessionKey(algo);
var symmencData = openpgp.crypto.cfb.encrypt(openpgp.crypto.getPrefixRandom(algo), algo, plaintext, symmKey, resync);
var text = openpgp.crypto.cfb.decrypt(algo, symmKey, symmencData, resync).join('');
var symmencData = openpgp.crypto.cfb.encrypt(openpgp.crypto.getPrefixRandom(algo), algo, util.str2Uint8Array(plaintext), symmKey, resync);
var text = util.Uint8Array2str(openpgp.crypto.cfb.decrypt(algo, symmKey, symmencData, resync));
expect(text).to.equal(plaintext);
});
}
@ -281,23 +283,29 @@ describe('API functional testing', function() {
});
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();
RSAUnencryptedData.fromBytes(openpgp.crypto.pkcs1.eme.encode(symmKey, RSApubMPIs[0].byteLength()));
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);
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();
ElgamalUnencryptedData.fromBytes(openpgp.crypto.pkcs1.eme.encode(symmKey, ElgamalpubMPIs[0].byteLength()));
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);
done();
});

View File

@ -122,7 +122,7 @@ describe('Basic', function() {
}
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 passphrase = 'password';
@ -147,7 +147,7 @@ describe('Basic', function() {
// sign and encrypt
var msg, encrypted;
msg = openpgp.message.fromBinary(message, "test.txt");
msg = openpgp.message.fromText(message, "test.txt");
msg = msg.sign([privKey]);
msg = msg.encrypt([pubKey]);
encrypted = openpgp.armor.encode(openpgp.enums.armor.message, msg.packets.write());
@ -171,6 +171,9 @@ describe('Basic', function() {
expect(decrypted.text).to.equal(message);
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) {
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);
message = openpgp.message.readArmored(encrypted);

View File

@ -2,6 +2,18 @@
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'),
expect = chai.expect;
@ -53,8 +65,8 @@ describe("Packet", function() {
message.push(enc);
enc.packets.push(literal);
var key = '123456789012345678901234',
algo = 'tripledes';
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';
enc.encrypt(algo, key);
@ -62,7 +74,7 @@ describe("Packet", function() {
msg2.read(message.write());
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();
});
@ -87,7 +99,7 @@ describe("Packet", function() {
});
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';
var literal = new openpgp.packet.Literal(),
@ -104,7 +116,7 @@ describe("Packet", function() {
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();
});
@ -129,7 +141,7 @@ describe("Packet", function() {
parsed[1].decrypt(parsed[0].sessionKeyAlgorithm, key);
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');
done();
@ -152,7 +164,7 @@ describe("Packet", function() {
msg = 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.sessionKeyAlgorithm = 'aes256';
enc.publicKeyId.bytes = '12345678';
@ -164,13 +176,13 @@ describe("Packet", function() {
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);
done();
});
});
it('Secret key packet (reading, unencrpted)', function(done) {
it('Secret key packet (reading, unencrypted)', function(done) {
var armored_key =
'-----BEGIN PGP PRIVATE KEY BLOCK-----\n' +
'Version: GnuPG v2.0.19 (GNU/Linux)\n' +
@ -198,7 +210,7 @@ describe("Packet", function() {
key = key[0];
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.publicKeyAlgorithm = 'rsa_encrypt';
@ -209,7 +221,7 @@ describe("Packet", function() {
enc.decrypt(key);
expect(enc.sessionKey).to.equal(secret);
expect(stringify(enc.sessionKey)).to.equal(stringify(secret));
done();
});
@ -271,7 +283,7 @@ describe("Packet", function() {
msg[0].decrypt(key);
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!');
done();
@ -306,7 +318,7 @@ describe("Packet", function() {
var key2 = msg2[0].sessionKey;
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();
});
@ -334,7 +346,7 @@ describe("Packet", function() {
msg[0].decrypt(key);
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!');
done();

View File

@ -189,7 +189,11 @@ describe('Init Worker', function() {
openpgp.getWorker().decryptKeyPacket(privKeyRSA, [privKeyRSA.primaryKey.getKeyId()], 'hello world').then(function(key) {
expect(key.primaryKey.isDecrypted).to.be.true;
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) {
return openpgp.encryptSessionKey(sk.key, sk.algo, pubKeyRSA);
}).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);
}).then(function(data) {
expect(data).to.exist;
@ -333,7 +337,7 @@ describe('High level API', function() {
openpgp.decryptSessionKey(password1, msgAES).then(function(sk) {
return openpgp.encryptSessionKey(sk.key, sk.algo, [], password2);
}).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);
}).then(function(data) {
expect(data).to.exist;