Comparing version 0.4.1 to 0.5.0
{ | ||
"name": "openpgp", | ||
"description": "OpenPGP.js is a Javascript implementation of the OpenPGP protocol. This is defined in RFC 4880.", | ||
"version": "0.4.1", | ||
"version": "0.5.0", | ||
"homepage": "http://openpgpjs.org/", | ||
@@ -39,5 +39,5 @@ "engines": { | ||
"grunt-browserify": "~1.2.11", | ||
"grunt-contrib-uglify": "*", | ||
"grunt-text-replace": "*", | ||
"grunt-jsbeautifier": "*", | ||
"grunt-contrib-uglify": "~0.3.2", | ||
"grunt-text-replace": "~0.3.11", | ||
"grunt-jsbeautifier": "~0.2.6", | ||
"grunt-contrib-jshint": "*", | ||
@@ -44,0 +44,0 @@ "grunt-jsdoc": "*", |
@@ -42,3 +42,3 @@ // GPG4Browsers - An OpenPGP implementation in javascript | ||
if (!(this instanceof CleartextMessage)) { | ||
return new CleartextMessage(packetlist); | ||
return new CleartextMessage(text, packetlist); | ||
} | ||
@@ -146,2 +146,3 @@ // normalize EOL to canonical form <CR><LF> | ||
packetlist.read(input.data); | ||
verifyHeaders(input.headers, packetlist); | ||
var newMessage = new CleartextMessage(input.text, packetlist); | ||
@@ -151,3 +152,48 @@ return newMessage; | ||
/** | ||
* Compare hash algorithm specified in the armor header with signatures | ||
* @private | ||
* @param {Array<String>} headers Armor headers | ||
* @param {module:packet/packetlist} packetlist The packetlist with signature packets | ||
*/ | ||
function verifyHeaders(headers, packetlist) { | ||
var checkHashAlgos = function(hashAlgos) { | ||
for (var i = 0; i < packetlist.length; i++) { | ||
if (packetlist[i].tag === enums.packet.signature && | ||
!hashAlgos.some(function(algo) { | ||
return packetlist[i].hashAlgorithm === algo; | ||
})) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
var oneHeader = null; | ||
var hashAlgos = []; | ||
for (var i = 0; i < headers.length; i++) { | ||
oneHeader = headers[i].match(/Hash: (.+)/); // get header value | ||
if (oneHeader) { | ||
oneHeader = oneHeader[1].replace(/\s/g, ''); // remove whitespace | ||
oneHeader = oneHeader.split(','); | ||
oneHeader = oneHeader.map(function(hash) { | ||
hash = hash.toLowerCase(); | ||
try { | ||
return enums.write(enums.hash, hash); | ||
} catch (e) { | ||
throw new Error('Unknown hash algorithm in armor header: ' + hash); | ||
} | ||
}); | ||
hashAlgos = hashAlgos.concat(oneHeader); | ||
} else { | ||
throw new Error('Only "Hash" header allowed in cleartext signed message'); | ||
} | ||
} | ||
if (!hashAlgos.length && !checkHashAlgos([enums.hash.md5])) { | ||
throw new Error('If no "Hash" header in cleartext signed message, then only MD5 signatures allowed'); | ||
} else if (!checkHashAlgos(hashAlgos)) { | ||
throw new Error('Hash algorithm mismatch in armor header and signature'); | ||
} | ||
} | ||
exports.CleartextMessage = CleartextMessage; | ||
exports.readArmored = readArmored; |
@@ -38,10 +38,11 @@ // GPG4Browsers - An OpenPGP implementation in javascript | ||
compression: enums.compression.zip, | ||
integrity_protect: true, | ||
rsa_blinding: true, | ||
show_version: true, | ||
show_comment: true, | ||
integrity_protect: true, | ||
keyserver: "keyserver.linux.it", // "pgp.mit.edu:11371" | ||
versionstring: "OpenPGP.js VERSION", | ||
commentstring: "http://openpgpjs.org", | ||
keyserver: "keyserver.linux.it", // "pgp.mit.edu:11371" | ||
node_store: './openpgp.store', | ||
@@ -48,0 +49,0 @@ |
@@ -460,23 +460,18 @@ /* Rijndael (AES) Encryption | ||
function AESencrypt(block, ctx) { | ||
var r; | ||
var t0, t1, t2, t3; | ||
function AESencrypt(block, ctx, t) { | ||
var r, rounds, b; | ||
var b = packBytes(block); | ||
var rounds = ctx.rounds; | ||
var b0 = b[0]; | ||
var b1 = b[1]; | ||
var b2 = b[2]; | ||
var b3 = b[3]; | ||
b = packBytes(block); | ||
rounds = ctx.rounds; | ||
for (r = 0; r < rounds - 1; r++) { | ||
t0 = b0 ^ ctx.rk[r][0]; | ||
t1 = b1 ^ ctx.rk[r][1]; | ||
t2 = b2 ^ ctx.rk[r][2]; | ||
t3 = b3 ^ ctx.rk[r][3]; | ||
t[0] = b[0] ^ ctx.rk[r][0]; | ||
t[1] = b[1] ^ ctx.rk[r][1]; | ||
t[2] = b[2] ^ ctx.rk[r][2]; | ||
t[3] = b[3] ^ ctx.rk[r][3]; | ||
b0 = T1[t0 & 255] ^ T2[(t1 >> 8) & 255] ^ T3[(t2 >> 16) & 255] ^ T4[t3 >>> 24]; | ||
b1 = T1[t1 & 255] ^ T2[(t2 >> 8) & 255] ^ T3[(t3 >> 16) & 255] ^ T4[t0 >>> 24]; | ||
b2 = T1[t2 & 255] ^ T2[(t3 >> 8) & 255] ^ T3[(t0 >> 16) & 255] ^ T4[t1 >>> 24]; | ||
b3 = T1[t3 & 255] ^ T2[(t0 >> 8) & 255] ^ T3[(t1 >> 16) & 255] ^ T4[t2 >>> 24]; | ||
b[0] = T1[t[0] & 255] ^ T2[(t[1] >> 8) & 255] ^ T3[(t[2] >> 16) & 255] ^ T4[t[3] >>> 24]; | ||
b[1] = T1[t[1] & 255] ^ T2[(t[2] >> 8) & 255] ^ T3[(t[3] >> 16) & 255] ^ T4[t[0] >>> 24]; | ||
b[2] = T1[t[2] & 255] ^ T2[(t[3] >> 8) & 255] ^ T3[(t[0] >> 16) & 255] ^ T4[t[1] >>> 24]; | ||
b[3] = T1[t[3] & 255] ^ T2[(t[0] >> 8) & 255] ^ T3[(t[1] >> 16) & 255] ^ T4[t[2] >>> 24]; | ||
} | ||
@@ -487,11 +482,11 @@ | ||
t0 = b0 ^ ctx.rk[r][0]; | ||
t1 = b1 ^ ctx.rk[r][1]; | ||
t2 = b2 ^ ctx.rk[r][2]; | ||
t3 = b3 ^ ctx.rk[r][3]; | ||
t[0] = b[0] ^ ctx.rk[r][0]; | ||
t[1] = b[1] ^ ctx.rk[r][1]; | ||
t[2] = b[2] ^ ctx.rk[r][2]; | ||
t[3] = b[3] ^ ctx.rk[r][3]; | ||
b[0] = F1(t0, t1, t2, t3) ^ ctx.rk[rounds][0]; | ||
b[1] = F1(t1, t2, t3, t0) ^ ctx.rk[rounds][1]; | ||
b[2] = F1(t2, t3, t0, t1) ^ ctx.rk[rounds][2]; | ||
b[3] = F1(t3, t0, t1, t2) ^ ctx.rk[rounds][3]; | ||
b[0] = F1(t[0], t[1], t[2], t[3]) ^ ctx.rk[rounds][0]; | ||
b[1] = F1(t[1], t[2], t[3], t[0]) ^ ctx.rk[rounds][1]; | ||
b[2] = F1(t[2], t[3], t[0], t[1]) ^ ctx.rk[rounds][2]; | ||
b[3] = F1(t[3], t[0], t[1], t[2]) ^ ctx.rk[rounds][3]; | ||
@@ -505,5 +500,6 @@ return unpackBytes(b); | ||
this.key = keyExpansion(key); | ||
this._temp = new Uint32Array(this.blockSize / 4); | ||
this.encrypt = function(block) { | ||
return AESencrypt(block, this.key); | ||
return AESencrypt(block, this.key, this._temp); | ||
}; | ||
@@ -510,0 +506,0 @@ }; |
@@ -21,3 +21,7 @@ /** | ||
/** @see module:crypto/cipher/blowfish */ | ||
blowfish: require('./blowfish.js') | ||
blowfish: require('./blowfish.js'), | ||
/** Not implemented */ | ||
idea: function() { | ||
throw new Error('IDEA symmetric-key algorithm not implemented'); | ||
} | ||
}; | ||
@@ -24,0 +28,0 @@ |
@@ -33,6 +33,2 @@ /* Modified by Recurity Labs GmbH | ||
function rotb(b, n) { | ||
return (b << n | b >>> (8 - n)) & 0xFF; | ||
} | ||
function rotw(w, n) { | ||
@@ -58,20 +54,2 @@ return (w << n | w >>> (32 - n)) & MAXINT; | ||
function getNrBits(i) { | ||
var n = 0; | ||
while (i > 0) { | ||
n++; | ||
i >>>= 1; | ||
} | ||
return n; | ||
} | ||
function getMask(n) { | ||
return (1 << n) - 1; | ||
} | ||
//added 2008/11/13 XXX MUST USE ONE-WAY HASH FUNCTION FOR SECURITY REASON | ||
function randByte() { | ||
return Math.floor(Math.random() * 256); | ||
} | ||
// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
@@ -78,0 +56,0 @@ // Twofish |
@@ -96,2 +96,5 @@ // GPG4Browsers - An OpenPGP implementation in javascript | ||
// 0 and 1 are the public key. | ||
var n = keyIntegers[0].toBigInteger(); | ||
var e = keyIntegers[1].toBigInteger(); | ||
// 2 to 5 are the private key. | ||
var d = keyIntegers[2].toBigInteger(); | ||
@@ -102,3 +105,3 @@ p = keyIntegers[3].toBigInteger(); | ||
var m = dataIntegers[0].toBigInteger(); | ||
return rsa.decrypt(m, d, p, q, u); | ||
return rsa.decrypt(m, n, e, d, p, q, u); | ||
case 'elgamal': | ||
@@ -105,0 +108,0 @@ var elgamal = new publicKey.elgamal(); |
@@ -88,3 +88,3 @@ /* | ||
default: | ||
document.write("Bogus round number"); | ||
throw new Error("Bogus round number"); | ||
break; | ||
@@ -91,0 +91,0 @@ } |
@@ -90,3 +90,3 @@ /* A JavaScript implementation of the SHA family of hashes, as defined in FIPS | ||
} else { | ||
return "INVALID HEX STRING"; | ||
throw new Error("INVALID HEX STRING"); | ||
} | ||
@@ -874,3 +874,3 @@ } | ||
/* This should never be reached */ | ||
return []; | ||
throw new Error('Unknown SHA variant'); | ||
} | ||
@@ -901,3 +901,3 @@ }, | ||
if (0 !== (srcString.length % 2)) { | ||
return "TEXT MUST BE IN BYTE INCREMENTS"; | ||
throw new Error("TEXT MUST BE IN BYTE INCREMENTS"); | ||
} | ||
@@ -911,3 +911,3 @@ this.strBinLen = srcString.length * 4; | ||
} else { | ||
return "UNKNOWN TEXT INPUT TYPE"; | ||
throw new Error("UNKNOWN TEXT INPUT TYPE"); | ||
} | ||
@@ -941,3 +941,3 @@ }; | ||
default: | ||
return "FORMAT NOT RECOGNIZED"; | ||
throw new Error("FORMAT NOT RECOGNIZED"); | ||
} | ||
@@ -972,3 +972,3 @@ | ||
default: | ||
return "HASH NOT RECOGNIZED"; | ||
throw new Error("HASH NOT RECOGNIZED"); | ||
} | ||
@@ -1007,3 +1007,3 @@ }, | ||
default: | ||
return "FORMAT NOT RECOGNIZED"; | ||
throw new Error("FORMAT NOT RECOGNIZED"); | ||
} | ||
@@ -1034,3 +1034,3 @@ | ||
default: | ||
return "HASH NOT RECOGNIZED"; | ||
throw new Error("HASH NOT RECOGNIZED"); | ||
} | ||
@@ -1042,3 +1042,3 @@ | ||
if (0 !== (key.length % 2)) { | ||
return "KEY MUST BE IN BYTE INCREMENTS"; | ||
throw new Error("KEY MUST BE IN BYTE INCREMENTS"); | ||
} | ||
@@ -1051,3 +1051,3 @@ keyToUse = hex2binb(key); | ||
} else { | ||
return "UNKNOWN KEY INPUT TYPE"; | ||
throw new Error("UNKNOWN KEY INPUT TYPE"); | ||
} | ||
@@ -1054,0 +1054,0 @@ |
@@ -31,3 +31,3 @@ // GPG4Browsers - An OpenPGP implementation in javascript | ||
*/ | ||
hash_headers = []; | ||
var hash_headers = []; | ||
hash_headers[1] = [0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, | ||
@@ -47,3 +47,3 @@ 0x10 | ||
]; | ||
hash_headers[11] = [0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, | ||
hash_headers[11] = [0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, | ||
0x00, 0x04, 0x1C | ||
@@ -58,2 +58,21 @@ ]; | ||
/** | ||
* Create padding with secure random data | ||
* @private | ||
* @param {Integer} length Length of the padding in bytes | ||
* @return {String} Padding as string | ||
*/ | ||
function getPkcs1Padding(length) { | ||
var result = ''; | ||
var randomByte; | ||
while (result.length < length) { | ||
randomByte = random.getSecureRandomOctet(); | ||
if (randomByte !== 0) { | ||
result += String.fromCharCode(randomByte); | ||
} | ||
} | ||
return result; | ||
} | ||
module.exports = { | ||
@@ -63,34 +82,47 @@ eme: { | ||
* create a EME-PKCS1-v1_5 padding (See {@link http://tools.ietf.org/html/rfc4880#section-13.1.1|RFC 4880 13.1.1}) | ||
* @param {String} message message to be padded | ||
* @param {Integer} length Length to the resulting message | ||
* @param {String} M message to be encoded | ||
* @param {Integer} k the length in octets of the key modulus | ||
* @return {String} EME-PKCS1 padded message | ||
*/ | ||
encode: function(message, length) { | ||
if (message.length > length - 11) | ||
return -1; | ||
var result = ""; | ||
result += String.fromCharCode(0); | ||
result += String.fromCharCode(2); | ||
for (var i = 0; i < length - message.length - 3; i++) { | ||
result += String.fromCharCode(random.getPseudoRandom(1, 255)); | ||
encode: function(M, k) { | ||
var mLen = M.length; | ||
// length checking | ||
if (mLen > k - 11) { | ||
throw new Error('Message too long'); | ||
} | ||
result += String.fromCharCode(0); | ||
result += message; | ||
return result; | ||
// Generate an octet string PS of length k - mLen - 3 consisting of | ||
// pseudo-randomly generated nonzero octets | ||
var PS = getPkcs1Padding(k - mLen - 3); | ||
// Concatenate PS, the message M, and other padding to form an | ||
// encoded message EM of length k octets as EM = 0x00 || 0x02 || PS || 0x00 || M. | ||
var EM = String.fromCharCode(0) + | ||
String.fromCharCode(2) + | ||
PS + | ||
String.fromCharCode(0) + | ||
M; | ||
return EM; | ||
}, | ||
/** | ||
* decodes a EME-PKCS1-v1_5 padding (See {@link http://tools.ietf.org/html/rfc4880#section-13.1.2|RFC 4880 13.1.2}) | ||
* @param {String} message EME-PKCS1 padded message | ||
* @return {String} decoded message | ||
* @param {String} EM encoded message, an octet string | ||
* @return {String} message, an octet string | ||
*/ | ||
decode: function(message, len) { | ||
if (message.length < len) | ||
message = String.fromCharCode(0) + message; | ||
if (message.length < 12 || message.charCodeAt(0) !== 0 || message.charCodeAt(1) != 2) | ||
return -1; | ||
decode: function(EM) { | ||
// leading zeros truncated by jsbn | ||
if (EM.charCodeAt(0) !== 0) { | ||
EM = String.fromCharCode(0) + EM; | ||
} | ||
var firstOct = EM.charCodeAt(0); | ||
var secondOct = EM.charCodeAt(1); | ||
var i = 2; | ||
while (message.charCodeAt(i) !== 0 && message.length > i) | ||
while (EM.charCodeAt(i) !== 0 && i < EM.length) { | ||
i++; | ||
return message.substring(i + 1, message.length); | ||
} | ||
var psLen = i - 2; | ||
var separator = EM.charCodeAt(i++); | ||
if (firstOct === 0 && secondOct === 2 && psLen >= 8 && separator === 0) { | ||
return EM.substr(i); | ||
} else { | ||
throw new Error('Decryption error'); | ||
} | ||
} | ||
@@ -100,51 +132,45 @@ }, | ||
emsa: { | ||
/** | ||
* create a EMSA-PKCS1-v1_5 padding (See {@link http://tools.ietf.org/html/rfc4880#section-13.1.3|RFC 4880 13.1.3}) | ||
* @param {Integer} algo Hash algorithm type used | ||
* @param {String} data Data to be hashed | ||
* @param {Integer} keylength Key size of the public mpi in bytes | ||
* @returns {String} Hashcode with pkcs1padding as string | ||
* @param {String} M message to be encoded | ||
* @param {Integer} emLen intended length in octets of the encoded message | ||
* @returns {String} encoded message | ||
*/ | ||
encode: function(algo, data, keylength) { | ||
var data2 = ""; | ||
data2 += String.fromCharCode(0x00); | ||
data2 += String.fromCharCode(0x01); | ||
encode: function(algo, M, emLen) { | ||
var i; | ||
for (i = 0; i < (keylength - hash_headers[algo].length - 3 - | ||
hash.getHashByteLength(algo)); i++) | ||
data2 += String.fromCharCode(0xff); | ||
data2 += String.fromCharCode(0x00); | ||
for (i = 0; i < hash_headers[algo].length; i++) | ||
data2 += String.fromCharCode(hash_headers[algo][i]); | ||
data2 += hash.digest(algo, data); | ||
return new BigInteger(util.hexstrdump(data2), 16); | ||
}, | ||
/** | ||
* extract the hash out of an EMSA-PKCS1-v1.5 padding (See {@link http://tools.ietf.org/html/rfc4880#section-13.1.3|RFC 4880 13.1.3}) | ||
* @param {String} data Hash in pkcs1 encoding | ||
* @returns {String} The hash as string | ||
*/ | ||
decode: function(algo, data) { | ||
var i = 0; | ||
if (data.charCodeAt(0) === 0) i++; | ||
else if (data.charCodeAt(0) != 1) return -1; | ||
else i++; | ||
while (data.charCodeAt(i) == 0xFF) i++; | ||
if (data.charCodeAt(i++) !== 0) return -1; | ||
var j = 0; | ||
for (j = 0; j < hash_headers[algo].length && j + i < data.length; j++) { | ||
if (data.charCodeAt(j + i) != hash_headers[algo][j]) return -1; | ||
// Apply the hash function to the message M to produce a hash value H | ||
var H = hash.digest(algo, M); | ||
if (H.length !== hash.getHashByteLength(algo)) { | ||
throw new Error('Invalid hash length'); | ||
} | ||
i += j; | ||
if (data.substring(i).length < hash.getHashByteLength(algo)) return -1; | ||
return data.substring(i); | ||
// produce an ASN.1 DER value for the hash function used. | ||
// Let T be the full hash prefix | ||
var T = ''; | ||
for (i = 0; i < hash_headers[algo].length; i++) { | ||
T += String.fromCharCode(hash_headers[algo][i]); | ||
} | ||
// add hash value to prefix | ||
T += H; | ||
// and let tLen be the length in octets of T | ||
var tLen = T.length; | ||
if (emLen < tLen + 11) { | ||
throw new Error('Intended encoded message length too short'); | ||
} | ||
// an octet string PS consisting of emLen - tLen - 3 octets with hexadecimal value 0xFF | ||
// The length of PS will be at least 8 octets | ||
var PS = ''; | ||
for (i = 0; i < (emLen - tLen - 3); i++) { | ||
PS += String.fromCharCode(0xff); | ||
} | ||
// Concatenate PS, the hash prefix T, and other padding to form the | ||
// encoded message EM as EM = 0x00 || 0x01 || PS || 0x00 || T. | ||
var EM = String.fromCharCode(0x00) + | ||
String.fromCharCode(0x01) + | ||
PS + | ||
String.fromCharCode(0x00) + | ||
T; | ||
return new BigInteger(util.hexstrdump(EM), 16); | ||
} | ||
} | ||
}; |
@@ -45,5 +45,16 @@ // GPG4Browsers - An OpenPGP implementation in javascript | ||
var hash = new BigInteger(util.hexstrdump(hashed_data), 16); | ||
var k = random.getRandomBigIntegerInRange(BigInteger.ONE.add(BigInteger.ONE), q.subtract(BigInteger.ONE)); | ||
var s1 = (g.modPow(k, p)).mod(q); | ||
var s2 = (k.modInverse(q).multiply(hash.add(x.multiply(s1)))).mod(q); | ||
// FIPS-186-4, section 4.6: | ||
// The values of r and s shall be checked to determine if r = 0 or s = 0. | ||
// If either r = 0 or s = 0, a new value of k shall be generated, and the | ||
// signature shall be recalculated. It is extremely unlikely that r = 0 | ||
// or s = 0 if signatures are generated properly. | ||
var k, s1, s2; | ||
while (true) { | ||
k = random.getRandomBigIntegerInRange(BigInteger.ONE, q.subtract(BigInteger.ONE)); | ||
s1 = (g.modPow(k, p)).mod(q); | ||
s2 = (k.modInverse(q).multiply(hash.add(x.multiply(s1)))).mod(q); | ||
if (s1 != 0 && s2 != 0) { | ||
break; | ||
} | ||
} | ||
var result = []; | ||
@@ -50,0 +61,0 @@ result[0] = s1.toMPI(); |
@@ -35,5 +35,4 @@ // GPG4Browsers - An OpenPGP implementation in javascript | ||
// choose k in {2,...,p-2} | ||
var two = BigInteger.ONE.add(BigInteger.ONE); | ||
var pMinus2 = p.subtract(two); | ||
var k = random.getRandomBigIntegerInRange(two, pMinus2); | ||
var pMinus2 = p.subtract(BigInteger.TWO); | ||
var k = random.getRandomBigIntegerInRange(BigInteger.ONE, pMinus2); | ||
k = k.mod(pMinus2).add(BigInteger.ONE); | ||
@@ -40,0 +39,0 @@ var c = []; |
@@ -173,3 +173,3 @@ /* | ||
if (x > 0) this[0] = x; | ||
else if (x < -1) this[0] = x + DV; | ||
else if (x < -1) this[0] = x + this.DV; | ||
else this.t = 0; | ||
@@ -297,3 +297,3 @@ } | ||
r = i - a.t; | ||
if (r != 0) return r; | ||
if (r != 0) return (this.s < 0) ? -r : r; | ||
while (--i >= 0) if ((r = this[i] - a[i]) != 0) return r; | ||
@@ -735,2 +735,3 @@ return 0; | ||
BigInteger.ONE = nbv(1); | ||
BigInteger.TWO = nbv(2); | ||
@@ -737,0 +738,0 @@ module.exports = BigInteger; |
@@ -29,3 +29,4 @@ // GPG4Browsers - An OpenPGP implementation in javascript | ||
util = require('../../util.js'), | ||
random = require('../random.js'); | ||
random = require('../random.js'), | ||
config = require('../../config'); | ||
@@ -41,2 +42,19 @@ function SecureRandom() { | ||
var blinder = BigInteger.ZERO; | ||
var unblinder = BigInteger.ZERO; | ||
function blind(m, n, e) { | ||
if (unblinder.bitLength() === n.bitLength()) { | ||
unblinder = unblinder.square().mod(n); | ||
} else { | ||
unblinder = random.getRandomBigIntegerInRange(BigInteger.TWO, n); | ||
} | ||
blinder = unblinder.modInverse(n).modPow(e, n); | ||
return m.multiply(blinder).mod(n); | ||
} | ||
function unblind(t, n) { | ||
return t.multiply(unblinder).mod(n); | ||
} | ||
function RSA() { | ||
@@ -47,2 +65,6 @@ /** | ||
* message | ||
* @param n | ||
* RSA public modulus n as BigInteger | ||
* @param e | ||
* RSA public exponent as BigInteger | ||
* @param d | ||
@@ -58,3 +80,6 @@ * RSA d as BigInteger | ||
*/ | ||
function decrypt(m, d, p, q, u) { | ||
function decrypt(m, n, e, d, p, q, u) { | ||
if (config.rsa_blinding) { | ||
m = blind(m, n, e); | ||
} | ||
var xp = m.mod(p).modPow(d.mod(p.subtract(BigInteger.ONE)), p); | ||
@@ -72,3 +97,7 @@ var xq = m.mod(q).modPow(d.mod(q.subtract(BigInteger.ONE)), q); | ||
} | ||
return t.multiply(p).add(xp); | ||
t = t.multiply(p).add(xp); | ||
if (config.rsa_blinding) { | ||
t = unblind(t, n); | ||
} | ||
return t; | ||
} | ||
@@ -75,0 +104,0 @@ |
@@ -47,12 +47,2 @@ // GPG4Browsers - An OpenPGP implementation in javascript | ||
/** | ||
* Return a pseudo-random number in the specified range | ||
* @param {Integer} from Min of the random number | ||
* @param {Integer} to Max of the random number (max 32bit) | ||
* @return {Integer} A pseudo random number | ||
*/ | ||
getPseudoRandom: function(from, to) { | ||
return Math.round(Math.random() * (to - from)) + from; | ||
}, | ||
/** | ||
* Return a secure random number in the specified range | ||
@@ -90,2 +80,5 @@ * @param {Integer} from Min of the random number | ||
getRandomValues: function(buf) { | ||
if (!(buf instanceof Uint8Array)) { | ||
throw new Error('Invalid type: buf not an Uint8Array'); | ||
} | ||
if (typeof window !== 'undefined' && window.crypto) { | ||
@@ -109,4 +102,4 @@ window.crypto.getRandomValues(buf); | ||
getRandomBigInteger: function(bits) { | ||
if (bits < 0) { | ||
return null; | ||
if (bits < 1) { | ||
throw new Error('Illegal parameter value: bits < 1'); | ||
} | ||
@@ -130,3 +123,3 @@ var numBytes = Math.floor((bits + 7) / 8); | ||
if (max.compareTo(min) <= 0) { | ||
return; | ||
throw new Error('Illegal parameter value: max <= min'); | ||
} | ||
@@ -159,3 +152,3 @@ | ||
RandomBuffer.prototype.init = function(size) { | ||
this.buffer = new Uint32Array(size); | ||
this.buffer = new Uint8Array(size); | ||
this.size = 0; | ||
@@ -166,3 +159,3 @@ }; | ||
* Concat array of secure random numbers to buffer | ||
* @param {Uint32Array} buf | ||
* @param {Uint8Array} buf | ||
*/ | ||
@@ -173,2 +166,5 @@ RandomBuffer.prototype.set = function(buf) { | ||
} | ||
if (!(buf instanceof Uint8Array)) { | ||
throw new Error('Invalid type: buf not an Uint8Array'); | ||
} | ||
var freeSpace = this.buffer.length - this.size; | ||
@@ -178,2 +174,3 @@ if (buf.length > freeSpace) { | ||
} | ||
// set buf with offset old size of buffer | ||
this.buffer.set(buf, this.size); | ||
@@ -185,3 +182,3 @@ this.size += buf.length; | ||
* Take numbers out of buffer and copy to array | ||
* @param {Uint32Array} buf the destination array | ||
* @param {Uint8Array} buf the destination array | ||
*/ | ||
@@ -192,8 +189,13 @@ RandomBuffer.prototype.get = function(buf) { | ||
} | ||
if (!(buf instanceof Uint8Array)) { | ||
throw new Error('Invalid type: buf not an Uint8Array'); | ||
} | ||
if (this.size < buf.length) { | ||
throw new Error('Random number buffer depleted.') | ||
throw new Error('Random number buffer depleted'); | ||
} | ||
for (var i = 0; i < buf.length; i++) { | ||
buf[i] = this.buffer[--this.size]; | ||
// clear buffer value | ||
this.buffer[this.size] = 0; | ||
} | ||
}; |
@@ -22,4 +22,2 @@ /** | ||
verify: function(algo, hash_algo, msg_MPIs, publickey_MPIs, data) { | ||
var calc_hash = hashModule.digest(hash_algo, data); | ||
var dopublic; | ||
@@ -35,11 +33,8 @@ switch (algo) { | ||
var n = publickey_MPIs[0].toBigInteger(); | ||
var k = publickey_MPIs[0].byteLength(); | ||
var e = publickey_MPIs[1].toBigInteger(); | ||
var x = msg_MPIs[0].toBigInteger(); | ||
dopublic = rsa.verify(x, e, n); | ||
var hash = pkcs1.emsa.decode(hash_algo, dopublic.toMPI().substring(2)); | ||
if (hash == -1) { | ||
throw new Error('PKCS1 padding in message or key incorrect. Aborting...'); | ||
} | ||
return hash == calc_hash; | ||
var m = msg_MPIs[0].toBigInteger(); | ||
var EM = rsa.verify(m, e, n); | ||
var EM2 = pkcs1.emsa.encode(hash_algo, data, k); | ||
return EM.compareTo(EM2) === 0; | ||
case 16: | ||
@@ -58,3 +53,3 @@ // Elgamal (Encrypt-Only) [ELGAMAL] [HAC] | ||
var m = data; | ||
dopublic = dsa.verify(hash_algo, s1, s2, m, p, q, g, y); | ||
var dopublic = dsa.verify(hash_algo, s1, s2, m, p, q, g, y); | ||
return dopublic.compareTo(s1) === 0; | ||
@@ -61,0 +56,0 @@ default: |
@@ -30,3 +30,4 @@ // GPG4Browsers - An OpenPGP implementation in javascript | ||
/** | ||
* Finds out which Ascii Armoring type is used. This is an internal function | ||
* Finds out which Ascii Armoring type is used. Throws error if unknown type. | ||
* @private | ||
* @param {String} text [String] ascii armored text | ||
@@ -39,13 +40,16 @@ * @returns {Integer} 0 = MESSAGE PART n of m | ||
* 5 = PRIVATE KEY BLOCK | ||
* null = unknown | ||
*/ | ||
function getType(text) { | ||
var reHeader = /^-----([^-]+)-----$\n/m; | ||
var reHeader = /^-----BEGIN PGP (MESSAGE, PART \d+\/\d+|MESSAGE, PART \d+|SIGNED MESSAGE|MESSAGE|PUBLIC KEY BLOCK|PRIVATE KEY BLOCK)-----$\n/m; | ||
var header = text.match(reHeader); | ||
if (!header) { | ||
throw new Error('Unknow ASCII armor type'); | ||
} | ||
// BEGIN PGP MESSAGE, PART X/Y | ||
// Used for multi-part messages, where the armor is split amongst Y | ||
// parts, and this is the Xth part out of Y. | ||
if (header[1].match(/BEGIN PGP MESSAGE, PART \d+\/\d+/)) { | ||
if (header[1].match(/MESSAGE, PART \d+\/\d+/)) { | ||
return enums.armor.multipart_section; | ||
@@ -57,3 +61,3 @@ } else | ||
// Header to be used. | ||
if (header[1].match(/BEGIN PGP MESSAGE, PART \d+/)) { | ||
if (header[1].match(/MESSAGE, PART \d+/)) { | ||
return enums.armor.multipart_last; | ||
@@ -66,3 +70,3 @@ | ||
// for detached signatures. | ||
if (header[1].match(/BEGIN PGP SIGNED MESSAGE/)) { | ||
if (header[1].match(/SIGNED MESSAGE/)) { | ||
return enums.armor.signed; | ||
@@ -73,3 +77,3 @@ | ||
// Used for signed, encrypted, or compressed files. | ||
if (header[1].match(/BEGIN PGP MESSAGE/)) { | ||
if (header[1].match(/MESSAGE/)) { | ||
return enums.armor.message; | ||
@@ -80,3 +84,3 @@ | ||
// Used for armoring public keys. | ||
if (header[1].match(/BEGIN PGP PUBLIC KEY BLOCK/)) { | ||
if (header[1].match(/PUBLIC KEY BLOCK/)) { | ||
return enums.armor.public_key; | ||
@@ -87,3 +91,3 @@ | ||
// Used for armoring private keys. | ||
if (header[1].match(/BEGIN PGP PRIVATE KEY BLOCK/)) { | ||
if (header[1].match(/PRIVATE KEY BLOCK/)) { | ||
return enums.armor.private_key; | ||
@@ -137,3 +141,3 @@ } | ||
var d = checksum; | ||
return c[0] == d[0] && c[1] == d[1] && c[2] == d[2]; | ||
return c[0] == d[0] && c[1] == d[1] && c[2] == d[2] && c[3] == d[3]; | ||
} | ||
@@ -218,4 +222,4 @@ /** | ||
function splitHeaders(text) { | ||
var reEmptyLine = /^[\t ]*\n/m; | ||
var headers = ""; | ||
var reEmptyLine = /^\s*\n/m; | ||
var headers = ''; | ||
var body = text; | ||
@@ -228,4 +232,10 @@ | ||
body = text.slice(matchResult.index + matchResult[0].length); | ||
} else { | ||
throw new Error('Mandatory blank line missing between armor headers and armor data'); | ||
} | ||
headers = headers.split('\n'); | ||
// remove empty entry | ||
headers.pop(); | ||
return { headers: headers, body: body }; | ||
@@ -235,2 +245,16 @@ } | ||
/** | ||
* Verify armored headers. RFC4880, section 6.3: "OpenPGP should consider improperly formatted | ||
* Armor Headers to be corruption of the ASCII Armor." | ||
* @private | ||
* @param {Array<String>} headers Armor headers | ||
*/ | ||
function verifyHeaders(headers) { | ||
for (var i = 0; i < headers.length; i++) { | ||
if (!headers[i].match(/^(Version|Comment|MessageID|Hash|Charset): .+$/)) { | ||
throw new Error('Improperly formatted armor header: ' + headers[i]);; | ||
} | ||
} | ||
} | ||
/** | ||
* Splits a message into two parts, the body and the checksum. This is an internal function | ||
@@ -271,5 +295,2 @@ * @param {String} text OpenPGP armored message part | ||
var type = getType(text); | ||
if (!type) { | ||
throw new Error('Unknow ASCII armor type'); | ||
} | ||
@@ -295,2 +316,3 @@ var splittext = text.split(reSplit); | ||
data: base64.decode(msg_sum.body), | ||
headers: msg.headers, | ||
type: type | ||
@@ -301,5 +323,6 @@ }; | ||
} else { | ||
// Reverse dash-escaping for msg and remove trailing whitespace at end of line | ||
// Reverse dash-escaping for msg and remove trailing whitespace (0x20) and tabs (0x09) at end of line | ||
msg = splitHeaders(splittext[indexBase].replace(/^- /mg, '').replace(/[\t ]+\n/g, "\n")); | ||
var sig = splitHeaders(splittext[indexBase + 1].replace(/^- /mg, '')); | ||
verifyHeaders(sig.headers); | ||
var sig_sum = splitChecksum(sig.body); | ||
@@ -310,2 +333,3 @@ | ||
data: base64.decode(sig_sum.body), | ||
headers: msg.headers, | ||
type: type | ||
@@ -317,2 +341,4 @@ }; | ||
checksum = checksum.substr(0, 4); | ||
if (!verifyCheckSum(result.data, checksum)) { | ||
@@ -322,6 +348,8 @@ throw new Error("Ascii armor integrity check on message failed: '" + | ||
"' should be '" + | ||
getCheckSum(result) + "'"); | ||
} else { | ||
return result; | ||
getCheckSum(result.data) + "'"); | ||
} | ||
verifyHeaders(result.headers); | ||
return result; | ||
} | ||
@@ -328,0 +356,0 @@ |
210
src/key.js
@@ -477,3 +477,3 @@ // GPG4Browsers - An OpenPGP implementation in javascript | ||
return null; | ||
}; | ||
} | ||
@@ -484,3 +484,3 @@ /** | ||
* - if no primary user is found returns the user with the latest self signature | ||
* @return {{user: Array<module:packet/User>, selfCertificate: Array<module:packet/signature>}} The primary user and the self signature | ||
* @return {{user: Array<module:packet/User>, selfCertificate: Array<module:packet/signature>}|null} The primary user and the self signature | ||
*/ | ||
@@ -498,5 +498,5 @@ Key.prototype.getPrimaryUser = function() { | ||
} | ||
if (!user || | ||
!userSelfCert.isPrimaryUserID && selfCert.isPrimaryUserID || | ||
userSelfCert.created < selfCert.created) { | ||
if (!user || | ||
(!userSelfCert.isPrimaryUserID || selfCert.isPrimaryUserID) && | ||
userSelfCert.created > selfCert.created) { | ||
user = this.users[i]; | ||
@@ -509,2 +509,98 @@ userSelfCert = selfCert; | ||
/** | ||
* Update key with new components from specified key with same key ID: | ||
* users, subkeys, certificates are merged into the destination key, | ||
* duplicates are ignored. | ||
* If the specified key is a private key and the destination key is public, | ||
* the destination key is tranformed to a private key. | ||
* @param {module:key~Key} key source key to merge | ||
*/ | ||
Key.prototype.update = function(key) { | ||
var that = this; | ||
if (key.verifyPrimaryKey() === enums.keyStatus.invalid) { | ||
return; | ||
} | ||
if (this.primaryKey.getFingerprint() !== key.primaryKey.getFingerprint()) { | ||
throw new Error('Key update method: fingerprints of keys not equal'); | ||
} | ||
if (this.isPublic() && key.isPrivate()) { | ||
// check for equal subkey packets | ||
var equal = ((this.subKeys && this.subKeys.length) === (key.subKeys && key.subKeys.length)) && | ||
(!this.subKeys || this.subKeys.every(function(destSubKey) { | ||
return key.subKeys.some(function(srcSubKey) { | ||
return destSubKey.subKey.getFingerprint() === srcSubKey.subKey.getFingerprint(); | ||
}); | ||
})); | ||
if (!equal) { | ||
throw new Error('Cannot update public key with private key if subkey mismatch'); | ||
} | ||
this.primaryKey = key.primaryKey; | ||
} | ||
// revocation signature | ||
if (!this.revocationSignature && key.revocationSignature && !key.revocationSignature.isExpired() && | ||
(key.revocationSignature.verified || | ||
key.revocationSignature.verify(key.primaryKey, {key: key.primaryKey}))) { | ||
this.revocationSignature = key.revocationSignature; | ||
} | ||
// direct signatures | ||
mergeSignatures(key, this, 'directSignatures'); | ||
// users | ||
key.users.forEach(function(srcUser) { | ||
var found = false; | ||
for (var i = 0; i < that.users.length; i++) { | ||
if (srcUser.userId && (srcUser.userId.userid === that.users[i].userId.userid) || | ||
srcUser.userAttribute && (srcUser.userAttribute.equals(that.users[i].userAttribute))) { | ||
that.users[i].update(srcUser, that.primaryKey); | ||
found = true; | ||
break; | ||
} | ||
} | ||
if (!found) { | ||
that.users.push(srcUser); | ||
} | ||
}); | ||
// subkeys | ||
if (key.subKeys) { | ||
key.subKeys.forEach(function(srcSubKey) { | ||
var found = false; | ||
for (var i = 0; i < that.subKeys.length; i++) { | ||
if (srcSubKey.subKey.getFingerprint() === that.subKeys[i].subKey.getFingerprint()) { | ||
that.subKeys[i].update(srcSubKey, that.primaryKey); | ||
found = true; | ||
break; | ||
} | ||
} | ||
if (!found) { | ||
that.subKeys.push(srcSubKey); | ||
} | ||
}); | ||
} | ||
}; | ||
/** | ||
* Merges signatures from source[attr] to dest[attr] | ||
* @private | ||
* @param {Object} source | ||
* @param {Object} dest | ||
* @param {String} attr | ||
* @param {Function} checkFn optional, signature only merged if true | ||
*/ | ||
function mergeSignatures(source, dest, attr, checkFn) { | ||
source = source[attr]; | ||
if (source) { | ||
if (!dest[attr]) { | ||
dest[attr] = source; | ||
} else { | ||
source.forEach(function(sourceSig) { | ||
if (!sourceSig.isExpired() && (!checkFn || checkFn(sourceSig)) && | ||
!dest[attr].some(function(destSig) { | ||
return destSig.signature === sourceSig.signature; | ||
})) { | ||
dest[attr].push(sourceSig); | ||
} | ||
}); | ||
} | ||
} | ||
} | ||
// TODO | ||
@@ -624,2 +720,20 @@ Key.prototype.revoke = function() { | ||
/** | ||
* Update user with new components from specified user | ||
* @param {module:key~User} user source user to merge | ||
* @param {module:packet/signature} primaryKey primary key used for validation | ||
*/ | ||
User.prototype.update = function(user, primaryKey) { | ||
var that = this; | ||
// self signatures | ||
mergeSignatures(user, this, 'selfCertifications', function(srcSelfSig) { | ||
return srcSelfSig.verified || | ||
srcSelfSig.verify(primaryKey, {userid: that.userId || that.userAttribute, key: primaryKey}); | ||
}); | ||
// other signatures | ||
mergeSignatures(user, this, 'otherCertifications'); | ||
// revocation signatures | ||
mergeSignatures(user, this, 'revocationCertifications'); | ||
}; | ||
/** | ||
* @class | ||
@@ -715,2 +829,26 @@ * @classdesc Class that represents a subkey packet and the relevant signatures. | ||
/** | ||
* Update subkey with new components from specified subkey | ||
* @param {module:key~SubKey} subKey source subkey to merge | ||
* @param {module:packet/signature} primaryKey primary key used for validation | ||
*/ | ||
SubKey.prototype.update = function(subKey, primaryKey) { | ||
if (this.verify(primaryKey) === enums.keyStatus.invalid) { | ||
return; | ||
} | ||
if (this.subKey.getFingerprint() !== subKey.subKey.getFingerprint()) { | ||
throw new Error('SubKey update method: fingerprints of subkeys not equal'); | ||
} | ||
if (this.subKey.tag === enums.packet.publicSubkey && | ||
subKey.subKey.tag === enums.packet.secretSubkey) { | ||
this.subKey = subKey.subKey; | ||
} | ||
// revocation signature | ||
if (!this.revocationSignature && subKey.revocationSignature && !subKey.revocationSignature.isExpired() && | ||
(subKey.revocationSignature.verified || | ||
subKey.revocationSignature.verify(primaryKey, {key: primaryKey, bind: this.subKey}))) { | ||
this.revocationSignature = subKey.revocationSignature; | ||
} | ||
}; | ||
/** | ||
* Reads an OpenPGP armored text and returns one or multiple key objects | ||
@@ -764,2 +902,7 @@ * @param {String} armoredText text to be parsed | ||
function generate(keyType, numBits, userId, passphrase) { | ||
// RSA Encrypt-Only and RSA Sign-Only are deprecated and SHOULD NOT be generated | ||
if (keyType !== enums.publicKey.rsa_encrypt_sign) { | ||
throw new Error('Only RSA Encrypt or Sign supported'); | ||
} | ||
var packetlist = new packet.List(); | ||
@@ -781,5 +924,21 @@ | ||
signaturePacket.publicKeyAlgorithm = keyType; | ||
//TODO we should load preferred hash from config, or as input to this function | ||
signaturePacket.hashAlgorithm = enums.hash.sha256; | ||
signaturePacket.hashAlgorithm = config.prefer_hash_algorithm; | ||
signaturePacket.keyFlags = [enums.keyFlags.certify_keys | enums.keyFlags.sign_data]; | ||
signaturePacket.preferredSymmetricAlgorithms = []; | ||
signaturePacket.preferredSymmetricAlgorithms.push(enums.symmetric.aes256); | ||
signaturePacket.preferredSymmetricAlgorithms.push(enums.symmetric.aes192); | ||
signaturePacket.preferredSymmetricAlgorithms.push(enums.symmetric.aes128); | ||
signaturePacket.preferredSymmetricAlgorithms.push(enums.symmetric.cast5); | ||
signaturePacket.preferredSymmetricAlgorithms.push(enums.symmetric.tripledes); | ||
signaturePacket.preferredHashAlgorithms = []; | ||
signaturePacket.preferredHashAlgorithms.push(enums.hash.sha256); | ||
signaturePacket.preferredHashAlgorithms.push(enums.hash.sha1); | ||
signaturePacket.preferredHashAlgorithms.push(enums.hash.sha512); | ||
signaturePacket.preferredCompressionAlgorithms = []; | ||
signaturePacket.preferredCompressionAlgorithms.push(enums.compression.zlib); | ||
signaturePacket.preferredCompressionAlgorithms.push(enums.compression.zip); | ||
if (config.integrity_protect) { | ||
signaturePacket.features = []; | ||
signaturePacket.features.push(1); // Modification Detection | ||
} | ||
signaturePacket.sign(secretKeyPacket, dataToSign); | ||
@@ -798,4 +957,3 @@ | ||
subkeySignaturePacket.publicKeyAlgorithm = keyType; | ||
//TODO we should load preferred hash from config, or as input to this function | ||
subkeySignaturePacket.hashAlgorithm = enums.hash.sha256; | ||
subkeySignaturePacket.hashAlgorithm = config.prefer_hash_algorithm; | ||
subkeySignaturePacket.keyFlags = [enums.keyFlags.encrypt_communication | enums.keyFlags.encrypt_storage]; | ||
@@ -813,4 +971,38 @@ subkeySignaturePacket.sign(secretKeyPacket, dataToSign); | ||
/** | ||
* Returns the preferred symmetric algorithm for a set of keys | ||
* @param {Array<module:key~Key>} keys Set of keys | ||
* @return {enums.symmetric} Preferred symmetric algorithm | ||
*/ | ||
function getPreferredSymAlgo(keys) { | ||
var prioMap = {}; | ||
for (var i = 0; i < keys.length; i++) { | ||
var primaryUser = keys[i].getPrimaryUser(); | ||
if (!primaryUser || !primaryUser.selfCertificate.preferredSymmetricAlgorithms) { | ||
return config.encryption_cipher; | ||
} | ||
primaryUser.selfCertificate.preferredSymmetricAlgorithms.forEach(function(algo, index) { | ||
var entry = prioMap[algo] || (prioMap[algo] = {prio: 0, count: 0, algo: algo}); | ||
entry.prio += 64 >> index; | ||
entry.count++; | ||
}); | ||
} | ||
var prefAlgo = {prio: 0, algo: config.encryption_cipher}; | ||
for (var algo in prioMap) { | ||
try { | ||
if (algo !== enums.symmetric.plaintext && | ||
algo !== enums.symmetric.idea && // not implemented | ||
enums.read(enums.symmetric, algo) && // known algorithm | ||
prioMap[algo].count === keys.length && // available for all keys | ||
prioMap[algo].prio > prefAlgo.prio) { | ||
prefAlgo = prioMap[algo]; | ||
} | ||
} catch (e) {} | ||
} | ||
return prefAlgo.algo; | ||
} | ||
exports.Key = Key; | ||
exports.readArmored = readArmored; | ||
exports.generate = generate; | ||
exports.getPreferredSymAlgo = getPreferredSymAlgo; |
@@ -30,10 +30,2 @@ // GPG4Browsers - An OpenPGP implementation in javascript | ||
/** | ||
* Callback to check if a key matches the input | ||
* @callback module:keyring/keyring.checkCallback | ||
* @param {String} input input to search for | ||
* @param {module:key~Key} key The key to be checked. | ||
* @return {Boolean} True if the input matches the specified key | ||
*/ | ||
module.exports = Keyring; | ||
@@ -49,4 +41,5 @@ | ||
this.storeHandler = storeHandler || new (require('./localstore.js'))(); | ||
this.keys = this.storeHandler.load(); | ||
}; | ||
this.publicKeys = new KeyArray(this.storeHandler.loadPublic()); | ||
this.privateKeys = new KeyArray(this.storeHandler.loadPrivate()); | ||
} | ||
@@ -57,3 +50,4 @@ /** | ||
Keyring.prototype.store = function () { | ||
this.storeHandler.store(this.keys); | ||
this.storeHandler.storePublic(this.publicKeys.keys); | ||
this.storeHandler.storePrivate(this.privateKeys.keys); | ||
}; | ||
@@ -65,7 +59,67 @@ | ||
Keyring.prototype.clear = function() { | ||
this.keys = []; | ||
this.publicKeys.keys = []; | ||
this.privateKeys.keys = []; | ||
}; | ||
/** | ||
* Searches the keyring for keys having the specified key id | ||
* @param {String} keyId provided as string of lowercase hex number | ||
* withouth 0x prefix (can be 16-character key ID or fingerprint) | ||
* @param {Boolean} deep if true search also in subkeys | ||
* @return {Array<module:key~Key>|null} keys found or null | ||
*/ | ||
Keyring.prototype.getKeysForId = function (keyId, deep) { | ||
var result = []; | ||
result = result.concat(this.publicKeys.getForId(keyId, deep) || []); | ||
result = result.concat(this.privateKeys.getForId(keyId, deep) || []); | ||
return result.length ? result : null; | ||
}; | ||
/** | ||
* Removes keys having the specified key id from the keyring | ||
* @param {String} keyId provided as string of lowercase hex number | ||
* withouth 0x prefix (can be 16-character key ID or fingerprint) | ||
* @return {Array<module:key~Key>|null} keys found or null | ||
*/ | ||
Keyring.prototype.removeKeysForId = function (keyId) { | ||
var result = []; | ||
result = result.concat(this.publicKeys.removeForId(keyId) || []); | ||
result = result.concat(this.privateKeys.removeForId(keyId) || []); | ||
return result.length ? result : null; | ||
}; | ||
/** | ||
* Get all public and private keys | ||
* @return {Array<module:key~Key>} all keys | ||
*/ | ||
Keyring.prototype.getAllKeys = function () { | ||
return this.publicKeys.keys.concat(this.privateKeys.keys); | ||
}; | ||
/** | ||
* Array of keys | ||
* @param {Array<module:key~Key>} keys The keys to store in this array | ||
*/ | ||
function KeyArray(keys) { | ||
this.keys = keys; | ||
} | ||
/** | ||
* Searches all keys in the KeyArray matching the address or address part of the user ids | ||
* @param {String} email email address to search for | ||
* @return {Array<module:key~Key>} The public keys associated with provided email address. | ||
*/ | ||
KeyArray.prototype.getForAddress = function(email) { | ||
var results = []; | ||
for (var i = 0; i < this.keys.length; i++) { | ||
if (emailCheck(email, this.keys[i])) { | ||
results.push(this.keys[i]); | ||
} | ||
} | ||
return results; | ||
}; | ||
/** | ||
* Checks a key to see if it matches the specified email address | ||
* @private | ||
* @param {String} email email address to search for | ||
@@ -90,109 +144,82 @@ * @param {module:key~Key} key The key to be checked. | ||
* Checks a key to see if it matches the specified keyid | ||
* @param {String} id hex string keyid to search for | ||
* @param {module:key~Key} key the key to be checked. | ||
* @return {Boolean} true if the email address is defined in the specified key | ||
* @inner | ||
* @private | ||
* @param {String} keyId provided as string of lowercase hex number | ||
* withouth 0x prefix (can be 16-character key ID or fingerprint) | ||
* @param {module:packet/secret_key|public_key|public_subkey|secret_subkey} keypacket The keypacket to be checked | ||
* @return {Boolean} True if keypacket has the specified keyid | ||
*/ | ||
function idCheck(id, key) { | ||
var keyids = key.getKeyIds(); | ||
for (var i = 0; i < keyids.length; i++) { | ||
if (util.hexstrdump(keyids[i].write()) == id) { | ||
return true; | ||
} | ||
function keyIdCheck(keyId, keypacket) { | ||
if (keyId.length === 16) { | ||
return keyId === keypacket.getKeyId().toHex(); | ||
} else { | ||
return keyId === keypacket.getFingerprint(); | ||
} | ||
return false; | ||
} | ||
/** | ||
* searches all public keys in the keyring matching the address or address part of the user ids | ||
* @param {Array<module:key~Key>} keys array of keys to search | ||
* @param {module:keyring/keyring.checkCallback} identityFunction callback function which checks for a match | ||
* @param {String} identityInput input to check against | ||
* @param {module:enums.packet} keyType packet types of keys to check | ||
* @return {Array<module:key~Key>} array of keys which match | ||
* Searches the KeyArray for a key having the specified key id | ||
* @param {String} keyId provided as string of lowercase hex number | ||
* withouth 0x prefix (can be 16-character key ID or fingerprint) | ||
* @param {Boolean} deep if true search also in subkeys | ||
* @return {module:key~Key|null} key found or null | ||
*/ | ||
function checkForIdentityAndKeyTypeMatch(keys, identityFunction, identityInput, keyType) { | ||
var results = []; | ||
for (var p = 0; p < keys.length; p++) { | ||
var key = keys[p]; | ||
switch (keyType) { | ||
case enums.packet.publicKey: | ||
if (key.isPublic() && identityFunction(identityInput, key)) { | ||
results.push(key); | ||
KeyArray.prototype.getForId = function (keyId, deep) { | ||
for (var i = 0; i < this.keys.length; i++) { | ||
if (keyIdCheck(keyId, this.keys[i].primaryKey)) { | ||
return this.keys[i]; | ||
} | ||
if (deep && this.keys[i].subKeys) { | ||
for (var j = 0; j < this.keys[i].subKeys.length; j++) { | ||
if (keyIdCheck(keyId, this.keys[i].subKeys[j].subKey)) { | ||
return this.keys[i]; | ||
} | ||
break; | ||
case enums.packet.secretKey: | ||
if (key.isPrivate() && identityFunction(identityInput, key)) { | ||
results.push(key); | ||
} | ||
break; | ||
} | ||
} | ||
} | ||
return results; | ||
} | ||
/** | ||
* searches all public keys in the keyring matching the address or address part of the user ids | ||
* @param {String} email email address to search for | ||
* @return {Array<module:key~Key>} The public keys associated with provided email address. | ||
*/ | ||
Keyring.prototype.getPublicKeyForAddress = function (email) { | ||
return checkForIdentityAndKeyTypeMatch(this.keys, emailCheck, email, enums.packet.publicKey); | ||
return null; | ||
}; | ||
/** | ||
* Searches the keyring for a private key containing the specified email address | ||
* @param {String} email email address to search for | ||
* @return {Array<module:key~Key>} private keys found | ||
*/ | ||
Keyring.prototype.getPrivateKeyForAddress = function (email) { | ||
return checkForIdentityAndKeyTypeMatch(this.keys, emailCheck, email, enums.packet.secretKey); | ||
}; | ||
/** | ||
* Searches the keyring for public keys having the specified key id | ||
* @param {String} keyId provided as string of hex number (lowercase) | ||
* @return {Array<module:key~Key>} public keys found | ||
*/ | ||
Keyring.prototype.getKeysForKeyId = function (keyId) { | ||
return checkForIdentityAndKeyTypeMatch(this.keys, idCheck, keyId, enums.packet.publicKey); | ||
}; | ||
/** | ||
* Imports a key from an ascii armored message | ||
* @param {String} armored message to read the keys/key from | ||
* @return {Array<Error>|null} array of error objects or null | ||
*/ | ||
Keyring.prototype.importKey = function (armored) { | ||
this.keys = this.keys.concat(keyModule.readArmored(armored).keys); | ||
return true; | ||
KeyArray.prototype.importKey = function (armored) { | ||
var imported = keyModule.readArmored(armored); | ||
var that = this; | ||
imported.keys.forEach(function(key) { | ||
// check if key already in key array | ||
var keyidHex = key.primaryKey.getKeyId().toHex(); | ||
var keyFound = that.getForId(keyidHex); | ||
if (keyFound) { | ||
keyFound.update(key); | ||
} else { | ||
that.push(key); | ||
} | ||
}); | ||
return imported.err ? imported.err : null; | ||
}; | ||
/** | ||
* returns the armored message representation of the key at key ring index | ||
* @param {Integer} index the index of the key within the array | ||
* @return {String} armored message representing the key object | ||
* Add key to KeyArray | ||
* @param {module:key~Key} key The key that will be added to the keyring | ||
* @return {Number} The new length of the KeyArray | ||
*/ | ||
Keyring.prototype.exportKey = function (index) { | ||
return this.keys[index].armor(); | ||
KeyArray.prototype.push = function (key) { | ||
return this.keys.push(key); | ||
}; | ||
/** | ||
* Removes a public key from the public key keyring at the specified index | ||
* @param {Integer} index the index of the public key within the publicKeys array | ||
* @return {module:key~Key} The public key object which has been removed | ||
* Removes a key with the specified keyid from the keyring | ||
* @param {String} keyId provided as string of lowercase hex number | ||
* withouth 0x prefix (can be 16-character key ID or fingerprint) | ||
* @return {module:key~Key|null} The key object which has been removed or null | ||
*/ | ||
Keyring.prototype.removeKey = function (index) { | ||
var removed = this.keys.splice(index, 1); | ||
return removed; | ||
KeyArray.prototype.removeForId = function (keyId) { | ||
for (var i = 0; i < this.keys.length; i++) { | ||
if (keyIdCheck(keyId, this.keys[i].primaryKey)) { | ||
return this.keys.splice(i, 1)[0]; | ||
} | ||
} | ||
return null; | ||
}; | ||
/** | ||
* returns the armored message representation of the public key portion of the key at key ring index | ||
* @param {Integer} index the index of the key within the array | ||
* @return {String} armored message representing the public key object | ||
*/ | ||
Keyring.prototype.exportPublicKey = function (index) { | ||
return this.keys[index].toPublic().armor(); | ||
}; |
@@ -20,32 +20,46 @@ // GPG4Browsers - An OpenPGP implementation in javascript | ||
* The class that deals with storage of the keyring. Currently the only option is to use HTML5 local storage. | ||
* @requires openpgp | ||
* @requires config | ||
* @module keyring/localstore | ||
* @param {String} item itemname in localstore | ||
* @param {String} prefix prefix for itemnames in localstore | ||
*/ | ||
module.exports = LocalStore; | ||
var openpgp = require('../'); | ||
var config = require('../config'), | ||
keyModule = require('../key.js'); | ||
function LocalStore(item) { | ||
function LocalStore(prefix) { | ||
prefix = prefix || 'openpgp-'; | ||
this.publicKeysItem = prefix + this.publicKeysItem; | ||
this.privateKeysItem = prefix + this.privateKeysItem; | ||
if (typeof window != 'undefined' && window.localStorage) { | ||
this.storage = window.localStorage; | ||
} else { | ||
this.storage = new (require('node-localstorage').LocalStorage)(openpgp.config.node_store); | ||
this.storage = new (require('node-localstorage').LocalStorage)(config.node_store); | ||
} | ||
if(typeof item == 'string') { | ||
this.item = item; | ||
} | ||
} | ||
/* | ||
* Declare the localstore itemname | ||
* Declare the localstore itemnames | ||
*/ | ||
LocalStore.prototype.item = 'armoredKeys'; | ||
LocalStore.prototype.publicKeysItem = 'public-keys'; | ||
LocalStore.prototype.privateKeysItem = 'private-keys'; | ||
/** | ||
* Load the keyring from HTML5 local storage and initializes this instance. | ||
* Load the public keys from HTML5 local storage. | ||
* @return {Array<module:key~Key>} array of keys retrieved from localstore | ||
*/ | ||
LocalStore.prototype.load = function () { | ||
var armoredKeys = JSON.parse(this.storage.getItem(this.item)); | ||
LocalStore.prototype.loadPublic = function () { | ||
return loadKeys(this.storage, this.publicKeysItem); | ||
}; | ||
/** | ||
* Load the private keys from HTML5 local storage. | ||
* @return {Array<module:key~Key>} array of keys retrieved from localstore | ||
*/ | ||
LocalStore.prototype.loadPrivate = function () { | ||
return loadKeys(this.storage, this.privateKeysItem); | ||
}; | ||
function loadKeys(storage, itemname) { | ||
var armoredKeys = JSON.parse(storage.getItem(itemname)); | ||
var keys = []; | ||
@@ -55,3 +69,3 @@ if (armoredKeys !== null && armoredKeys.length !== 0) { | ||
for (var i = 0; i < armoredKeys.length; i++) { | ||
key = openpgp.key.readArmored(armoredKeys[i]).keys[0]; | ||
key = keyModule.readArmored(armoredKeys[i]).keys[0]; | ||
keys.push(key); | ||
@@ -61,10 +75,23 @@ } | ||
return keys; | ||
} | ||
/** | ||
* Saves the current state of the public keys to HTML5 local storage. | ||
* The key array gets stringified using JSON | ||
* @param {Array<module:key~Key>} keys array of keys to save in localstore | ||
*/ | ||
LocalStore.prototype.storePublic = function (keys) { | ||
storeKeys(this.storage, this.publicKeysItem, keys); | ||
}; | ||
/** | ||
* Saves the current state of the keyring to HTML5 local storage. | ||
* The privateKeys array and publicKeys array gets Stringified using JSON | ||
* Saves the current state of the private keys to HTML5 local storage. | ||
* The key array gets stringified using JSON | ||
* @param {Array<module:key~Key>} keys array of keys to save in localstore | ||
*/ | ||
LocalStore.prototype.store = function (keys) { | ||
LocalStore.prototype.storePrivate = function (keys) { | ||
storeKeys(this.storage, this.privateKeysItem, keys); | ||
}; | ||
function storeKeys(storage, itemname, keys) { | ||
var armoredKeys = []; | ||
@@ -74,3 +101,3 @@ for (var i = 0; i < keys.length; i++) { | ||
} | ||
this.storage.setItem(this.item, JSON.stringify(armoredKeys)); | ||
}; | ||
storage.setItem(itemname, JSON.stringify(armoredKeys)); | ||
} |
@@ -31,3 +31,4 @@ // GPG4Browsers - An OpenPGP implementation in javascript | ||
config = require('./config'), | ||
crypto = require('./crypto'); | ||
crypto = require('./crypto'), | ||
keyModule = require('./key.js'); | ||
@@ -111,3 +112,6 @@ /** | ||
symEncryptedPacket.decrypt(pkESKeyPacket.sessionKeyAlgorithm, pkESKeyPacket.sessionKey); | ||
return new Message(symEncryptedPacket.packets); | ||
var resultMsg = new Message(symEncryptedPacket.packets); | ||
// remove packets after decryption | ||
symEncryptedPacket.packets = new packet.List(); | ||
return resultMsg; | ||
} | ||
@@ -146,4 +150,4 @@ } | ||
var packetlist = new packet.List(); | ||
//TODO get preferred algo from signature | ||
var sessionKey = crypto.generateSessionKey(enums.read(enums.symmetric, config.encryption_cipher)); | ||
var symAlgo = keyModule.getPreferredSymAlgo(keys); | ||
var sessionKey = crypto.generateSessionKey(enums.read(enums.symmetric, symAlgo)); | ||
keys.forEach(function(key) { | ||
@@ -156,4 +160,3 @@ var encryptionKeyPacket = key.getEncryptionKeyPacket(); | ||
pkESKeyPacket.sessionKey = sessionKey; | ||
//TODO get preferred algo from signature | ||
pkESKeyPacket.sessionKeyAlgorithm = enums.read(enums.symmetric, config.encryption_cipher); | ||
pkESKeyPacket.sessionKeyAlgorithm = enums.read(enums.symmetric, symAlgo); | ||
pkESKeyPacket.encrypt(encryptionKeyPacket); | ||
@@ -172,4 +175,3 @@ packetlist.push(pkESKeyPacket); | ||
symEncryptedPacket.packets = this.packets; | ||
//TODO get preferred algo from signature | ||
symEncryptedPacket.encrypt(enums.read(enums.symmetric, config.encryption_cipher), sessionKey); | ||
symEncryptedPacket.encrypt(enums.read(enums.symmetric, symAlgo), sessionKey); | ||
packetlist.push(symEncryptedPacket); | ||
@@ -176,0 +178,0 @@ // remove packets after encryption |
@@ -207,3 +207,3 @@ // GPG4Browsers - An OpenPGP implementation in javascript | ||
* @param {function} callback (optional) callback(error, result) for async style | ||
* @return {Object} {key: Array<module:key~Key>, privateKeyArmored: Array<String>, publicKeyArmored: Array<String>} | ||
* @return {Object} {key: module:key~Key, privateKeyArmored: String, publicKeyArmored: String} | ||
* @static | ||
@@ -210,0 +210,0 @@ */ |
@@ -41,2 +41,3 @@ // GPG4Browsers - An OpenPGP implementation in javascript | ||
this.date = new Date(); | ||
this.filename = 'msg.txt'; | ||
} | ||
@@ -89,2 +90,20 @@ | ||
/** | ||
* Sets the filename of the literal packet data | ||
* @param {String} filename Any native javascript string | ||
*/ | ||
Literal.prototype.setFilename = function (filename) { | ||
this.filename = filename; | ||
}; | ||
/** | ||
* Get the filename of the literal packet data | ||
* @returns {String} filename | ||
*/ | ||
Literal.prototype.getFilename = function() { | ||
return this.filename; | ||
}; | ||
/** | ||
* Parsing function for a literal data packet (tag 11). | ||
@@ -122,3 +141,3 @@ * | ||
Literal.prototype.write = function () { | ||
var filename = util.encode_utf8("msg.txt"); | ||
var filename = util.encode_utf8(this.filename); | ||
@@ -125,0 +144,0 @@ var data = this.getBytes(); |
@@ -238,3 +238,3 @@ // GPG4Browsers - An OpenPGP implementation in javascript | ||
} | ||
real_packet_length = mypos2; | ||
real_packet_length = mypos2 - mypos; | ||
// 4.2.2.3. Five-Octet Lengths | ||
@@ -241,0 +241,0 @@ } else { |
@@ -172,5 +172,3 @@ // GPG4Browsers - An OpenPGP implementation in javascript | ||
var decoded = crypto.pkcs1.eme.decode( | ||
result, | ||
key.mpi[0].byteLength()); | ||
var decoded = crypto.pkcs1.eme.decode(result); | ||
@@ -177,0 +175,0 @@ key = decoded.substring(1, decoded.length - 2); |
@@ -58,2 +58,12 @@ // GPG4Browsers - An OpenPGP implementation in javascript | ||
this.expirationTimeV3 = 0; | ||
/** | ||
* Fingerprint in lowercase hex | ||
* @type {String} | ||
*/ | ||
this.fingerprint = null; | ||
/** | ||
* Keyid | ||
* @type {module:type/keyid} | ||
*/ | ||
this.keyid = null; | ||
} | ||
@@ -162,9 +172,12 @@ | ||
PublicKey.prototype.getKeyId = function () { | ||
var keyid = new type_keyid(); | ||
if (this.keyid) { | ||
return this.keyid; | ||
} | ||
this.keyid = new type_keyid(); | ||
if (this.version == 4) { | ||
keyid.read(this.getFingerprint().substr(12, 8)); | ||
this.keyid.read(util.hex2bin(this.getFingerprint()).substr(12, 8)); | ||
} else if (this.version == 3) { | ||
keyid.read(this.mpi[0].write().substr(-8)); | ||
this.keyid.read(this.mpi[0].write().substr(-8)); | ||
} | ||
return keyid; | ||
return this.keyid; | ||
}; | ||
@@ -174,9 +187,12 @@ | ||
* Calculates the fingerprint of the key | ||
* @return {String} A string containing the fingerprint | ||
* @return {String} A string containing the fingerprint in lowercase hex | ||
*/ | ||
PublicKey.prototype.getFingerprint = function () { | ||
if (this.fingerprint) { | ||
return this.fingerprint; | ||
} | ||
var toHash = ''; | ||
if (this.version == 4) { | ||
toHash = this.writeOld(); | ||
return crypto.hash.sha1(toHash); | ||
this.fingerprint = crypto.hash.sha1(toHash); | ||
} else if (this.version == 3) { | ||
@@ -187,4 +203,6 @@ var mpicount = crypto.getPublicMpiCount(this.algorithm); | ||
} | ||
return crypto.hash.md5(toHash); | ||
this.fingerprint = crypto.hash.md5(toHash); | ||
} | ||
this.fingerprint = util.hexstrdump(this.fingerprint); | ||
return this.fingerprint; | ||
}; | ||
@@ -207,2 +225,5 @@ | ||
} | ||
if (this.keyid) { | ||
this.keyid = type_keyid.fromClone(this.keyid); | ||
} | ||
}; |
@@ -54,2 +54,3 @@ // GPG4Browsers - An OpenPGP implementation in javascript | ||
this.signatureData = null; | ||
this.unhashedSubpackets = null; | ||
this.signedHashValue = null; | ||
@@ -170,5 +171,7 @@ | ||
this.signatureData = bytes.substr(0, i); | ||
var sigDataLength = i; | ||
// unhashed subpackets | ||
i += subpackets.call(this, bytes.substr(i), false); | ||
this.unhashedSubpackets = bytes.substr(sigDataLength, i - sigDataLength); | ||
@@ -189,3 +192,4 @@ break; | ||
return this.signatureData + | ||
util.writeNumber(0, 2) + // Number of unsigned subpackets. | ||
// unhashed subpackets or two octets for zero | ||
(this.unhashedSubpackets ? this.unhashedSubpackets : util.writeNumber(0, 2)) + | ||
this.signedHashValue + | ||
@@ -296,3 +300,3 @@ this.signature; | ||
bytes = util.bin2str(this.preferredCompressionAlgorithms); | ||
result += write_sub_packet(sub.preferred_hash_algorithms, bytes); | ||
result += write_sub_packet(sub.preferred_compression_algorithms, bytes); | ||
} | ||
@@ -414,8 +418,3 @@ if (this.keyServerPreferences !== null) { | ||
// Preferred Symmetric Algorithms | ||
this.preferredSymmetricAlgorithms = []; | ||
while (mypos != bytes.length) { | ||
this.preferredSymmetricAlgorithms.push(bytes.charCodeAt(mypos++)); | ||
} | ||
read_array.call(this, 'preferredSymmetricAlgorithms', bytes.substr(mypos)); | ||
break; | ||
@@ -454,3 +453,5 @@ case 12: | ||
this.notation[name] = value; | ||
} else throw new Error("Unsupported notation flag."); | ||
} else { | ||
util.print_debug("Unsupported notation flag "+bytes.charCodeAt(mypos)); | ||
} | ||
break; | ||
@@ -463,3 +464,3 @@ case 21: | ||
// Preferred Compression Algorithms | ||
read_array.call(this, 'preferredCompressionAlgorithms ', bytes.substr(mypos)); | ||
read_array.call(this, 'preferredCompressionAlgorithms', bytes.substr(mypos)); | ||
break; | ||
@@ -515,3 +516,3 @@ case 23: | ||
default: | ||
throw new Error("Unknown signature subpacket type " + type + " @:" + mypos); | ||
util.print_debug("Unknown signature subpacket type " + type + " @:" + mypos); | ||
} | ||
@@ -570,3 +571,3 @@ }; | ||
if (data.key === undefined) | ||
throw new Error('Key packet is required for this sigtature.'); | ||
throw new Error('Key packet is required for this signature.'); | ||
@@ -573,0 +574,0 @@ return data.key.writeOld(); |
@@ -67,1 +67,15 @@ // GPG4Browsers - An OpenPGP implementation in javascript | ||
}; | ||
/** | ||
* Compare for equality | ||
* @param {module:user_attribute~UserAttribute} usrAttr | ||
* @return {Boolean} true if equal | ||
*/ | ||
UserAttribute.prototype.equals = function(usrAttr) { | ||
if (!usrAttr || !(usrAttr instanceof UserAttribute)) { | ||
return false; | ||
} | ||
return this.attributes.every(function(attr, index) { | ||
return attr === usrAttr.attributes[index]; | ||
}); | ||
}; |
@@ -145,2 +145,5 @@ // GPG4Browsers - An OpenPGP implementation in javascript | ||
decode_utf8: function (utf8) { | ||
if (typeof utf8 !== 'string') { | ||
throw new Error('Parameter "utf8" is not of type string'); | ||
} | ||
try { | ||
@@ -147,0 +150,0 @@ return decodeURIComponent(escape(utf8)); |
@@ -44,2 +44,5 @@ // GPG4Browsers - An OpenPGP implementation in javascript | ||
this.worker.onmessage = this.onMessage.bind(this); | ||
this.worker.onerror = function(e) { | ||
throw new Error('Unhandled error in openpgp worker: ' + e.message + ' (' + e.filename + ':' + e.lineno + ')'); | ||
}; | ||
this.seedRandom(INITIAL_RANDOM_SEED); | ||
@@ -46,0 +49,0 @@ // FIFO |
@@ -20,3 +20,3 @@ // GPG4Browsers - An OpenPGP implementation in javascript | ||
importScripts('openpgp.min.js'); | ||
importScripts('openpgp.js'); | ||
@@ -35,2 +35,5 @@ var MIN_SIZE_RANDOM_BUFFER = 40000; | ||
case 'seed-random': | ||
if (!(msg.buf instanceof Uint8Array)) { | ||
msg.buf = new Uint8Array(msg.buf); | ||
} | ||
window.openpgp.crypto.random.randomBuffer.set(msg.buf); | ||
@@ -37,0 +40,0 @@ break; |
'use strict'; | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('../../../src/index'); | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('openpgp'); | ||
@@ -5,0 +5,0 @@ var util = openpgp.util, |
'use strict'; | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('../../../src/index'); | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('openpgp'); | ||
@@ -5,0 +5,0 @@ var util = openpgp.util, |
'use strict'; | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('../../../src/index'); | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('openpgp'); | ||
@@ -5,0 +5,0 @@ var util = openpgp.util, |
'use strict'; | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('../../../src/index'); | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('openpgp'); | ||
@@ -5,0 +5,0 @@ var util = openpgp.util, |
'use strict'; | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('../../../src/index'); | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('openpgp'); | ||
@@ -5,0 +5,0 @@ var util = openpgp.util, |
'use strict'; | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('../../src/index'); | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('openpgp'); | ||
@@ -5,0 +5,0 @@ var chai = require('chai'), |
'use strict'; | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('../../../src/index'); | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('openpgp'); | ||
@@ -5,0 +5,0 @@ var util = openpgp.util, |
'use strict'; | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('../../../src/index'); | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('openpgp'); | ||
@@ -5,0 +5,0 @@ var util = openpgp.util, |
'use strict'; | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('../../../src/index'); | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('openpgp'); | ||
@@ -5,0 +5,0 @@ var util = openpgp.util, |
'use strict'; | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('../../src/index'); | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('openpgp'); | ||
@@ -91,3 +91,8 @@ var chai = require('chai'), | ||
var encrypted = openpgp.signAndEncryptMessage([pubKey], privKey, message); | ||
// sign and encrypt | ||
var msg, encrypted; | ||
msg = openpgp.message.fromBinary(message); | ||
msg = msg.sign([privKey]); | ||
msg = msg.encrypt([pubKey]); | ||
encrypted = openpgp.armor.encode(openpgp.enums.armor.message, msg.packets.write()); | ||
@@ -98,3 +103,3 @@ if (console.profileEnd) { | ||
var msg = openpgp.message.readArmored(encrypted); | ||
msg = openpgp.message.readArmored(encrypted); | ||
@@ -119,3 +124,2 @@ var keyids = msg.getEncryptionKeyIds(); | ||
'Version: GnuPG v2.0.19 (GNU/Linux)', | ||
'Type: RSA/RSA', | ||
'', | ||
@@ -146,4 +150,2 @@ 'mI0EUmEvTgEEANyWtQQMOybQ9JltDqmaX0WnNPJeLILIM36sw6zL0nfTQ5zXSS3+', | ||
'Version: GnuPG v2.0.19 (GNU/Linux)', | ||
'Type: RSA/RSA', | ||
'Pwd: hello world', | ||
'', | ||
@@ -259,2 +261,9 @@ 'lQH+BFJhL04BBADclrUEDDsm0PSZbQ6pml9FpzTyXiyCyDN+rMOsy9J300Oc10kt', | ||
}); | ||
it('Decrypt message 2x', function() { | ||
decrypted = openpgp.decryptMessage(privKey, message); | ||
var decrypted2 = openpgp.decryptMessage(privKey, message); | ||
expect(decrypted).to.equal(decrypted2); | ||
}); | ||
}); | ||
@@ -327,2 +336,11 @@ | ||
describe("Misc.", function() { | ||
it('util.decode_utf8 throws error if invalid parameter type', function () { | ||
var test = openpgp.util.decode_utf8.bind(null, {chameleon: true}); | ||
expect(test).to.throw(Error, /Parameter "utf8" is not of type string/); | ||
}); | ||
}); | ||
}); |
describe('General', function () { | ||
require('./basic.js'); | ||
require('./armor.js'); | ||
require('./key.js'); | ||
@@ -4,0 +5,0 @@ require('./keyring.js'); |
'use strict'; | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('../../src/index'); | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('openpgp'); | ||
@@ -224,2 +224,42 @@ var chai = require('chai'), | ||
var priv_key_rsa = | ||
['-----BEGIN PGP PRIVATE KEY BLOCK-----', | ||
'Version: GnuPG v2.0.19 (GNU/Linux)', | ||
'', | ||
'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', | ||
'=lw5e', | ||
'-----END PGP PRIVATE KEY BLOCK-----'].join('\n'); | ||
it('Parsing armored text with two keys', function(done) { | ||
@@ -254,5 +294,5 @@ var pubKeys = openpgp.key.readArmored(twoKeys); | ||
expect(pubKeyV4.getKeyPacket().getKeyId().toHex()).to.equal('4a63613a4d6e4094'); | ||
expect(openpgp.util.hexstrdump(pubKeyV4.getKeyPacket().getFingerprint())).to.equal('f470e50dcb1ad5f1e64e08644a63613a4d6e4094'); | ||
expect(pubKeyV4.getKeyPacket().getFingerprint()).to.equal('f470e50dcb1ad5f1e64e08644a63613a4d6e4094'); | ||
expect(pubKeyV3.getKeyPacket().getKeyId().toHex()).to.equal('e5b7a014a237ba9d'); | ||
expect(openpgp.util.hexstrdump(pubKeyV3.getKeyPacket().getFingerprint())).to.equal('a44fcee620436a443bc4913640ab3e49'); | ||
expect(pubKeyV3.getKeyPacket().getFingerprint()).to.equal('a44fcee620436a443bc4913640ab3e49'); | ||
done(); | ||
@@ -327,3 +367,138 @@ }); | ||
it('update() - throw error if fingerprints not equal', function() { | ||
var keys = openpgp.key.readArmored(twoKeys).keys; | ||
expect(keys[0].update.bind(keys[0], keys[1])).to.throw('Key update method: fingerprints of keys not equal'); | ||
}); | ||
it('update() - merge revocation signature', function() { | ||
var source = openpgp.key.readArmored(pub_revoked).keys[0]; | ||
var dest = openpgp.key.readArmored(pub_revoked).keys[0]; | ||
expect(source.revocationSignature).to.exist; | ||
dest.revocationSignature = null; | ||
dest.update(source); | ||
expect(dest.revocationSignature).to.exist.and.be.an.instanceof(openpgp.packet.Signature); | ||
}); | ||
it('update() - merge user', function() { | ||
var source = openpgp.key.readArmored(pub_sig_test).keys[0]; | ||
var dest = openpgp.key.readArmored(pub_sig_test).keys[0]; | ||
expect(source.users[1]).to.exist; | ||
dest.users.pop(); | ||
dest.update(source); | ||
expect(dest.users[1]).to.exist; | ||
expect(dest.users[1].userId).to.equal(source.users[1].userId); | ||
}); | ||
it('update() - merge user - other and revocation certification', function() { | ||
var source = openpgp.key.readArmored(pub_sig_test).keys[0]; | ||
var dest = openpgp.key.readArmored(pub_sig_test).keys[0]; | ||
expect(source.users[1].otherCertifications).to.exist; | ||
expect(source.users[1].revocationCertifications).to.exist; | ||
dest.users[1].otherCertifications = null; | ||
dest.users[1].revocationCertifications.pop(); | ||
dest.update(source); | ||
expect(dest.users[1].otherCertifications).to.exist.and.to.have.length(1); | ||
expect(dest.users[1].otherCertifications[0].signature).to.equal(source.users[1].otherCertifications[0].signature); | ||
expect(dest.users[1].revocationCertifications).to.exist.and.to.have.length(2); | ||
expect(dest.users[1].revocationCertifications[1].signature).to.equal(source.users[1].revocationCertifications[1].signature); | ||
}); | ||
it('update() - merge subkey', function() { | ||
var source = openpgp.key.readArmored(pub_sig_test).keys[0]; | ||
var dest = openpgp.key.readArmored(pub_sig_test).keys[0]; | ||
expect(source.subKeys[1]).to.exist; | ||
dest.subKeys.pop(); | ||
dest.update(source); | ||
expect(dest.subKeys[1]).to.exist; | ||
expect(dest.subKeys[1].subKey.getKeyId().toHex()).to.equal(source.subKeys[1].subKey.getKeyId().toHex()); | ||
}); | ||
it('update() - merge subkey - revocation signature', function() { | ||
var source = openpgp.key.readArmored(pub_sig_test).keys[0]; | ||
var dest = openpgp.key.readArmored(pub_sig_test).keys[0]; | ||
expect(source.subKeys[0].revocationSignature).to.exist; | ||
dest.subKeys[0].revocationSignature = null; | ||
dest.update(source); | ||
expect(dest.subKeys[0].revocationSignature).to.exist; | ||
expect(dest.subKeys[0].revocationSignature.signature).to.equal(dest.subKeys[0].revocationSignature.signature); | ||
}); | ||
it('update() - merge private key into public key', function() { | ||
var source = openpgp.key.readArmored(priv_key_rsa).keys[0]; | ||
var dest = openpgp.key.readArmored(twoKeys).keys[0]; | ||
expect(dest.isPublic()).to.be.true; | ||
dest.update(source); | ||
expect(dest.isPrivate()).to.be.true; | ||
expect(source.verifyPrimaryKey()).to.equal(dest.verifyPrimaryKey()); | ||
expect(source.users[0].verify(source.primaryKey)).to.equal(dest.users[0].verify(dest.primaryKey)); | ||
expect(source.subKeys[0].verify(source.primaryKey)).to.equal(dest.subKeys[0].verify(dest.primaryKey)); | ||
}); | ||
it('update() - merge private key into public key - no subkeys', function() { | ||
var source = openpgp.key.readArmored(priv_key_rsa).keys[0]; | ||
var dest = openpgp.key.readArmored(twoKeys).keys[0]; | ||
source.subKeys = null; | ||
dest.subKeys = null; | ||
expect(dest.isPublic()).to.be.true; | ||
dest.update(source); | ||
expect(dest.isPrivate()).to.be.true; | ||
expect(source.verifyPrimaryKey()).to.equal(dest.verifyPrimaryKey()); | ||
expect(source.users[0].verify(source.primaryKey)).to.equal(dest.users[0].verify(dest.primaryKey)); | ||
}); | ||
it('update() - merge private key into public key - mismatch throws error', function() { | ||
var source = openpgp.key.readArmored(priv_key_rsa).keys[0]; | ||
var dest = openpgp.key.readArmored(twoKeys).keys[0]; | ||
source.subKeys = null; | ||
expect(dest.subKeys).to.exist; | ||
expect(dest.isPublic()).to.be.true; | ||
expect(dest.update.bind(dest, source)).to.throw('Cannot update public key with private key if subkey mismatch'); | ||
}); | ||
it('getPreferredSymAlgo() - one key - AES256', function() { | ||
var key1 = openpgp.key.readArmored(twoKeys).keys[0]; | ||
var prefAlgo = openpgp.key.getPreferredSymAlgo([key1]); | ||
expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes256); | ||
}); | ||
it('getPreferredSymAlgo() - two key - AES192', function() { | ||
var keys = openpgp.key.readArmored(twoKeys).keys; | ||
var key1 = keys[0]; | ||
var key2 = keys[1]; | ||
key2.getPrimaryUser().selfCertificate.preferredSymmetricAlgorithms = [6,8,3]; | ||
var prefAlgo = openpgp.key.getPreferredSymAlgo([key1, key2]); | ||
expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes192); | ||
}); | ||
it('getPreferredSymAlgo() - two key - one without pref', function() { | ||
var keys = openpgp.key.readArmored(twoKeys).keys; | ||
var key1 = keys[0]; | ||
var key2 = keys[1]; | ||
key2.getPrimaryUser().selfCertificate.preferredSymmetricAlgorithms = null; | ||
var prefAlgo = openpgp.key.getPreferredSymAlgo([key1, key2]); | ||
expect(prefAlgo).to.equal(openpgp.config.encryption_cipher); | ||
}); | ||
it('Preferences of generated key', function() { | ||
var testPref = function(key) { | ||
// key flags | ||
var keyFlags = openpgp.enums.keyFlags; | ||
expect(key.users[0].selfCertifications[0].keyFlags[0] & keyFlags.certify_keys).to.equal(keyFlags.certify_keys); | ||
expect(key.users[0].selfCertifications[0].keyFlags[0] & keyFlags.sign_data).to.equal(keyFlags.sign_data); | ||
expect(key.subKeys[0].bindingSignature.keyFlags[0] & keyFlags.encrypt_communication).to.equal(keyFlags.encrypt_communication); | ||
expect(key.subKeys[0].bindingSignature.keyFlags[0] & keyFlags.encrypt_storage).to.equal(keyFlags.encrypt_storage); | ||
var sym = openpgp.enums.symmetric; | ||
expect(key.users[0].selfCertifications[0].preferredSymmetricAlgorithms).to.eql([sym.aes256, sym.aes192, sym.aes128, sym.cast5, sym.tripledes]); | ||
var hash = openpgp.enums.hash; | ||
expect(key.users[0].selfCertifications[0].preferredHashAlgorithms).to.eql([hash.sha256, hash.sha1, hash.sha512]); | ||
var compr = openpgp.enums.compression; | ||
expect(key.users[0].selfCertifications[0].preferredCompressionAlgorithms).to.eql([compr.zlib, compr.zip]); | ||
expect(key.users[0].selfCertifications[0].features).to.eql(openpgp.config.integrity_protect ? [1] : null); // modification detection | ||
} | ||
var key = openpgp.generateKeyPair(openpgp.enums.publicKey.rsa_encrypt_sign, 512, 'test', 'hello'); | ||
testPref(key.key); | ||
testPref(openpgp.key.readArmored(key.publicKeyArmored).keys[0]); | ||
}); | ||
}); | ||
'use strict'; | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('../../src/index'); | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('openpgp'); | ||
@@ -13,3 +13,4 @@ var keyring = new openpgp.Keyring(), | ||
keySize = 512, | ||
keyId = 'F6F60E9B42CDFF4C', | ||
keyId = 'f6f60e9b42cdff4c', | ||
keyFingerP = '5856cef789c3a307e8a1b976f6f60e9b42cdff4c', | ||
pubkey = '-----BEGIN PGP PUBLIC KEY BLOCK-----\n' + | ||
@@ -41,63 +42,241 @@ 'Version: OpenPGP.js v.1.20131011\n' + | ||
'=ULta\n' + | ||
'-----END PGP PRIVATE KEY BLOCK-----'; | ||
'-----END PGP PRIVATE KEY BLOCK-----', | ||
keyId2 = 'ba993fc2aee18a3a', | ||
keyFingerP2 = '560b7a7f3f9ab516b233b299ba993fc2aee18a3a', | ||
subkeyId2 = 'f47c5210a8cc2740', | ||
subkeyFingerP2 = '2a20c371141e000833848d85f47c5210a8cc2740', | ||
pubkey2 = | ||
['-----BEGIN PGP PUBLIC KEY BLOCK-----', | ||
'Version: GnuPG v2.0.22 (GNU/Linux)', | ||
'', | ||
'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', | ||
'og2umGfGng==', | ||
'=v3+L', | ||
'-----END PGP PUBLIC KEY BLOCK-----'].join('\n'); | ||
it('Import key pair', function(done) { | ||
it('Import key pair', function() { | ||
// clear any keys already in the keychain | ||
keyring.clear(); | ||
keyring.importKey(privkey); | ||
keyring.importKey(pubkey); | ||
done(); | ||
keyring.store(); | ||
keyring.publicKeys.importKey(pubkey); | ||
keyring.publicKeys.importKey(pubkey2); | ||
keyring.privateKeys.importKey(privkey); | ||
}); | ||
it('getPublicKeyForAddress() - unknown address', function(done) { | ||
var key = keyring.getPublicKeyForAddress('nobody@example.com'); | ||
expect(key).to.be.empty; | ||
done(); | ||
it('getKeysForId() - unknown id', function() { | ||
var keys = keyring.getKeysForId('01234567890123456'); | ||
expect(keys).to.be.null; | ||
}); | ||
it('getPublicKeyForAddress() - valid address', function(done) { | ||
var key = keyring.getPublicKeyForAddress(user); | ||
expect(key).to.exist.and.have.length(1); | ||
done(); | ||
it('getKeysForId() - valid id', function() { | ||
var keys = keyring.getKeysForId(keyId); | ||
// we get public and private key | ||
expect(keys).to.exist.and.have.length(2); | ||
expect(keys[0].primaryKey.getKeyId().toHex()).equals(keyId); | ||
}); | ||
it('getPrivateKeyForAddress() - unknown address', function(done) { | ||
var key = keyring.getPrivateKeyForAddress('nobody@example.com'); | ||
expect(key).to.be.empty; | ||
done(); | ||
it('publicKeys.getForId() - unknown id', function() { | ||
var key = keyring.publicKeys.getForId('01234567890123456'); | ||
expect(key).to.be.null; | ||
}); | ||
it('getPrivateKeyForAddress() - valid address', function(done) { | ||
var key = keyring.getPrivateKeyForAddress(user); | ||
expect(key).to.exist.and.have.length(1); | ||
done(); | ||
it('publicKeys.getForId() - valid id', function() { | ||
var key = keyring.publicKeys.getForId(keyId); | ||
expect(key).to.exist.and.be.an.instanceof(openpgp.key.Key); | ||
expect(key.primaryKey.getKeyId().toHex()).equals(keyId); | ||
}); | ||
it('getKeysForKeyId() - unknown id', function(done) { | ||
var keys = keyring.getKeysForKeyId('000102030405060708'); | ||
it('privateKeys.getForId() - unknown id', function() { | ||
var key = keyring.privateKeys.getForId('01234567890123456'); | ||
expect(key).to.be.null; | ||
}); | ||
it('privateKeys.getForId() - valid id', function() { | ||
var key = keyring.privateKeys.getForId(keyId); | ||
expect(key).to.exist.and.be.an.instanceof(openpgp.key.Key); | ||
expect(key.primaryKey.getKeyId().toHex()).equals(keyId); | ||
}); | ||
it('publicKeys.getForId() - subkey id', function() { | ||
var key = keyring.publicKeys.getForId(subkeyId2); | ||
expect(key).to.be.null; | ||
}); | ||
it('publicKeys.getForId() - deep, including subkeys - subkey id', function() { | ||
var key = keyring.publicKeys.getForId(subkeyId2, true); | ||
expect(key).to.exist.and.be.an.instanceof(openpgp.key.Key); | ||
expect(key.primaryKey.getKeyId().toHex()).equals(keyId2); | ||
}); | ||
it('getKeysForId() - unknown fingerprint', function() { | ||
var keys = keyring.getKeysForId('71130e8383bef9526e062600d5e9f93acbbc7275'); | ||
expect(keys).to.be.null; | ||
}); | ||
it('getKeysForId() - valid fingerprint', function() { | ||
var keys = keyring.getKeysForId(keyFingerP2); | ||
expect(keys).to.exist.and.have.length(1); | ||
expect(keys[0].primaryKey.getKeyId().toHex()).equals(keyId2); | ||
}); | ||
it('publicKeys.getForId() - unknown fingerprint', function() { | ||
var key = keyring.publicKeys.getForId('71130e8383bef9526e062600d5e9f93acbbc7275'); | ||
expect(key).to.be.null; | ||
}); | ||
it('publicKeys.getForId() - valid fingerprint', function() { | ||
var key = keyring.publicKeys.getForId(keyFingerP2); | ||
expect(key).to.exist.and.be.an.instanceof(openpgp.key.Key); | ||
expect(key.primaryKey.getKeyId().toHex()).equals(keyId2); | ||
}); | ||
it('publicKeys.getForId() - subkey fingerprint', function() { | ||
var key = keyring.publicKeys.getForId(subkeyFingerP2); | ||
expect(key).to.be.null; | ||
}); | ||
it('publicKeys.getForId() - deep, including subkeys - subkey fingerprint', function() { | ||
var key = keyring.publicKeys.getForId(subkeyFingerP2, true); | ||
expect(key).to.exist.and.be.an.instanceof(openpgp.key.Key); | ||
expect(key.primaryKey.getKeyId().toHex()).equals(keyId2); | ||
}); | ||
it('publicKeys.getForAddress() - unknown address', function() { | ||
var keys = keyring.publicKeys.getForAddress('nobody@example.com'); | ||
expect(keys).to.be.empty; | ||
done(); | ||
}); | ||
it('getKeysForKeyId() - valid id', function(done) { | ||
var keys = keyring.getKeysForKeyId(keyId.toLowerCase()); | ||
it('publicKeys.getForAddress() - valid address', function() { | ||
var keys = keyring.publicKeys.getForAddress(user); | ||
expect(keys).to.exist.and.have.length(1); | ||
done(); | ||
}); | ||
it('store keys in localstorage', function(done){ | ||
it('privateKeys.getForAddress() - unknown address', function() { | ||
var key = keyring.privateKeys.getForAddress('nobody@example.com'); | ||
expect(key).to.be.empty; | ||
}); | ||
it('privateKeys.getForAddress() - valid address', function() { | ||
var key = keyring.privateKeys.getForAddress(user); | ||
expect(key).to.exist.and.have.length(1); | ||
}); | ||
it('store keys in localstorage', function(){ | ||
keyring.store(); | ||
done(); | ||
}); | ||
it('after loading from localstorage: getKeysForKeyId() - valid id', function(done) { | ||
it('after loading from localstorage: getKeysForKeyId() - valid id', function() { | ||
var keyring = new openpgp.Keyring(), | ||
keys = keyring.getKeysForKeyId(keyId.toLowerCase()); | ||
expect(keys).to.exist.and.have.length(1); | ||
done(); | ||
keys = keyring.getKeysForId(keyId); | ||
// we expect public and private key | ||
expect(keys).to.exist.and.have.length(2); | ||
}); | ||
it('publicKeys.removeForId() - unknown id', function() { | ||
var key = keyring.publicKeys.removeForId('01234567890123456'); | ||
expect(key).to.be.null; | ||
}); | ||
it('publicKeys.removeForId() - valid id', function() { | ||
var key = keyring.publicKeys.removeForId(keyId); | ||
expect(key).to.exist.and.be.an.instanceof(openpgp.key.Key); | ||
expect(key.primaryKey.getKeyId().toHex()).equals(keyId); | ||
expect(keyring.publicKeys.keys).to.exist.and.have.length(1); | ||
}); | ||
it('publicKeys.removeForId() - unknown fingerprint', function() { | ||
var key = keyring.publicKeys.removeForId('71130e8383bef9526e062600d5e9f93acbbc7275'); | ||
expect(key).to.be.null; | ||
expect(keyring.publicKeys.keys).to.exist.and.have.length(1); | ||
}); | ||
it('publicKeys.removeForId() - valid fingerprint', function() { | ||
var key = keyring.publicKeys.removeForId(keyFingerP2); | ||
expect(key).to.exist.and.be.an.instanceof(openpgp.key.Key); | ||
expect(key.primaryKey.getKeyId().toHex()).equals(keyId2); | ||
expect(keyring.publicKeys.keys).to.be.empty; | ||
}); | ||
it('customize localstorage itemname', function() { | ||
var localstore1 = new openpgp.Keyring.localstore('my-custom-name'); | ||
var localstore2 = new openpgp.Keyring.localstore('my-custom-name'); | ||
var localstore1 = new openpgp.Keyring.localstore('my-custom-prefix-'); | ||
var localstore2 = new openpgp.Keyring.localstore('my-custom-prefix-'); | ||
var localstore3 = new openpgp.Keyring.localstore(); | ||
localstore3.store([]); | ||
localstore3.storePublic([]); | ||
var key = openpgp.key.readArmored(pubkey).keys[0]; | ||
localstore1.store([key]); | ||
expect(localstore2.load()[0].primaryKey.getKeyId().equals(key.primaryKey.getKeyId())).to.be.true; | ||
expect(localstore3.load()).to.have.length(0); | ||
localstore1.storePublic([key]); | ||
expect(localstore2.loadPublic()[0].primaryKey.getKeyId().equals(key.primaryKey.getKeyId())).to.be.true; | ||
expect(localstore3.loadPublic()).to.have.length(0); | ||
}); | ||
it('removeKeysForId() - unknown id', function() { | ||
keyring.publicKeys.importKey(pubkey); | ||
keyring.publicKeys.importKey(pubkey2); | ||
keyring.privateKeys.importKey(privkey); | ||
expect(keyring.publicKeys.keys).to.have.length(2); | ||
expect(keyring.privateKeys.keys).to.have.length(1); | ||
var keys = keyring.removeKeysForId('01234567890123456'); | ||
expect(keys).to.be.null; | ||
expect(keyring.publicKeys.keys).to.have.length(2); | ||
expect(keyring.privateKeys.keys).to.have.length(1); | ||
}); | ||
it('removeKeysForId() - valid id', function() { | ||
var keys = keyring.removeKeysForId(keyId); | ||
expect(keys).to.have.length(2); | ||
expect(keyring.publicKeys.keys).to.have.length(1); | ||
expect(keyring.privateKeys.keys).to.have.length(0); | ||
}); | ||
it('removeKeysForId() - unknown fingerprint', function() { | ||
keyring.publicKeys.importKey(pubkey); | ||
keyring.publicKeys.importKey(pubkey2); | ||
keyring.privateKeys.importKey(privkey); | ||
expect(keyring.publicKeys.keys).to.have.length(2); | ||
expect(keyring.privateKeys.keys).to.have.length(1); | ||
var keys = keyring.removeKeysForId('71130e8383bef9526e062600d5e9f93acbbc7275'); | ||
expect(keys).to.be.null; | ||
expect(keyring.publicKeys.keys).to.have.length(2); | ||
expect(keyring.privateKeys.keys).to.have.length(1); | ||
}); | ||
it('removeKeysForId() - valid fingerprint', function() { | ||
var keys = keyring.removeKeysForId(keyFingerP); | ||
expect(keys).to.have.length(2); | ||
expect(keyring.publicKeys.keys).to.have.length(1); | ||
expect(keyring.privateKeys.keys).to.have.length(0); | ||
}); | ||
}); | ||
'use strict'; | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('../../src/index'); | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('openpgp'); | ||
@@ -5,0 +5,0 @@ var chai = require('chai'), |
'use strict'; | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('../../src/index'); | ||
var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp : require('openpgp'); | ||
@@ -80,4 +80,2 @@ var chai = require('chai'), | ||
'Version: GnuPG v2.0.19 (GNU/Linux)', | ||
'Type: RSA/RSA', | ||
'Pwd: hello world', | ||
'', | ||
@@ -124,3 +122,2 @@ 'lQH+BFJhL04BBADclrUEDDsm0PSZbQ6pml9FpzTyXiyCyDN+rMOsy9J300Oc10kt', | ||
'Version: GnuPG v2.0.19 (GNU/Linux)', | ||
'Type: RSA/RSA', | ||
'', | ||
@@ -576,2 +573,10 @@ 'mI0EUmEvTgEEANyWtQQMOybQ9JltDqmaX0WnNPJeLILIM36sw6zL0nfTQ5zXSS3+', | ||
}); | ||
it('Write unhashed subpackets', function() { | ||
var pubKey = openpgp.key.readArmored(pub_key_arm2).keys[0]; | ||
expect(pubKey.users[0].selfCertifications).to.exist; | ||
pubKey = openpgp.key.readArmored(pubKey.armor()).keys[0] | ||
expect(pubKey.users[0].selfCertifications).to.exist; | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
718589
86
17770