0) {
if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); }
while(i >= 0) {
if(p < k) {
d = (this[i]&((1<>(p+=this.DB-k);
}
else {
d = (this[i]>>(p-=k))&km;
if(p <= 0) { p += this.DB; --i; }
}
if(d > 0) m = true;
if(m) r += int2char(d);
}
}
return m?r:"0";
}
// (public) -this
function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }
// (public) |this|
function bnAbs() { return (this.s<0)?this.negate():this; }
// (public) return + if this > a, - if this < a, 0 if equal
function bnCompareTo(a) {
var r = this.s-a.s;
if(r != 0) return r;
var i = this.t;
r = i-a.t;
if(r != 0) return r;
while(--i >= 0) if((r=this[i]-a[i]) != 0) return r;
return 0;
}
// returns bit length of the integer x
function nbits(x) {
var r = 1, t;
if((t=x>>>16) != 0) { x = t; r += 16; }
if((t=x>>8) != 0) { x = t; r += 8; }
if((t=x>>4) != 0) { x = t; r += 4; }
if((t=x>>2) != 0) { x = t; r += 2; }
if((t=x>>1) != 0) { x = t; r += 1; }
return r;
}
// (public) return the number of bits in "this"
function bnBitLength() {
if(this.t <= 0) return 0;
return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM));
}
// (protected) r = this << n*DB
function bnpDLShiftTo(n,r) {
var i;
for(i = this.t-1; i >= 0; --i) r[i+n] = this[i];
for(i = n-1; i >= 0; --i) r[i] = 0;
r.t = this.t+n;
r.s = this.s;
}
// (protected) r = this >> n*DB
function bnpDRShiftTo(n,r) {
for(var i = n; i < this.t; ++i) r[i-n] = this[i];
r.t = Math.max(this.t-n,0);
r.s = this.s;
}
// (protected) r = this << n
function bnpLShiftTo(n,r) {
var bs = n%this.DB;
var cbs = this.DB-bs;
var bm = (1<= 0; --i) {
r[i+ds+1] = (this[i]>>cbs)|c;
c = (this[i]&bm)<= 0; --i) r[i] = 0;
r[ds] = c;
r.t = this.t+ds+1;
r.s = this.s;
r.clamp();
}
// (protected) r = this >> n
function bnpRShiftTo(n,r) {
r.s = this.s;
var ds = Math.floor(n/this.DB);
if(ds >= this.t) { r.t = 0; return; }
var bs = n%this.DB;
var cbs = this.DB-bs;
var bm = (1<>bs;
for(var i = ds+1; i < this.t; ++i) {
r[i-ds-1] |= (this[i]&bm)<>bs;
}
if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<>= this.DB;
}
if(a.t < this.t) {
c -= a.s;
while(i < this.t) {
c += this[i];
r[i++] = c&this.DM;
c >>= this.DB;
}
c += this.s;
}
else {
c += this.s;
while(i < a.t) {
c -= a[i];
r[i++] = c&this.DM;
c >>= this.DB;
}
c -= a.s;
}
r.s = (c<0)?-1:0;
if(c < -1) r[i++] = this.DV+c;
else if(c > 0) r[i++] = c;
r.t = i;
r.clamp();
}
// (protected) r = this * a, r != this,a (HAC 14.12)
// "this" should be the larger one if appropriate.
function bnpMultiplyTo(a,r) {
var x = this.abs(), y = a.abs();
var i = x.t;
r.t = i+y.t;
while(--i >= 0) r[i] = 0;
for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t);
r.s = 0;
r.clamp();
if(this.s != a.s) BigInteger.ZERO.subTo(r,r);
}
// (protected) r = this^2, r != this (HAC 14.16)
function bnpSquareTo(r) {
var x = this.abs();
var i = r.t = 2*x.t;
while(--i >= 0) r[i] = 0;
for(i = 0; i < x.t-1; ++i) {
var c = x.am(i,x[i],r,2*i,0,1);
if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) {
r[i+x.t] -= x.DV;
r[i+x.t+1] = 1;
}
}
if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1);
r.s = 0;
r.clamp();
}
// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
// r != q, this != m. q or r may be null.
function bnpDivRemTo(m,q,r) {
var pm = m.abs();
if(pm.t <= 0) return;
var pt = this.abs();
if(pt.t < pm.t) {
if(q != null) q.fromInt(0);
if(r != null) this.copyTo(r);
return;
}
if(r == null) r = nbi();
var y = nbi(), ts = this.s, ms = m.s;
var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus
if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); }
else { pm.copyTo(y); pt.copyTo(r); }
var ys = y.t;
var y0 = y[ys-1];
if(y0 == 0) return;
var yt = y0*(1<1)?y[ys-2]>>this.F2:0);
var d1 = this.FV/yt, d2 = (1<= 0) {
r[r.t++] = 1;
r.subTo(t,r);
}
BigInteger.ONE.dlShiftTo(ys,t);
t.subTo(y,y); // "negative" y so we can replace sub with am later
while(y.t < ys) y[y.t++] = 0;
while(--j >= 0) {
// Estimate quotient digit
var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);
if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out
y.dlShiftTo(j,t);
r.subTo(t,r);
while(r[i] < --qd) r.subTo(t,r);
}
}
if(q != null) {
r.drShiftTo(ys,q);
if(ts != ms) BigInteger.ZERO.subTo(q,q);
}
r.t = ys;
r.clamp();
if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder
if(ts < 0) BigInteger.ZERO.subTo(r,r);
}
// (public) this mod a
function bnMod(a) {
var r = nbi();
this.abs().divRemTo(a,null,r);
if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r);
return r;
}
// Modular reduction using "classic" algorithm
function Classic(m) { this.m = m; }
function cConvert(x) {
if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
else return x;
}
function cRevert(x) { return x; }
function cReduce(x) { x.divRemTo(this.m,null,x); }
function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
Classic.prototype.convert = cConvert;
Classic.prototype.revert = cRevert;
Classic.prototype.reduce = cReduce;
Classic.prototype.mulTo = cMulTo;
Classic.prototype.sqrTo = cSqrTo;
// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
// justification:
// xy == 1 (mod m)
// xy = 1+km
// xy(2-xy) = (1+km)(1-km)
// x[y(2-xy)] = 1-k^2m^2
// x[y(2-xy)] == 1 (mod m^2)
// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
// JS multiply "overflows" differently from C/C++, so care is needed here.
function bnpInvDigit() {
if(this.t < 1) return 0;
var x = this[0];
if((x&1) == 0) return 0;
var y = x&3; // y == 1/x mod 2^2
y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4
y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8
y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16
// last step - calculate inverse mod DV directly;
// assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits
// we really want the negative inverse, and -DV < y < DV
return (y>0)?this.DV-y:-y;
}
// Montgomery reduction
function Montgomery(m) {
this.m = m;
this.mp = m.invDigit();
this.mpl = this.mp&0x7fff;
this.mph = this.mp>>15;
this.um = (1<<(m.DB-15))-1;
this.mt2 = 2*m.t;
}
// xR mod m
function montConvert(x) {
var r = nbi();
x.abs().dlShiftTo(this.m.t,r);
r.divRemTo(this.m,null,r);
if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r);
return r;
}
// x/R mod m
function montRevert(x) {
var r = nbi();
x.copyTo(r);
this.reduce(r);
return r;
}
// x = x/R mod m (HAC 14.32)
function montReduce(x) {
while(x.t <= this.mt2) // pad x so am has enough room later
x[x.t++] = 0;
for(var i = 0; i < this.m.t; ++i) {
// faster way of calculating u0 = x[i]*mp mod DV
var j = x[i]&0x7fff;
var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM;
// use am to combine the multiply-shift-add into one call
j = i+this.m.t;
x[j] += this.m.am(0,u0,x,i,0,this.m.t);
// propagate carry
while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; }
}
x.clamp();
x.drShiftTo(this.m.t,x);
if(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
}
// r = "x^2/R mod m"; x != r
function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
// r = "xy/R mod m"; x,y != r
function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
Montgomery.prototype.convert = montConvert;
Montgomery.prototype.revert = montRevert;
Montgomery.prototype.reduce = montReduce;
Montgomery.prototype.mulTo = montMulTo;
Montgomery.prototype.sqrTo = montSqrTo;
// (protected) true iff this is even
function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; }
// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
function bnpExp(e,z) {
if(e > 0xffffffff || e < 1) return BigInteger.ONE;
var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1;
g.copyTo(r);
while(--i >= 0) {
z.sqrTo(r,r2);
if((e&(1< 0) z.mulTo(r2,g,r);
else { var t = r; r = r2; r2 = t; }
}
return z.revert(r);
}
// (public) this^e % m, 0 <= e < 2^32
function bnModPowInt(e,m) {
var z;
if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
return this.exp(e,z);
}
// protected
BigInteger.prototype.copyTo = bnpCopyTo;
BigInteger.prototype.fromInt = bnpFromInt;
BigInteger.prototype.fromString = bnpFromString;
BigInteger.prototype.clamp = bnpClamp;
BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
BigInteger.prototype.drShiftTo = bnpDRShiftTo;
BigInteger.prototype.lShiftTo = bnpLShiftTo;
BigInteger.prototype.rShiftTo = bnpRShiftTo;
BigInteger.prototype.subTo = bnpSubTo;
BigInteger.prototype.multiplyTo = bnpMultiplyTo;
BigInteger.prototype.squareTo = bnpSquareTo;
BigInteger.prototype.divRemTo = bnpDivRemTo;
BigInteger.prototype.invDigit = bnpInvDigit;
BigInteger.prototype.isEven = bnpIsEven;
BigInteger.prototype.exp = bnpExp;
// public
BigInteger.prototype.toString = bnToString;
BigInteger.prototype.negate = bnNegate;
BigInteger.prototype.abs = bnAbs;
BigInteger.prototype.compareTo = bnCompareTo;
BigInteger.prototype.bitLength = bnBitLength;
BigInteger.prototype.mod = bnMod;
BigInteger.prototype.modPowInt = bnModPowInt;
// "constants"
BigInteger.ZERO = nbv(0);
BigInteger.ONE = nbv(1);
module.exports = BigInteger;
/*
* Copyright (c) 2003-2005 Tom Wu (tjw@cs.Stanford.EDU)
* All Rights Reserved.
*
* Modified by Recurity Labs GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
*
* IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
* THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* In addition, the following condition applies:
*
* All redistributions must retain an intact copy of this copyright notice
* and disclaimer.
*/
// Extended JavaScript BN functions, required for RSA private ops.
// Version 1.1: new BigInteger("0", 10) returns "proper" zero
// Version 1.2: square() API, isProbablePrime fix
// (public)
function bnClone() { var r = nbi(); this.copyTo(r); return r; }
// (public) return value as integer
function bnIntValue() {
if(this.s < 0) {
if(this.t == 1) return this[0]-this.DV;
else if(this.t == 0) return -1;
}
else if(this.t == 1) return this[0];
else if(this.t == 0) return 0;
// assumes 16 < DB < 32
return ((this[1]&((1<<(32-this.DB))-1))<>24; }
// (public) return value as short (assumes DB>=16)
function bnShortValue() { return (this.t==0)?this.s:(this[0]<<16)>>16; }
// (protected) return x s.t. r^x < DV
function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); }
// (public) 0 if this == 0, 1 if this > 0
function bnSigNum() {
if(this.s < 0) return -1;
else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
else return 1;
}
// (protected) convert to radix string
function bnpToRadix(b) {
if(b == null) b = 10;
if(this.signum() == 0 || b < 2 || b > 36) return "0";
var cs = this.chunkSize(b);
var a = Math.pow(b,cs);
var d = nbv(a), y = nbi(), z = nbi(), r = "";
this.divRemTo(d,y,z);
while(y.signum() > 0) {
r = (a+z.intValue()).toString(b).substr(1) + r;
y.divRemTo(d,y,z);
}
return z.intValue().toString(b) + r;
}
// (protected) convert from radix string
function bnpFromRadix(s,b) {
this.fromInt(0);
if(b == null) b = 10;
var cs = this.chunkSize(b);
var d = Math.pow(b,cs), mi = false, j = 0, w = 0;
for(var i = 0; i < s.length; ++i) {
var x = intAt(s,i);
if(x < 0) {
if(s.charAt(i) == "-" && this.signum() == 0) mi = true;
continue;
}
w = b*w+x;
if(++j >= cs) {
this.dMultiply(d);
this.dAddOffset(w,0);
j = 0;
w = 0;
}
}
if(j > 0) {
this.dMultiply(Math.pow(b,j));
this.dAddOffset(w,0);
}
if(mi) BigInteger.ZERO.subTo(this,this);
}
// (protected) alternate constructor
function bnpFromNumber(a,b,c) {
if("number" == typeof b) {
// new BigInteger(int,int,RNG)
if(a < 2) this.fromInt(1);
else {
this.fromNumber(a,c);
if(!this.testBit(a-1)) // force MSB set
this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this);
if(this.isEven()) this.dAddOffset(1,0); // force odd
while(!this.isProbablePrime(b)) {
this.dAddOffset(2,0);
if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this);
}
}
}
else {
// new BigInteger(int,RNG)
var x = new Array(), t = a&7;
x.length = (a>>3)+1;
b.nextBytes(x);
if(t > 0) x[0] &= ((1< 0) {
if(p < this.DB && (d = this[i]>>p) != (this.s&this.DM)>>p)
r[k++] = d|(this.s<<(this.DB-p));
while(i >= 0) {
if(p < 8) {
d = (this[i]&((1<>(p+=this.DB-8);
}
else {
d = (this[i]>>(p-=8))&0xff;
if(p <= 0) { p += this.DB; --i; }
}
//if((d&0x80) != 0) d |= -256;
//if(k == 0 && (this.s&0x80) != (d&0x80)) ++k;
if(k > 0 || d != this.s) r[k++] = d;
}
}
return r;
}
function bnEquals(a) { return(this.compareTo(a)==0); }
function bnMin(a) { return(this.compareTo(a)<0)?this:a; }
function bnMax(a) { return(this.compareTo(a)>0)?this:a; }
// (protected) r = this op a (bitwise)
function bnpBitwiseTo(a,op,r) {
var i, f, m = Math.min(a.t,this.t);
for(i = 0; i < m; ++i) r[i] = op(this[i],a[i]);
if(a.t < this.t) {
f = a.s&this.DM;
for(i = m; i < this.t; ++i) r[i] = op(this[i],f);
r.t = this.t;
}
else {
f = this.s&this.DM;
for(i = m; i < a.t; ++i) r[i] = op(f,a[i]);
r.t = a.t;
}
r.s = op(this.s,a.s);
r.clamp();
}
// (public) this & a
function op_and(x,y) { return x&y; }
function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; }
// (public) this | a
function op_or(x,y) { return x|y; }
function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; }
// (public) this ^ a
function op_xor(x,y) { return x^y; }
function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; }
// (public) this & ~a
function op_andnot(x,y) { return x&~y; }
function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; }
// (public) ~this
function bnNot() {
var r = nbi();
for(var i = 0; i < this.t; ++i) r[i] = this.DM&~this[i];
r.t = this.t;
r.s = ~this.s;
return r;
}
// (public) this << n
function bnShiftLeft(n) {
var r = nbi();
if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r);
return r;
}
// (public) this >> n
function bnShiftRight(n) {
var r = nbi();
if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r);
return r;
}
// return index of lowest 1-bit in x, x < 2^31
function lbit(x) {
if(x == 0) return -1;
var r = 0;
if((x&0xffff) == 0) { x >>= 16; r += 16; }
if((x&0xff) == 0) { x >>= 8; r += 8; }
if((x&0xf) == 0) { x >>= 4; r += 4; }
if((x&3) == 0) { x >>= 2; r += 2; }
if((x&1) == 0) ++r;
return r;
}
// (public) returns index of lowest 1-bit (or -1 if none)
function bnGetLowestSetBit() {
for(var i = 0; i < this.t; ++i)
if(this[i] != 0) return i*this.DB+lbit(this[i]);
if(this.s < 0) return this.t*this.DB;
return -1;
}
// return number of 1 bits in x
function cbit(x) {
var r = 0;
while(x != 0) { x &= x-1; ++r; }
return r;
}
// (public) return number of set bits
function bnBitCount() {
var r = 0, x = this.s&this.DM;
for(var i = 0; i < this.t; ++i) r += cbit(this[i]^x);
return r;
}
// (public) true iff nth bit is set
function bnTestBit(n) {
var j = Math.floor(n/this.DB);
if(j >= this.t) return(this.s!=0);
return((this[j]&(1<<(n%this.DB)))!=0);
}
// (protected) this op (1<>= this.DB;
}
if(a.t < this.t) {
c += a.s;
while(i < this.t) {
c += this[i];
r[i++] = c&this.DM;
c >>= this.DB;
}
c += this.s;
}
else {
c += this.s;
while(i < a.t) {
c += a[i];
r[i++] = c&this.DM;
c >>= this.DB;
}
c += a.s;
}
r.s = (c<0)?-1:0;
if(c > 0) r[i++] = c;
else if(c < -1) r[i++] = this.DV+c;
r.t = i;
r.clamp();
}
// (public) this + a
function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; }
// (public) this - a
function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; }
// (public) this * a
function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; }
// (public) this^2
function bnSquare() { var r = nbi(); this.squareTo(r); return r; }
// (public) this / a
function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; }
// (public) this % a
function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; }
// (public) [this/a,this%a]
function bnDivideAndRemainder(a) {
var q = nbi(), r = nbi();
this.divRemTo(a,q,r);
return new Array(q,r);
}
// (protected) this *= n, this >= 0, 1 < n < DV
function bnpDMultiply(n) {
this[this.t] = this.am(0,n-1,this,0,0,this.t);
++this.t;
this.clamp();
}
// (protected) this += n << w words, this >= 0
function bnpDAddOffset(n,w) {
if(n == 0) return;
while(this.t <= w) this[this.t++] = 0;
this[w] += n;
while(this[w] >= this.DV) {
this[w] -= this.DV;
if(++w >= this.t) this[this.t++] = 0;
++this[w];
}
}
// A "null" reducer
function NullExp() {}
function nNop(x) { return x; }
function nMulTo(x,y,r) { x.multiplyTo(y,r); }
function nSqrTo(x,r) { x.squareTo(r); }
NullExp.prototype.convert = nNop;
NullExp.prototype.revert = nNop;
NullExp.prototype.mulTo = nMulTo;
NullExp.prototype.sqrTo = nSqrTo;
// (public) this^e
function bnPow(e) { return this.exp(e,new NullExp()); }
// (protected) r = lower n words of "this * a", a.t <= n
// "this" should be the larger one if appropriate.
function bnpMultiplyLowerTo(a,n,r) {
var i = Math.min(this.t+a.t,n);
r.s = 0; // assumes a,this >= 0
r.t = i;
while(i > 0) r[--i] = 0;
var j;
for(j = r.t-this.t; i < j; ++i) r[i+this.t] = this.am(0,a[i],r,i,0,this.t);
for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a[i],r,i,0,n-i);
r.clamp();
}
// (protected) r = "this * a" without lower n words, n > 0
// "this" should be the larger one if appropriate.
function bnpMultiplyUpperTo(a,n,r) {
--n;
var i = r.t = this.t+a.t-n;
r.s = 0; // assumes a,this >= 0
while(--i >= 0) r[i] = 0;
for(i = Math.max(n-this.t,0); i < a.t; ++i)
r[this.t+i-n] = this.am(n-i,a[i],r,0,0,this.t+i-n);
r.clamp();
r.drShiftTo(1,r);
}
// Barrett modular reduction
function Barrett(m) {
// setup Barrett
this.r2 = nbi();
this.q3 = nbi();
BigInteger.ONE.dlShiftTo(2*m.t,this.r2);
this.mu = this.r2.divide(m);
this.m = m;
}
function barrettConvert(x) {
if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m);
else if(x.compareTo(this.m) < 0) return x;
else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; }
}
function barrettRevert(x) { return x; }
// x = x mod m (HAC 14.42)
function barrettReduce(x) {
x.drShiftTo(this.m.t-1,this.r2);
if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); }
this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3);
this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);
while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1);
x.subTo(this.r2,x);
while(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
}
// r = x^2 mod m; x != r
function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
// r = x*y mod m; x,y != r
function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
Barrett.prototype.convert = barrettConvert;
Barrett.prototype.revert = barrettRevert;
Barrett.prototype.reduce = barrettReduce;
Barrett.prototype.mulTo = barrettMulTo;
Barrett.prototype.sqrTo = barrettSqrTo;
// (public) this^e % m (HAC 14.85)
function bnModPow(e,m) {
var i = e.bitLength(), k, r = nbv(1), z;
if(i <= 0) return r;
else if(i < 18) k = 1;
else if(i < 48) k = 3;
else if(i < 144) k = 4;
else if(i < 768) k = 5;
else k = 6;
if(i < 8)
z = new Classic(m);
else if(m.isEven())
z = new Barrett(m);
else
z = new Montgomery(m);
// precomputation
var g = new Array(), n = 3, k1 = k-1, km = (1< 1) {
var g2 = nbi();
z.sqrTo(g[1],g2);
while(n <= km) {
g[n] = nbi();
z.mulTo(g2,g[n-2],g[n]);
n += 2;
}
}
var j = e.t-1, w, is1 = true, r2 = nbi(), t;
i = nbits(e[j])-1;
while(j >= 0) {
if(i >= k1) w = (e[j]>>(i-k1))&km;
else {
w = (e[j]&((1<<(i+1))-1))<<(k1-i);
if(j > 0) w |= e[j-1]>>(this.DB+i-k1);
}
n = k;
while((w&1) == 0) { w >>= 1; --n; }
if((i -= n) < 0) { i += this.DB; --j; }
if(is1) { // ret == 1, don't bother squaring or multiplying it
g[w].copyTo(r);
is1 = false;
}
else {
while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; }
if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; }
z.mulTo(r2,g[w],r);
}
while(j >= 0 && (e[j]&(1< 0) {
x.rShiftTo(g,x);
y.rShiftTo(g,y);
}
while(x.signum() > 0) {
if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x);
if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y);
if(x.compareTo(y) >= 0) {
x.subTo(y,x);
x.rShiftTo(1,x);
}
else {
y.subTo(x,y);
y.rShiftTo(1,y);
}
}
if(g > 0) y.lShiftTo(g,y);
return y;
}
// (protected) this % n, n < 2^26
function bnpModInt(n) {
if(n <= 0) return 0;
var d = this.DV%n, r = (this.s<0)?n-1:0;
if(this.t > 0)
if(d == 0) r = this[0]%n;
else for(var i = this.t-1; i >= 0; --i) r = (d*r+this[i])%n;
return r;
}
// (public) 1/this % m (HAC 14.61)
function bnModInverse(m) {
var ac = m.isEven();
if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
var u = m.clone(), v = this.clone();
var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
while(u.signum() != 0) {
while(u.isEven()) {
u.rShiftTo(1,u);
if(ac) {
if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); }
a.rShiftTo(1,a);
}
else if(!b.isEven()) b.subTo(m,b);
b.rShiftTo(1,b);
}
while(v.isEven()) {
v.rShiftTo(1,v);
if(ac) {
if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); }
c.rShiftTo(1,c);
}
else if(!d.isEven()) d.subTo(m,d);
d.rShiftTo(1,d);
}
if(u.compareTo(v) >= 0) {
u.subTo(v,u);
if(ac) a.subTo(c,a);
b.subTo(d,b);
}
else {
v.subTo(u,v);
if(ac) c.subTo(a,c);
d.subTo(b,d);
}
}
if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
if(d.compareTo(m) >= 0) return d.subtract(m);
if(d.signum() < 0) d.addTo(m,d); else return d;
if(d.signum() < 0) return d.add(m); else return d;
}
var lowprimes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997];
var lplim = (1<<26)/lowprimes[lowprimes.length-1];
// (public) test primality with certainty >= 1-.5^t
function bnIsProbablePrime(t) {
var i, x = this.abs();
if(x.t == 1 && x[0] <= lowprimes[lowprimes.length-1]) {
for(i = 0; i < lowprimes.length; ++i)
if(x[0] == lowprimes[i]) return true;
return false;
}
if(x.isEven()) return false;
i = 1;
while(i < lowprimes.length) {
var m = lowprimes[i], j = i+1;
while(j < lowprimes.length && m < lplim) m *= lowprimes[j++];
m = x.modInt(m);
while(i < j) if(m%lowprimes[i++] == 0) return false;
}
return x.millerRabin(t);
}
/* added by Recurity Labs */
function nbits(x) {
var n = 1, t;
if ((t = x >>> 16) != 0) {
x = t;
n += 16;
}
if ((t = x >> 8) != 0) {
x = t;
n += 8;
}
if ((t = x >> 4) != 0) {
x = t;
n += 4;
}
if ((t = x >> 2) != 0) {
x = t;
n += 2;
}
if ((t = x >> 1) != 0) {
x = t;
n += 1;
}
return n;
}
function bnToMPI () {
var ba = this.toByteArray();
var size = (ba.length-1)*8+nbits(ba[0]);
var result = "";
result += String.fromCharCode((size & 0xFF00) >> 8);
result += String.fromCharCode(size & 0xFF);
result += util.bin2str(ba);
return result;
}
/* END of addition */
// (protected) true if probably prime (HAC 4.24, Miller-Rabin)
function bnpMillerRabin(t) {
var n1 = this.subtract(BigInteger.ONE);
var k = n1.getLowestSetBit();
if(k <= 0) return false;
var r = n1.shiftRight(k);
t = (t+1)>>1;
if(t > lowprimes.length) t = lowprimes.length;
var a = nbi();
for(var i = 0; i < t; ++i) {
//Pick bases at random, instead of starting at 2
a.fromInt(lowprimes[Math.floor(Math.random()*lowprimes.length)]);
var y = a.modPow(r,this);
if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {
var j = 1;
while(j++ < k && y.compareTo(n1) != 0) {
y = y.modPowInt(2,this);
if(y.compareTo(BigInteger.ONE) == 0) return false;
}
if(y.compareTo(n1) != 0) return false;
}
}
return true;
}
var BigInteger = require('./jsbn.js');
// protected
BigInteger.prototype.chunkSize = bnpChunkSize;
BigInteger.prototype.toRadix = bnpToRadix;
BigInteger.prototype.fromRadix = bnpFromRadix;
BigInteger.prototype.fromNumber = bnpFromNumber;
BigInteger.prototype.bitwiseTo = bnpBitwiseTo;
BigInteger.prototype.changeBit = bnpChangeBit;
BigInteger.prototype.addTo = bnpAddTo;
BigInteger.prototype.dMultiply = bnpDMultiply;
BigInteger.prototype.dAddOffset = bnpDAddOffset;
BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo;
BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo;
BigInteger.prototype.modInt = bnpModInt;
BigInteger.prototype.millerRabin = bnpMillerRabin;
// public
BigInteger.prototype.clone = bnClone;
BigInteger.prototype.intValue = bnIntValue;
BigInteger.prototype.byteValue = bnByteValue;
BigInteger.prototype.shortValue = bnShortValue;
BigInteger.prototype.signum = bnSigNum;
BigInteger.prototype.toByteArray = bnToByteArray;
BigInteger.prototype.equals = bnEquals;
BigInteger.prototype.min = bnMin;
BigInteger.prototype.max = bnMax;
BigInteger.prototype.and = bnAnd;
BigInteger.prototype.or = bnOr;
BigInteger.prototype.xor = bnXor;
BigInteger.prototype.andNot = bnAndNot;
BigInteger.prototype.not = bnNot;
BigInteger.prototype.shiftLeft = bnShiftLeft;
BigInteger.prototype.shiftRight = bnShiftRight;
BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit;
BigInteger.prototype.bitCount = bnBitCount;
BigInteger.prototype.testBit = bnTestBit;
BigInteger.prototype.setBit = bnSetBit;
BigInteger.prototype.clearBit = bnClearBit;
BigInteger.prototype.flipBit = bnFlipBit;
BigInteger.prototype.add = bnAdd;
BigInteger.prototype.subtract = bnSubtract;
BigInteger.prototype.multiply = bnMultiply;
BigInteger.prototype.divide = bnDivide;
BigInteger.prototype.remainder = bnRemainder;
BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder;
BigInteger.prototype.modPow = bnModPow;
BigInteger.prototype.modInverse = bnModInverse;
BigInteger.prototype.pow = bnPow;
BigInteger.prototype.gcd = bnGCD;
BigInteger.prototype.isProbablePrime = bnIsProbablePrime;
BigInteger.prototype.toMPI = bnToMPI;
// JSBN-specific extension
BigInteger.prototype.square = bnSquare;
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
// RSA implementation
var BigInteger = require('./jsbn.js'),
util = require('../../util'),
random = require('../random.js');
function SecureRandom(){
function nextBytes(byteArray){
for(var n = 0; n < byteArray.length;n++){
byteArray[n] = random.getSecureRandomOctet();
}
}
this.nextBytes = nextBytes;
}
function RSA() {
/**
* This function uses jsbn Big Num library to decrypt RSA
* @param m
* message
* @param d
* RSA d as BigInteger
* @param p
* RSA p as BigInteger
* @param q
* RSA q as BigInteger
* @param u
* RSA u as BigInteger
* @return {BigInteger} The decrypted value of the message
*/
function decrypt(m, d, p, q, u) {
var xp = m.mod(p).modPow(d.mod(p.subtract(BigInteger.ONE)), p);
var xq = m.mod(q).modPow(d.mod(q.subtract(BigInteger.ONE)), q);
util.print_debug("rsa.js decrypt\nxpn:"+util.hexstrdump(xp.toMPI())+"\nxqn:"+util.hexstrdump(xq.toMPI()));
var t = xq.subtract(xp);
if (t[0] == 0) {
t = xp.subtract(xq);
t = t.multiply(u).mod(q);
t = q.subtract(t);
} else {
t = t.multiply(u).mod(q);
}
return t.multiply(p).add(xp);
}
/**
* encrypt message
* @param m message as BigInteger
* @param e public MPI part as BigInteger
* @param n public MPI part as BigInteger
* @return BigInteger
*/
function encrypt(m,e,n) {
return m.modPowInt(e, n);
}
/* Sign and Verify */
function sign(m,d,n) {
return m.modPow(d, n);
}
function verify(x,e,n) {
return x.modPowInt(e, n);
}
// "empty" RSA key constructor
function keyObject() {
this.n = null;
this.e = 0;
this.ee = null;
this.d = null;
this.p = null;
this.q = null;
this.dmp1 = null;
this.dmq1 = null;
this.u = null;
}
// Generate a new random private key B bits long, using public expt E
function generate(B,E) {
var key = new keyObject();
var rng = new SecureRandom();
var qs = B>>1;
key.e = parseInt(E,16);
key.ee = new BigInteger(E,16);
for(;;) {
for(;;) {
key.p = new BigInteger(B-qs,1,rng);
if(key.p.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) == 0 && key.p.isProbablePrime(10)) break;
}
for(;;) {
key.q = new BigInteger(qs,1,rng);
if(key.q.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) == 0 && key.q.isProbablePrime(10)) break;
}
if(key.p.compareTo(key.q) <= 0) {
var t = key.p;
key.p = key.q;
key.q = t;
}
var p1 = key.p.subtract(BigInteger.ONE);
var q1 = key.q.subtract(BigInteger.ONE);
var phi = p1.multiply(q1);
if(phi.gcd(key.ee).compareTo(BigInteger.ONE) == 0) {
key.n = key.p.multiply(key.q);
key.d = key.ee.modInverse(phi);
key.dmp1 = key.d.mod(p1);
key.dmq1 = key.d.mod(q1);
key.u = key.p.modInverse(key.q);
break;
}
}
return key;
}
this.encrypt = encrypt;
this.decrypt = decrypt;
this.verify = verify;
this.sign = sign;
this.generate = generate;
this.keyObject = keyObject;
}
module.exports = RSA;
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
// The GPG4Browsers crypto interface
var type_mpi = require('../type/mpi.js');
module.exports = {
/**
* Retrieve secure random byte string of the specified length
* @param {Integer} length Length in bytes to generate
* @return {String} Random byte string
*/
getRandomBytes: function(length) {
var result = '';
for (var i = 0; i < length; i++) {
result += String.fromCharCode(this.getSecureRandomOctet());
}
return result;
},
/**
* 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
* @param {Integer} from Min of the random number
* @param {Integer} to Max of the random number (max 32bit)
* @return {Integer} A secure random number
*/
getSecureRandom: function(from, to) {
var buf = new Uint32Array(1);
window.crypto.getRandomValues(buf);
var bits = ((to-from)).toString(2).length;
while ((buf[0] & (Math.pow(2, bits) -1)) > (to-from))
window.crypto.getRandomValues(buf);
return from+(Math.abs(buf[0] & (Math.pow(2, bits) -1)));
},
getSecureRandomOctet: function() {
var buf = new Uint32Array(1);
window.crypto.getRandomValues(buf);
return buf[0] & 0xFF;
},
/**
* Create a secure random big integer of bits length
* @param {Integer} bits Bit length of the MPI to create
* @return {BigInteger} Resulting big integer
*/
getRandomBigInteger: function(bits) {
if (bits < 0) {
return null;
}
var numBytes = Math.floor((bits+7)/8);
var randomBits = this.getRandomBytes(numBytes);
if (bits % 8 > 0) {
randomBits = String.fromCharCode(
(Math.pow(2,bits % 8)-1) &
randomBits.charCodeAt(0)) +
randomBits.substring(1);
}
var mpi = new type_mpi();
mpi.fromBytes(randomBits);
return mpi.toBigInteger();
},
getRandomBigIntegerInRange: function(min, max) {
if (max.compareTo(min) <= 0) {
return;
}
var range = max.subtract(min);
var r = this.getRandomBigInteger(range.bitLength());
while (r > range) {
r = this.getRandomBigInteger(range.bitLength());
}
return min.add(r);
}
};
var publicKey = require('./public_key'),
pkcs1 = require('./pkcs1.js'),
hashModule = require('./hash');
module.exports = {
/**
*
* @param {Integer} algo public Key algorithm
* @param {Integer} hash_algo Hash algorithm
* @param {openpgp_type_mpi[]} msg_MPIs Signature multiprecision integers
* @param {openpgp_type_mpi[]} publickey_MPIs Public key multiprecision integers
* @param {String} 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) {
var calc_hash = hashModule.digest(hash_algo, data);
switch(algo) {
case 1: // RSA (Encrypt or Sign) [HAC]
case 2: // RSA Encrypt-Only [HAC]
case 3: // RSA Sign-Only [HAC]
var rsa = new publicKey.rsa();
var n = publickey_MPIs[0].toBigInteger();
var e = publickey_MPIs[1].toBigInteger();
var x = msg_MPIs[0].toBigInteger();
var 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;
case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
throw new Error("signing with Elgamal is not defined in the OpenPGP standard.");
case 17: // DSA (Digital Signature Algorithm) [FIPS186] [HAC]
var dsa = new publicKey.dsa();
var s1 = msg_MPIs[0].toBigInteger();
var s2 = msg_MPIs[1].toBigInteger();
var p = publickey_MPIs[0].toBigInteger();
var q = publickey_MPIs[1].toBigInteger();
var g = publickey_MPIs[2].toBigInteger();
var y = publickey_MPIs[3].toBigInteger();
var m = data;
var dopublic = dsa.verify(hash_algo,s1,s2,m,p,q,g,y);
return dopublic.compareTo(s1) == 0;
default:
throw new Error('Invalid signature algorithm.');
}
},
/**
* Create a signature on data using the specified algorithm
* @param {Integer} hash_algo hash Algorithm to use (See RFC4880 9.4)
* @param {Integer} algo Asymmetric cipher algorithm to use (See RFC4880 9.1)
* @param {openpgp_type_mpi[]} publicMPIs Public key multiprecision integers
* of the private key
* @param {openpgp_type_mpi[]} secretMPIs Private key multiprecision
* integers which is used to sign the data
* @param {String} data Data to be signed
* @return {openpgp_type_mpi[]}
*/
sign: function(hash_algo, algo, keyIntegers, data) {
switch(algo) {
case 1: // RSA (Encrypt or Sign) [HAC]
case 2: // RSA Encrypt-Only [HAC]
case 3: // RSA Sign-Only [HAC]
var rsa = new publicKey.rsa();
var d = keyIntegers[2].toBigInteger();
var n = keyIntegers[0].toBigInteger();
var m = pkcs1.emsa.encode(hash_algo,
data, keyIntegers[0].byteLength());
return rsa.sign(m, d, n).toMPI();
case 17: // DSA (Digital Signature Algorithm) [FIPS186] [HAC]
var dsa = new publicKey.dsa();
var p = keyIntegers[0].toBigInteger();
var q = keyIntegers[1].toBigInteger();
var g = keyIntegers[2].toBigInteger();
var y = keyIntegers[3].toBigInteger();
var x = keyIntegers[4].toBigInteger();
var m = data;
var result = dsa.sign(hash_algo,m, g, p, q, x);
return result[0].toString() + result[1].toString();
case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
throw new Error('Signing with Elgamal is not defined in the OpenPGP standard.');
default:
throw new Error('Invalid signature algorithm.');
}
}
}
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
var base64 = require('./base64.js');
/**
* Finds out which Ascii Armoring type is used. This is an internal function
* @param {String} text [String] ascii armored text
* @returns {Integer} 0 = MESSAGE PART n of m
* 1 = MESSAGE PART n
* 2 = SIGNED MESSAGE
* 3 = PGP MESSAGE
* 4 = PUBLIC KEY BLOCK
* 5 = PRIVATE KEY BLOCK
* null = unknown
*/
function get_type(text) {
var splittedtext = text.split('-----');
// 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 (splittedtext[1].match(/BEGIN PGP MESSAGE, PART \d+\/\d+/)) {
return 0;
} else
// BEGIN PGP MESSAGE, PART X
// Used for multi-part messages, where this is the Xth part of an
// unspecified number of parts. Requires the MESSAGE-ID Armor
// Header to be used.
if (splittedtext[1].match(/BEGIN PGP MESSAGE, PART \d+/)) {
return 1;
} else
// BEGIN PGP SIGNATURE
// Used for detached signatures, OpenPGP/MIME signatures, and
// cleartext signatures. Note that PGP 2.x uses BEGIN PGP MESSAGE
// for detached signatures.
if (splittedtext[1].match(/BEGIN PGP SIGNED MESSAGE/)) {
return 2;
} else
// BEGIN PGP MESSAGE
// Used for signed, encrypted, or compressed files.
if (splittedtext[1].match(/BEGIN PGP MESSAGE/)) {
return 3;
} else
// BEGIN PGP PUBLIC KEY BLOCK
// Used for armoring public keys.
if (splittedtext[1].match(/BEGIN PGP PUBLIC KEY BLOCK/)) {
return 4;
} else
// BEGIN PGP PRIVATE KEY BLOCK
// Used for armoring private keys.
if (splittedtext[1].match(/BEGIN PGP PRIVATE KEY BLOCK/)) {
return 5;
}
}
/**
* Add additional information to the armor version of an OpenPGP binary
* packet block.
* @author Alex
* @version 2011-12-16
* @returns {String} The header information
*/
function armor_addheader() {
var result = "";
if (openpgp.config.config.show_version) {
result += "Version: "+openpgp.config.versionstring+'\r\n';
}
if (openpgp.config.config.show_comment) {
result += "Comment: "+openpgp.config.commentstring+'\r\n';
}
result += '\r\n';
return result;
}
/**
* Calculates a checksum over the given data and returns it base64 encoded
* @param {String} data Data to create a CRC-24 checksum for
* @return {String} Base64 encoded checksum
*/
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);
}
/**
* Calculates the checksum over the given data and compares it with the
* given base64 encoded checksum
* @param {String} data Data to create a CRC-24 checksum for
* @param {String} checksum Base64 encoded checksum
* @return {Boolean} True if the given checksum is correct; otherwise false
*/
function verifyCheckSum(data, checksum) {
var c = getCheckSum(data);
var d = checksum;
return c[0] == d[0] && c[1] == d[1] && c[2] == d[2];
}
/**
* Internal function to calculate a CRC-24 checksum over a given string (data)
* @param {String} data Data to create a CRC-24 checksum for
* @return {Integer} The CRC-24 checksum as number
*/
var crc_table = [
0x00000000, 0x00864cfb, 0x018ad50d, 0x010c99f6, 0x0393e6e1, 0x0315aa1a, 0x021933ec, 0x029f7f17, 0x07a18139, 0x0727cdc2, 0x062b5434, 0x06ad18cf, 0x043267d8, 0x04b42b23, 0x05b8b2d5, 0x053efe2e, 0x0fc54e89, 0x0f430272, 0x0e4f9b84, 0x0ec9d77f, 0x0c56a868, 0x0cd0e493, 0x0ddc7d65, 0x0d5a319e, 0x0864cfb0, 0x08e2834b, 0x09ee1abd, 0x09685646, 0x0bf72951, 0x0b7165aa, 0x0a7dfc5c, 0x0afbb0a7, 0x1f0cd1e9, 0x1f8a9d12, 0x1e8604e4, 0x1e00481f, 0x1c9f3708, 0x1c197bf3, 0x1d15e205, 0x1d93aefe, 0x18ad50d0, 0x182b1c2b, 0x192785dd, 0x19a1c926, 0x1b3eb631, 0x1bb8faca, 0x1ab4633c, 0x1a322fc7, 0x10c99f60, 0x104fd39b, 0x11434a6d, 0x11c50696, 0x135a7981, 0x13dc357a, 0x12d0ac8c, 0x1256e077, 0x17681e59, 0x17ee52a2, 0x16e2cb54, 0x166487af, 0x14fbf8b8, 0x147db443, 0x15712db5, 0x15f7614e, 0x3e19a3d2, 0x3e9fef29, 0x3f9376df, 0x3f153a24, 0x3d8a4533, 0x3d0c09c8, 0x3c00903e, 0x3c86dcc5, 0x39b822eb, 0x393e6e10, 0x3832f7e6, 0x38b4bb1d, 0x3a2bc40a, 0x3aad88f1, 0x3ba11107, 0x3b275dfc, 0x31dced5b, 0x315aa1a0,
0x30563856, 0x30d074ad, 0x324f0bba, 0x32c94741, 0x33c5deb7, 0x3343924c, 0x367d6c62, 0x36fb2099, 0x37f7b96f, 0x3771f594, 0x35ee8a83, 0x3568c678, 0x34645f8e, 0x34e21375, 0x2115723b, 0x21933ec0, 0x209fa736, 0x2019ebcd, 0x228694da, 0x2200d821, 0x230c41d7, 0x238a0d2c, 0x26b4f302, 0x2632bff9, 0x273e260f, 0x27b86af4, 0x252715e3, 0x25a15918, 0x24adc0ee, 0x242b8c15, 0x2ed03cb2, 0x2e567049, 0x2f5ae9bf, 0x2fdca544, 0x2d43da53, 0x2dc596a8, 0x2cc90f5e, 0x2c4f43a5, 0x2971bd8b, 0x29f7f170, 0x28fb6886, 0x287d247d, 0x2ae25b6a, 0x2a641791, 0x2b688e67, 0x2beec29c, 0x7c3347a4, 0x7cb50b5f, 0x7db992a9, 0x7d3fde52, 0x7fa0a145, 0x7f26edbe, 0x7e2a7448, 0x7eac38b3, 0x7b92c69d, 0x7b148a66, 0x7a181390, 0x7a9e5f6b, 0x7801207c, 0x78876c87, 0x798bf571, 0x790db98a, 0x73f6092d, 0x737045d6, 0x727cdc20, 0x72fa90db, 0x7065efcc, 0x70e3a337, 0x71ef3ac1, 0x7169763a, 0x74578814, 0x74d1c4ef, 0x75dd5d19, 0x755b11e2, 0x77c46ef5, 0x7742220e, 0x764ebbf8, 0x76c8f703, 0x633f964d, 0x63b9dab6, 0x62b54340, 0x62330fbb,
0x60ac70ac, 0x602a3c57, 0x6126a5a1, 0x61a0e95a, 0x649e1774, 0x64185b8f, 0x6514c279, 0x65928e82, 0x670df195, 0x678bbd6e, 0x66872498, 0x66016863, 0x6cfad8c4, 0x6c7c943f, 0x6d700dc9, 0x6df64132, 0x6f693e25, 0x6fef72de, 0x6ee3eb28, 0x6e65a7d3, 0x6b5b59fd, 0x6bdd1506, 0x6ad18cf0, 0x6a57c00b, 0x68c8bf1c, 0x684ef3e7, 0x69426a11, 0x69c426ea, 0x422ae476, 0x42aca88d, 0x43a0317b, 0x43267d80, 0x41b90297, 0x413f4e6c, 0x4033d79a, 0x40b59b61, 0x458b654f, 0x450d29b4, 0x4401b042, 0x4487fcb9, 0x461883ae, 0x469ecf55, 0x479256a3, 0x47141a58, 0x4defaaff, 0x4d69e604, 0x4c657ff2, 0x4ce33309, 0x4e7c4c1e, 0x4efa00e5, 0x4ff69913, 0x4f70d5e8, 0x4a4e2bc6, 0x4ac8673d, 0x4bc4fecb, 0x4b42b230, 0x49ddcd27, 0x495b81dc, 0x4857182a, 0x48d154d1, 0x5d26359f, 0x5da07964, 0x5cace092, 0x5c2aac69, 0x5eb5d37e, 0x5e339f85, 0x5f3f0673, 0x5fb94a88, 0x5a87b4a6, 0x5a01f85d, 0x5b0d61ab, 0x5b8b2d50, 0x59145247, 0x59921ebc, 0x589e874a, 0x5818cbb1, 0x52e37b16, 0x526537ed, 0x5369ae1b, 0x53efe2e0, 0x51709df7, 0x51f6d10c,
0x50fa48fa, 0x507c0401, 0x5542fa2f, 0x55c4b6d4, 0x54c82f22, 0x544e63d9, 0x56d11cce, 0x56575035, 0x575bc9c3, 0x57dd8538];
function createcrc24(input) {
var crc = 0xB704CE;
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];
index += 16;
}
for(var j = index; j < input.length; j++) {
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index++)) & 0xff]
}
return crc & 0xffffff;
}
/**
* DeArmor an OpenPGP armored message; verify the checksum and return
* the encoded bytes
* @param {String} text OpenPGP armored message
* @returns {(Boolean|Object)} Either false in case of an error
* or an object with attribute "text" containing the message text
* and an attribute "openpgp" containing the bytes.
*/
function dearmor(text) {
text = text.replace(/\r/g, '')
var type = get_type(text);
if (type != 2) {
var splittedtext = text.split('-----');
var data = {
openpgp: base64.decode(
splittedtext[2]
.split('\n\n')[1]
.split("\n=")[0]
.replace(/\n- /g,"\n")),
type: type
};
if (verifyCheckSum(data.openpgp,
splittedtext[2]
.split('\n\n')[1]
.split("\n=")[1]
.split('\n')[0]))
return data;
else {
util.print_error("Ascii armor integrity check on message failed: '"
+ splittedtext[2]
.split('\n\n')[1]
.split("\n=")[1]
.split('\n')[0]
+ "' should be '"
+ getCheckSum(data)) + "'";
return false;
}
} else {
var splittedtext = text.split('-----');
var result = {
text: splittedtext[2]
.replace(/\n- /g,"\n")
.split("\n\n")[1],
openpgp: base64_decode(splittedtext[4]
.split("\n\n")[1]
.split("\n=")[0]),
type: type
};
if (verifyCheckSum(result.openpgp, splittedtext[4]
.split("\n\n")[1]
.split("\n=")[1]))
return result;
else {
util.print_error("Ascii armor integrity check on message failed");
return false;
}
}
}
/**
* Armor an OpenPGP binary packet block
* @param {Integer} messagetype type of the message
* @param data
* @param {Integer} partindex
* @param {Integer} parttotal
* @returns {String} Armored text
*/
function armor(messagetype, data, partindex, parttotal) {
var result = "";
switch(messagetype) {
case 0:
result += "-----BEGIN PGP MESSAGE, PART "+partindex+"/"+parttotal+"-----\r\n";
result += armor_addheader();
result += base64.encode(data);
result += "\r\n="+getCheckSum(data)+"\r\n";
result += "-----END PGP MESSAGE, PART "+partindex+"/"+parttotal+"-----\r\n";
break;
case 1:
result += "-----BEGIN PGP MESSAGE, PART "+partindex+"-----\r\n";
result += armor_addheader();
result += base64.encode(data);
result += "\r\n="+getCheckSum(data)+"\r\n";
result += "-----END PGP MESSAGE, PART "+partindex+"-----\r\n";
break;
case 2:
result += "\r\n-----BEGIN PGP SIGNED MESSAGE-----\r\nHash: "+data.hash+"\r\n\r\n";
result += data.text.replace(/\n-/g,"\n- -");
result += "\r\n-----BEGIN PGP SIGNATURE-----\r\n";
result += armor_addheader();
result += base64.encode(data.openpgp);
result += "\r\n="+getCheckSum(data.openpgp)+"\r\n";
result += "-----END PGP SIGNATURE-----\r\n";
break;
case 3:
result += "-----BEGIN PGP MESSAGE-----\r\n";
result += armor_addheader();
result += base64.encode(data);
result += "\r\n="+getCheckSum(data)+"\r\n";
result += "-----END PGP MESSAGE-----\r\n";
break;
case 4:
result += "-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n";
result += armor_addheader();
result += base64.encode(data);
result += "\r\n="+getCheckSum(data)+"\r\n";
result += "-----END PGP PUBLIC KEY BLOCK-----\r\n\r\n";
break;
case 5:
result += "-----BEGIN PGP PRIVATE KEY BLOCK-----\r\n";
result += armor_addheader();
result += base64.encode(data);
result += "\r\n="+getCheckSum(data)+"\r\n";
result += "-----END PGP PRIVATE KEY BLOCK-----\r\n";
break;
}
return result;
}
module.exports = {
encode: armor,
decode: dearmor
}
/* OpenPGP radix-64/base64 string encoding/decoding
* Copyright 2005 Herbert Hanewinkel, www.haneWIN.de
* version 1.0, check www.haneWIN.de for the latest version
*
* This software is provided as-is, without express or implied warranty.
* Permission to use, copy, modify, distribute or sell this software, with or
* without fee, for any purpose and by any individual or organization, is hereby
* granted, provided that the above copyright notice and this paragraph appear
* in all copies. Distribution as a part of an application or binary must
* include the above copyright notice in the documentation and/or other materials
* provided with the application or distribution.
*/
var b64s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
function s2r(t) {
var a, c, n;
var r = '', l = 0, s = 0;
var tl = t.length;
for (n = 0; n < tl; n++) {
c = t.charCodeAt(n);
if (s == 0) {
r += b64s.charAt((c >> 2) & 63);
a = (c & 3) << 4;
} else if (s == 1) {
r += b64s.charAt((a | (c >> 4) & 15));
a = (c & 15) << 2;
} else if (s == 2) {
r += b64s.charAt(a | ((c >> 6) & 3));
l += 1;
if ((l % 60) == 0)
r += "\n";
r += b64s.charAt(c & 63);
}
l += 1;
if ((l % 60) == 0)
r += "\n";
s += 1;
if (s == 3)
s = 0;
}
if (s > 0) {
r += b64s.charAt(a);
l += 1;
if ((l % 60) == 0)
r += "\n";
r += '=';
l += 1;
}
if (s == 1) {
if ((l % 60) == 0)
r += "\n";
r += '=';
}
return r;
}
function r2s(t) {
var c, n;
var r = '', s = 0, a = 0;
var tl = t.length;
for (n = 0; n < tl; n++) {
c = b64s.indexOf(t.charAt(n));
if (c >= 0) {
if (s)
r += String.fromCharCode(a | (c >> (6 - s)) & 255);
s = (s + 2) & 7;
a = (c << s) & 255;
}
}
return r;
}
module.exports = {
encode: s2r,
decode: r2s
}
var enums = {
/** A string to key specifier type
* @enum {Integer}
*/
s2k: {
simple: 0,
salted: 1,
iterated: 3,
gnu: 101
},
/** RFC4880, section 9.1
* @enum {String}
*/
publicKey: {
rsa_encrypt_sign: 1,
rsa_encrypt: 2,
rsa_sign: 3,
elgamal: 16,
dsa: 17
},
/** RFC4880, section 9.2
* @enum {String}
*/
symmetric: {
plaintext: 0,
/** Not implemented! */
idea: 1,
tripledes: 2,
cast5: 3,
blowfish: 4,
aes128: 7,
aes192: 8,
aes256: 9,
twofish: 10
},
/** RFC4880, section 9.3
* @enum {String}
*/
compression: {
uncompressed: 0,
/** RFC1951 */
zip: 1,
/** RFC1950 */
zlib: 2,
bzip2: 3
},
/** RFC4880, section 9.4
* @enum {String}
*/
hash: {
md5: 1,
sha1: 2,
ripemd: 3,
sha256: 8,
sha384: 9,
sha512: 10,
sha224: 11
},
/**
* @enum {String}
* A list of packet types and numeric tags associated with them.
*/
packet: {
public_key_encrypted_session_key: 1,
signature: 2,
sym_encrypted_session_key: 3,
one_pass_signature: 4,
secret_key: 5,
public_key: 6,
secret_subkey: 7,
compressed: 8,
symmetrically_encrypted: 9,
marker: 10,
literal: 11,
trust: 12,
userid: 13,
public_subkey: 14,
user_attribute: 17,
sym_encrypted_integrity_protected: 18,
modification_detection_code: 19
},
/**
* Data types in the literal packet
* @readonly
* @enum {String}
*/
literal: {
/** Binary data */
binary: 'b'.charCodeAt(),
/** Text data */
text: 't'.charCodeAt(),
/** Utf8 data */
utf8: 'u'.charCodeAt()
},
/** One pass signature packet type
* @enum {String} */
signature: {
/** 0x00: Signature of a binary document. */
binary: 0,
/** 0x01: Signature of a canonical text document.
* Canonicalyzing the document by converting line endings. */
text: 1,
/** 0x02: Standalone signature.
* This signature is a signature of only its own subpacket contents.
* It is calculated identically to a signature over a zero-lengh
* binary document. Note that it doesn't make sense to have a V3
* standalone signature. */
standalone: 2,
/** 0x10: Generic certification of a User ID and Public-Key packet.
* The issuer of this certification does not make any particular
* assertion as to how well the certifier has checked that the owner
* of the key is in fact the person described by the User ID. */
cert_generic: 16,
/** 0x11: Persona certification of a User ID and Public-Key packet.
* The issuer of this certification has not done any verification of
* the claim that the owner of this key is the User ID specified. */
cert_persona: 17,
/** 0x12: Casual certification of a User ID and Public-Key packet.
* The issuer of this certification has done some casual
* verification of the claim of identity. */
cert_casual: 18,
/** 0x13: Positive certification of a User ID and Public-Key packet.
* The issuer of this certification has done substantial
* verification of the claim of identity.
*
* Most OpenPGP implementations make their "key signatures" as 0x10
* certifications. Some implementations can issue 0x11-0x13
* certifications, but few differentiate between the types. */
cert_positive: 19,
/** 0x30: Certification revocation signature
* This signature revokes an earlier User ID certification signature
* (signature class 0x10 through 0x13) or direct-key signature
* (0x1F). It should be issued by the same key that issued the
* revoked signature or an authorized revocation key. The signature
* is computed over the same data as the certificate that it
* revokes, and should have a later creation date than that
* certificate. */
cert_revocation: 48,
/** 0x18: Subkey Binding Signature
* This signature is a statement by the top-level signing key that
* indicates that it owns the subkey. This signature is calculated
* directly on the primary key and subkey, and not on any User ID or
* other packets. A signature that binds a signing subkey MUST have
* an Embedded Signature subpacket in this binding signature that
* contains a 0x19 signature made by the signing subkey on the
* primary key and subkey. */
subkey_binding: 24,
/** 0x19: Primary Key Binding Signature
* This signature is a statement by a signing subkey, indicating
* that it is owned by the primary key and subkey. This signature
* is calculated the same way as a 0x18 signature: directly on the
* primary key and subkey, and not on any User ID or other packets.
* When a signature is made over a key, the hash data starts with the
* octet 0x99, followed by a two-octet length of the key, and then body
* of the key packet. (Note that this is an old-style packet header for
* a key packet with two-octet length.) A subkey binding signature
* (type 0x18) or primary key binding signature (type 0x19) then hashes
* the subkey using the same format as the main key (also using 0x99 as
* the first octet). */
key_binding: 25,
/** 0x1F: Signature directly on a key
* This signature is calculated directly on a key. It binds the
* information in the Signature subpackets to the key, and is
* appropriate to be used for subpackets that provide information
* about the key, such as the Revocation Key subpacket. It is also
* appropriate for statements that non-self certifiers want to make
* about the key itself, rather than the binding between a key and a
* name. */
key: 31,
/** 0x20: Key revocation signature
* The signature is calculated directly on the key being revoked. A
* revoked key is not to be used. Only revocation signatures by the
* key being revoked, or by an authorized revocation key, should be
* considered valid revocation signatures.a */
key_revocation: 32,
/** 0x28: Subkey revocation signature
* The signature is calculated directly on the subkey being revoked.
* A revoked subkey is not to be used. Only revocation signatures
* by the top-level signature key that is bound to this subkey, or
* by an authorized revocation key, should be considered valid
* revocation signatures.
* Key revocation signatures (types 0x20 and 0x28)
* hash only the key being revoked. */
subkey_revocation: 40,
/** 0x40: Timestamp signature.
* This signature is only meaningful for the timestamp contained in
* it. */
timestamp: 64,
/** 0x50: Third-Party Confirmation signature.
* This signature is a signature over some other OpenPGP Signature
* packet(s). It is analogous to a notary seal on the signed data.
* A third-party signature SHOULD include Signature Target
* subpacket(s) to give easy identification. Note that we really do
* mean SHOULD. There are plausible uses for this (such as a blind
* party that only sees the signature, not the key or source
* document) that cannot include a target subpacket. */
third_party: 80
},
// Asserts validity and converts from string/integer to integer.
write: function(type, e) {
if(typeof e == 'number') {
e = this.read(type, e);
}
if(type[e] != undefined) {
return type[e];
} else throw new Error('Invalid enum value.');
},
// Converts from an integer to string.
read: function(type, e) {
for(var i in type)
if(type[i] == e) return i;
throw new Error('Invalid enum value.');
}
}
module.exports = enums;
var crypto = require('./crypto');
module.exports = require('./openpgp.js');
module.exports.util = require('./util');
module.exports.packet = require('./packet');
module.exports.mpi = require('./type/mpi.js');
module.exports.s2k = require('./type/s2k.js');
module.exports.keyid = require('./type/keyid.js');
module.exports.armor = require('./encoding/armor.js');
module.exports.enums = require('./enums.js');
for(var i in crypto)
module.exports[i] = crypto[i];
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
/**
* @class
* @classdesc Class that represents an OpenPGP key. Must contain a master key.
* Can contain additional subkeys, signatures,
* user ids, user attributes.
*/
function openpgp_key() {
this.packets = new openpgp_packetlist();
/** Returns the master key (secret or public)
* @returns {openpgp_packet_secret_key|openpgp_packet_public_key|null} */
this.getKey = function() {
for(var i = 0; i < this.packets.length; i++)
if(this.packets[i].tag == openpgp_packets.tags.public_key ||
this.packets[i].tag == openpgp_packets.tags.secret_key)
return this.packets[i];
return null;
}
/** Returns all the private and public subkeys
* @returns {openpgp_packet_subkey[]} */
this.getSubkeys = function() {
var subkeys = [];
for(var i = 0; i < this.packets.length; i++)
if(this.packets[i].tag == openpgp_packet.tags.public_subkey ||
this.packets[i].tag == openpgp_packet.tags.secret_subkey)
subkeys.push(this.packets[i]);
return subkeys;
}
this.getAllKeys = function() {
return [this.getKey()].concat(this.getSubkeys());
}
this.getSigningKey = function() {
var signing = ['rsa_encrypt_sign', 'rsa_sign', 'dsa'];
signing = signing.map(function(s) { return openpgp.publickey[s]; })
var keys = this.getAllKeys();
for(var i in keys)
if(signing.indexOf(keys[i].public_algorithm) != -1)
return keys[i];
return null;
}
function getPreferredSignatureHashAlgorithm() {
var pkey = this.getSigningKey();
if (pkey == null) {
util.print_error("private key is for encryption only! Cannot create a signature.")
return null;
}
if (pkey.publicKey.publicKeyAlgorithm == 17) {
var dsa = new DSA();
return dsa.select_hash_algorithm(pkey.publicKey.MPIs[1].toBigInteger()); // q
}
//TODO implement: https://tools.ietf.org/html/rfc4880#section-5.2.3.8
//separate private key preference from digest preferences
return openpgp.config.config.prefer_hash_algorithm;
}
this.decrypt = function(passphrase) {
var keys = this.getAllKeys();
for(var i in keys)
if(keys[i].tag == openpgp_packet.tags.secret_subkey ||
keys[i].tag == openpgp_packet.tags.secret_key)
keys[i].decrypt(passphrase);
}
// TODO need to implement this
function revoke() {
}
}
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
/**
* @fileoverview The openpgp base class should provide all of the functionality
* to consume the openpgp.js library. All additional classes are documented
* for extending and developing on top of the base library.
*/
/**
* GPG4Browsers Core interface. A single instance is hold
* from the beginning. To use this library call "openpgp.init()"
* @alias openpgp
* @class
* @classdesc Main Openpgp.js class. Use this to initiate and make all calls to this library.
*/
function _openpgp () {
this.tostring = "";
/**
* initializes the library:
* - reading the keyring from local storage
* - reading the config from local storage
*/
function init() {
this.config = new openpgp_config();
this.config.read();
this.keyring = new openpgp_keyring();
this.keyring.init();
}
/**
* reads several publicKey objects from a ascii armored
* representation an returns openpgp_msg_publickey packets
* @param {String} armoredText OpenPGP armored text containing
* the public key(s)
* @return {openpgp_msg_publickey[]} on error the function
* returns null
*/
function read_publicKey(armoredText) {
var mypos = 0;
var publicKeys = new Array();
var publicKeyCount = 0;
var input = openpgp_encoding_deArmor(armoredText.replace(/\r/g,'')).openpgp;
var l = input.length;
while (mypos != input.length) {
var first_packet = openpgp_packet.read_packet(input, mypos, l);
// public key parser
if (input[mypos].charCodeAt() == 0x99 || first_packet.tagType == 6) {
publicKeys[publicKeyCount] = new openpgp_msg_publickey();
publicKeys[publicKeyCount].header = input.substring(mypos,mypos+3);
if (input[mypos].charCodeAt() == 0x99) {
// parse the length and read a tag6 packet
mypos++;
var l = (input[mypos++].charCodeAt() << 8)
| input[mypos++].charCodeAt();
publicKeys[publicKeyCount].publicKeyPacket = new openpgp_packet_keymaterial();
publicKeys[publicKeyCount].publicKeyPacket.header = publicKeys[publicKeyCount].header;
publicKeys[publicKeyCount].publicKeyPacket.read_tag6(input, mypos, l);
mypos += publicKeys[publicKeyCount].publicKeyPacket.packetLength;
mypos += publicKeys[publicKeyCount].read_nodes(publicKeys[publicKeyCount].publicKeyPacket, input, mypos, (input.length - mypos));
} else {
publicKeys[publicKeyCount] = new openpgp_msg_publickey();
publicKeys[publicKeyCount].publicKeyPacket = first_packet;
mypos += first_packet.headerLength+first_packet.packetLength;
mypos += publicKeys[publicKeyCount].read_nodes(first_packet, input, mypos, input.length -mypos);
}
} else {
util.print_error("no public key found!");
return null;
}
publicKeys[publicKeyCount].data = input.substring(0,mypos);
publicKeyCount++;
}
return publicKeys;
}
/**
* reads several privateKey objects from a ascii armored
* representation an returns openpgp_msg_privatekey objects
* @param {String} armoredText OpenPGP armored text containing
* the private key(s)
* @return {openpgp_msg_privatekey[]} on error the function
* returns null
*/
function read_privateKey(armoredText) {
var privateKeys = new Array();
var privateKeyCount = 0;
var mypos = 0;
var input = openpgp_encoding_deArmor(armoredText.replace(/\r/g,'')).openpgp;
var l = input.length;
while (mypos != input.length) {
var first_packet = openpgp_packet.read_packet(input, mypos, l);
if (first_packet.tagType == 5) {
privateKeys[privateKeys.length] = new openpgp_msg_privatekey();
mypos += first_packet.headerLength+first_packet.packetLength;
mypos += privateKeys[privateKeyCount].read_nodes(first_packet, input, mypos, l);
// other blocks
} else {
util.print_error('no block packet found!');
return null;
}
privateKeys[privateKeyCount].data = input.substring(0,mypos);
privateKeyCount++;
}
return privateKeys;
}
/**
* reads message packets out of an OpenPGP armored text and
* returns an array of message objects
* @param {String} armoredText text to be parsed
* @return {openpgp_msg_message[]} on error the function
* returns null
*/
function read_message(armoredText) {
var dearmored;
try{
dearmored = openpgp_encoding_deArmor(armoredText.replace(/\r/g,''));
}
catch(e){
util.print_error('no message found!');
return null;
}
return read_messages_dearmored(dearmored);
}
/**
* reads message packets out of an OpenPGP armored text and
* returns an array of message objects. Can be called externally or internally.
* External call will parse a de-armored messaged and return messages found.
* Internal will be called to read packets wrapped in other packets (i.e. compressed)
* @param {String} input dearmored text of OpenPGP packets, to be parsed
* @return {openpgp_msg_message[]} on error the function
* returns null
*/
function read_messages_dearmored(input){
var messageString = input.openpgp;
var signatureText = input.text; //text to verify signatures against. Modified by Tag11.
var messages = new Array();
var messageCount = 0;
var mypos = 0;
var l = messageString.length;
while (mypos < messageString.length) {
var first_packet = openpgp_packet.read_packet(messageString, mypos, l);
if (!first_packet) {
break;
}
// public key parser (definition from the standard:)
// OpenPGP Message :- Encrypted Message | Signed Message |
// Compressed Message | Literal Message.
// Compressed Message :- Compressed Data Packet.
//
// Literal Message :- Literal Data Packet.
//
// ESK :- Public-Key Encrypted Session Key Packet |
// Symmetric-Key Encrypted Session Key Packet.
//
// ESK Sequence :- ESK | ESK Sequence, ESK.
//
// Encrypted Data :- Symmetrically Encrypted Data Packet |
// Symmetrically Encrypted Integrity Protected Data Packet
//
// Encrypted Message :- Encrypted Data | ESK Sequence, Encrypted Data.
//
// One-Pass Signed Message :- One-Pass Signature Packet,
// OpenPGP Message, Corresponding Signature Packet.
// Signed Message :- Signature Packet, OpenPGP Message |
// One-Pass Signed Message.
if (first_packet.tagType == 1 ||
(first_packet.tagType == 2 && first_packet.signatureType < 16) ||
first_packet.tagType == 3 ||
first_packet.tagType == 4 ||
first_packet.tagType == 8 ||
first_packet.tagType == 9 ||
first_packet.tagType == 10 ||
first_packet.tagType == 11 ||
first_packet.tagType == 18 ||
first_packet.tagType == 19) {
messages[messages.length] = new openpgp_msg_message();
messages[messageCount].messagePacket = first_packet;
messages[messageCount].type = input.type;
// Encrypted Message
if (first_packet.tagType == 9 ||
first_packet.tagType == 1 ||
first_packet.tagType == 3 ||
first_packet.tagType == 18) {
if (first_packet.tagType == 9) {
util.print_error("unexpected openpgp packet");
break;
} else if (first_packet.tagType == 1) {
util.print_debug("session key found:\n "+first_packet.toString());
var issessionkey = true;
messages[messageCount].sessionKeys = new Array();
var sessionKeyCount = 0;
while (issessionkey) {
messages[messageCount].sessionKeys[sessionKeyCount] = first_packet;
mypos += first_packet.packetLength + first_packet.headerLength;
l -= (first_packet.packetLength + first_packet.headerLength);
first_packet = openpgp_packet.read_packet(messageString, mypos, l);
if (first_packet.tagType != 1 && first_packet.tagType != 3)
issessionkey = false;
sessionKeyCount++;
}
if (first_packet.tagType == 18 || first_packet.tagType == 9) {
util.print_debug("encrypted data found:\n "+first_packet.toString());
messages[messageCount].encryptedData = first_packet;
mypos += first_packet.packetLength+first_packet.headerLength;
l -= (first_packet.packetLength+first_packet.headerLength);
messageCount++;
} else {
util.print_debug("something is wrong: "+first_packet.tagType);
}
} else if (first_packet.tagType == 18) {
util.print_debug("symmetric encrypted data");
break;
}
} else
if (first_packet.tagType == 2 && first_packet.signatureType < 3) {
// Signed Message
mypos += first_packet.packetLength + first_packet.headerLength;
l -= (first_packet.packetLength + first_packet.headerLength);
messages[messageCount].text = signatureText;
messages[messageCount].signature = first_packet;
messageCount++;
} else
// Signed Message
if (first_packet.tagType == 4) {
//TODO: Implement check
mypos += first_packet.packetLength + first_packet.headerLength;
l -= (first_packet.packetLength + first_packet.headerLength);
} else
if (first_packet.tagType == 8) {
// Compressed Message
mypos += first_packet.packetLength + first_packet.headerLength;
l -= (first_packet.packetLength + first_packet.headerLength);
var decompressedText = first_packet.decompress();
messages = messages.concat(openpgp.read_messages_dearmored({text: decompressedText, openpgp: decompressedText}));
} else
// Marker Packet (Obsolete Literal Packet) (Tag 10)
// "Such a packet MUST be ignored when received." see http://tools.ietf.org/html/rfc4880#section-5.8
if (first_packet.tagType == 10) {
// reset messages
messages.length = 0;
// continue with next packet
mypos += first_packet.packetLength + first_packet.headerLength;
l -= (first_packet.packetLength + first_packet.headerLength);
} else
if (first_packet.tagType == 11) {
// Literal Message -- work is already done in read_packet
mypos += first_packet.packetLength + first_packet.headerLength;
l -= (first_packet.packetLength + first_packet.headerLength);
signatureText = first_packet.data;
messages[messageCount].data = first_packet.data;
messageCount++;
} else
if (first_packet.tagType == 19) {
// Modification Detect Code
mypos += first_packet.packetLength + first_packet.headerLength;
l -= (first_packet.packetLength + first_packet.headerLength);
}
} else {
util.print_error('no message found!');
return null;
}
}
return messages;
}
/**
* creates a binary string representation of an encrypted and signed message.
* The message will be encrypted with the public keys specified and signed
* with the specified private key.
* @param {Object} privatekey {obj: [openpgp_msg_privatekey]} Private key
* to be used to sign the message
* @param {Object[]} publickeys An arraf of {obj: [openpgp_msg_publickey]}
* - public keys to be used to encrypt the message
* @param {String} messagetext message text to encrypt and sign
* @return {String} a binary string representation of the message which
* can be OpenPGP armored
*/
function write_signed_and_encrypted_message(privatekey, publickeys, messagetext) {
var result = "";
var literal = new openpgp_packet_literaldata().write_packet(messagetext.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n"));
util.print_debug_hexstr_dump("literal_packet: |"+literal+"|\n",literal);
for (var i = 0; i < publickeys.length; i++) {
var onepasssignature = new openpgp_packet_onepasssignature();
var onepasssigstr = "";
if (i == 0)
onepasssigstr = onepasssignature.write_packet(1, openpgp.config.config.prefer_hash_algorithm, privatekey, false);
else
onepasssigstr = onepasssignature.write_packet(1, openpgp.config.config.prefer_hash_algorithm, privatekey, false);
util.print_debug_hexstr_dump("onepasssigstr: |"+onepasssigstr+"|\n",onepasssigstr);
var datasignature = new openpgp_packet_signature().write_message_signature(1, messagetext.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n"), privatekey);
util.print_debug_hexstr_dump("datasignature: |"+datasignature.openpgp+"|\n",datasignature.openpgp);
if (i == 0) {
result = onepasssigstr+literal+datasignature.openpgp;
} else {
result = onepasssigstr+result+datasignature.openpgp;
}
}
util.print_debug_hexstr_dump("signed packet: |"+result+"|\n",result);
// signatures done.. now encryption
var sessionkey = openpgp_crypto_generateSessionKey(openpgp.config.config.encryption_cipher);
var result2 = "";
// creating session keys for each recipient
for (var i = 0; i < publickeys.length; i++) {
var pkey = publickeys[i].getEncryptionKey();
if (pkey == null) {
util.print_error("no encryption key found! Key is for signing only.");
return null;
}
result2 += new openpgp_packet_encryptedsessionkey().
write_pub_key_packet(
pkey.getKeyId(),
pkey.MPIs,
pkey.publicKeyAlgorithm,
openpgp.config.config.encryption_cipher,
sessionkey);
}
if (openpgp.config.config.integrity_protect) {
result2 += new openpgp_packet_encryptedintegrityprotecteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result);
} else {
result2 += new openpgp_packet_encrypteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result);
}
return openpgp_encoding_armor(3,result2,null,null);
}
/**
* creates a binary string representation of an encrypted message.
* The message will be encrypted with the public keys specified
* @param {Object[]} publickeys An array of {obj: [openpgp_msg_publickey]}
* -public keys to be used to encrypt the message
* @param {String} messagetext message text to encrypt
* @return {String} a binary string representation of the message
* which can be OpenPGP armored
*/
function write_encrypted_message(publickeys, messagetext) {
var result = "";
var literal = new openpgp_packet_literaldata().write_packet(messagetext.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n"));
util.print_debug_hexstr_dump("literal_packet: |"+literal+"|\n",literal);
result = literal;
// signatures done.. now encryption
var sessionkey = openpgp_crypto_generateSessionKey(openpgp.config.config.encryption_cipher);
var result2 = "";
// creating session keys for each recipient
for (var i = 0; i < publickeys.length; i++) {
var pkey = publickeys[i].getEncryptionKey();
if (pkey == null) {
util.print_error("no encryption key found! Key is for signing only.");
return null;
}
result2 += new openpgp_packet_encryptedsessionkey().
write_pub_key_packet(
pkey.getKeyId(),
pkey.MPIs,
pkey.publicKeyAlgorithm,
openpgp.config.config.encryption_cipher,
sessionkey);
}
if (openpgp.config.config.integrity_protect) {
result2 += new openpgp_packet_encryptedintegrityprotecteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result);
} else {
result2 += new openpgp_packet_encrypteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result);
}
return openpgp_encoding_armor(3,result2,null,null);
}
/**
* creates a binary string representation a signed message.
* The message will be signed with the specified private key.
* @param {Object} privatekey {obj: [openpgp_msg_privatekey]}
* - the private key to be used to sign the message
* @param {String} messagetext message text to sign
* @return {Object} {Object: text [String]}, openpgp: {String} a binary
* string representation of the message which can be OpenPGP
* armored(openpgp) and a text representation of the message (text).
* This can be directly used to OpenPGP armor the message
*/
function write_signed_message(privatekey, messagetext) {
var sig = new openpgp_packet_signature().write_message_signature(1, messagetext.replace(/\r\n/g,"\n").replace(/\n/,"\r\n"), privatekey);
var result = {text: messagetext.replace(/\r\n/g,"\n").replace(/\n/,"\r\n"), openpgp: sig.openpgp, hash: sig.hash};
return openpgp_encoding_armor(2,result, null, null)
}
/**
* generates a new key pair for openpgp. Beta stage. Currently only
* supports RSA keys, and no subkeys.
* @param {Integer} keyType to indicate what type of key to make.
* RSA is 1. Follows algorithms outlined in OpenPGP.
* @param {Integer} numBits number of bits for the key creation. (should
* be 1024+, generally)
* @param {String} userId assumes already in form of "User Name
* "
* @param {String} passphrase The passphrase used to encrypt the resulting private key
* @return {Object} {privateKey: [openpgp_msg_privatekey],
* privateKeyArmored: [string], publicKeyArmored: [string]}
*/
function generate_key_pair(keyType, numBits, userId, passphrase){
var userIdPacket = new openpgp_packet_userid();
var userIdString = userIdPacket.write_packet(userId);
var keyPair = openpgp_crypto_generateKeyPair(keyType,numBits, passphrase, openpgp.config.config.prefer_hash_algorithm, 3);
var privKeyString = keyPair.privateKey;
var privKeyPacket = new openpgp_packet_keymaterial().read_priv_key(privKeyString.string,3,privKeyString.string.length);
if(!privKeyPacket.decryptSecretMPIs(passphrase))
util.print_error('Issue creating key. Unable to read resulting private key');
var privKey = new openpgp_msg_privatekey();
privKey.privateKeyPacket = privKeyPacket;
privKey.getPreferredSignatureHashAlgorithm = function(){return openpgp.config.config.prefer_hash_algorithm};//need to override this to solve catch 22 to generate signature. 8 is value for SHA256
var publicKeyString = privKey.privateKeyPacket.publicKey.data;
var hashData = String.fromCharCode(0x99)+ String.fromCharCode(((publicKeyString.length) >> 8) & 0xFF)
+ String.fromCharCode((publicKeyString.length) & 0xFF) +publicKeyString+String.fromCharCode(0xB4) +
String.fromCharCode((userId.length) >> 24) +String.fromCharCode(((userId.length) >> 16) & 0xFF)
+ String.fromCharCode(((userId.length) >> 8) & 0xFF) + String.fromCharCode((userId.length) & 0xFF) + userId
var signature = new openpgp_packet_signature();
signature = signature.write_message_signature(16,hashData, privKey);
var publicArmored = openpgp_encoding_armor(4, keyPair.publicKey.string + userIdString + signature.openpgp );
var privArmored = openpgp_encoding_armor(5,privKeyString.string+userIdString+signature.openpgp);
return {privateKey : privKey, privateKeyArmored: privArmored, publicKeyArmored: publicArmored}
}
this.generate_key_pair = generate_key_pair;
this.write_signed_message = write_signed_message;
this.write_signed_and_encrypted_message = write_signed_and_encrypted_message;
this.write_encrypted_message = write_encrypted_message;
this.read_message = read_message;
this.read_messages_dearmored = read_messages_dearmored;
this.read_publicKey = read_publicKey;
this.read_privateKey = read_privateKey;
this.init = init;
}
module.exports = new _openpgp();
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
/**
* @class
* @classdesc The class that deals with storage of the keyring. Currently the only option is to use HTML5 local storage.
*/
function openpgp_keyring() {
/**
* Initialization routine for the keyring. This method reads the
* keyring from HTML5 local storage and initializes this instance.
* This method is called by openpgp.init().
*/
function init() {
var sprivatekeys = JSON.parse(window.localStorage.getItem("privatekeys"));
var spublickeys = JSON.parse(window.localStorage.getItem("publickeys"));
if (sprivatekeys == null || sprivatekeys.length == 0) {
sprivatekeys = new Array();
}
if (spublickeys == null || spublickeys.length == 0) {
spublickeys = new Array();
}
this.publicKeys = new Array();
this.privateKeys = new Array();
var k = 0;
for (var i =0; i < sprivatekeys.length; i++) {
var r = openpgp.read_privateKey(sprivatekeys[i]);
this.privateKeys[k] = { armored: sprivatekeys[i], obj: r[0], keyId: r[0].getKeyId()};
k++;
}
k = 0;
for (var i =0; i < spublickeys.length; i++) {
var r = openpgp.read_publicKey(spublickeys[i]);
if (r[0] != null) {
this.publicKeys[k] = { armored: spublickeys[i], obj: r[0], keyId: r[0].getKeyId()};
k++;
}
}
}
this.init = init;
/**
* Checks if at least one private key is in the keyring
* @return {Boolean} True if there are private keys, else false.
*/
function hasPrivateKey() {
return this.privateKeys.length > 0;
}
this.hasPrivateKey = hasPrivateKey;
/**
* Saves the current state of the keyring to HTML5 local storage.
* The privateKeys array and publicKeys array gets Stringified using JSON
*/
function store() {
var priv = new Array();
for (var i = 0; i < this.privateKeys.length; i++) {
priv[i] = this.privateKeys[i].armored;
}
var pub = new Array();
for (var i = 0; i < this.publicKeys.length; i++) {
pub[i] = this.publicKeys[i].armored;
}
window.localStorage.setItem("privatekeys",JSON.stringify(priv));
window.localStorage.setItem("publickeys",JSON.stringify(pub));
}
this.store = store;
/**
* searches all public keys in the keyring matching the address or address part of the user ids
* @param {String} email_address
* @return {openpgp_msg_publickey[]} The public keys associated with provided email address.
*/
function getPublicKeyForAddress(email_address) {
var results = new Array();
var spl = email_address.split("<");
var email = "";
if (spl.length > 1) {
email = spl[1].split(">")[0];
} else {
email = email_address.trim();
}
email = email.toLowerCase();
if(!util.emailRegEx.test(email)){
return results;
}
for (var i =0; i < this.publicKeys.length; i++) {
for (var j = 0; j < this.publicKeys[i].obj.userIds.length; j++) {
if (this.publicKeys[i].obj.userIds[j].text.toLowerCase().indexOf(email) >= 0)
results[results.length] = this.publicKeys[i];
}
}
return results;
}
this.getPublicKeyForAddress = getPublicKeyForAddress;
/**
* Searches the keyring for a private key containing the specified email address
* @param {String} email_address email address to search for
* @return {openpgp_msg_privatekey[]} private keys found
*/
function getPrivateKeyForAddress(email_address) {
var results = new Array();
var spl = email_address.split("<");
var email = "";
if (spl.length > 1) {
email = spl[1].split(">")[0];
} else {
email = email_address.trim();
}
email = email.toLowerCase();
if(!util.emailRegEx.test(email)){
return results;
}
for (var i =0; i < this.privateKeys.length; i++) {
for (var j = 0; j < this.privateKeys[i].obj.userIds.length; j++) {
if (this.privateKeys[i].obj.userIds[j].text.toLowerCase().indexOf(email) >= 0)
results[results.length] = this.privateKeys[i];
}
}
return results;
}
this.getPrivateKeyForAddress = getPrivateKeyForAddress;
/**
* Searches the keyring for public keys having the specified key id
* @param {String} keyId provided as string of hex number (lowercase)
* @return {openpgp_msg_privatekey[]} public keys found
*/
function getPublicKeysForKeyId(keyId) {
var result = new Array();
for (var i=0; i < this.publicKeys.length; i++) {
var key = this.publicKeys[i];
if (keyId == key.obj.getKeyId())
result[result.length] = key;
else if (key.obj.subKeys != null) {
for (var j=0; j < key.obj.subKeys.length; j++) {
var subkey = key.obj.subKeys[j];
if (keyId == subkey.getKeyId()) {
result[result.length] = {
obj: key.obj.getSubKeyAsKey(j),
keyId: subkey.getKeyId()
}
}
}
}
}
return result;
}
this.getPublicKeysForKeyId = getPublicKeysForKeyId;
/**
* Searches the keyring for private keys having the specified key id
* @param {String} keyId 8 bytes as string containing the key id to look for
* @return {openpgp_msg_privatekey[]} private keys found
*/
function getPrivateKeyForKeyId(keyId) {
var result = new Array();
for (var i=0; i < this.privateKeys.length; i++) {
if (keyId == this.privateKeys[i].obj.getKeyId()) {
result[result.length] = { key: this.privateKeys[i], keymaterial: this.privateKeys[i].obj.privateKeyPacket};
}
if (this.privateKeys[i].obj.subKeys != null) {
var subkeyids = this.privateKeys[i].obj.getSubKeyIds();
for (var j=0; j < subkeyids.length; j++)
if (keyId == util.hexstrdump(subkeyids[j])) {
result[result.length] = { key: this.privateKeys[i], keymaterial: this.privateKeys[i].obj.subKeys[j]};
}
}
}
return result;
}
this.getPrivateKeyForKeyId = getPrivateKeyForKeyId;
/**
* Imports a public key from an exported ascii armored message
* @param {String} armored_text PUBLIC KEY BLOCK message to read the public key from
*/
function importPublicKey (armored_text) {
var result = openpgp.read_publicKey(armored_text);
for (var i = 0; i < result.length; i++) {
this.publicKeys[this.publicKeys.length] = {armored: armored_text, obj: result[i], keyId: result[i].getKeyId()};
}
return true;
}
/**
* Imports a private key from an exported ascii armored message
* @param {String} armored_text PRIVATE KEY BLOCK message to read the private key from
*/
function importPrivateKey (armored_text, password) {
var result = openpgp.read_privateKey(armored_text);
if(!result[0].decryptSecretMPIs(password))
return false;
for (var i = 0; i < result.length; i++) {
this.privateKeys[this.privateKeys.length] = {armored: armored_text, obj: result[i], keyId: result[i].getKeyId()};
}
return true;
}
this.importPublicKey = importPublicKey;
this.importPrivateKey = importPrivateKey;
/**
* returns the openpgp_msg_privatekey representation of the public key at public key ring index
* @param {Integer} index the index of the public key within the publicKeys array
* @return {openpgp_msg_privatekey} the public key object
*/
function exportPublicKey(index) {
return this.publicKey[index];
}
this.exportPublicKey = exportPublicKey;
/**
* 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 {openpgp_msg_privatekey} The public key object which has been removed
*/
function removePublicKey(index) {
var removed = this.publicKeys.splice(index,1);
this.store();
return removed;
}
this.removePublicKey = removePublicKey;
/**
* returns the openpgp_msg_privatekey representation of the private key at private key ring index
* @param {Integer} index the index of the private key within the privateKeys array
* @return {openpgp_msg_privatekey} the private key object
*/
function exportPrivateKey(index) {
return this.privateKeys[index];
}
this.exportPrivateKey = exportPrivateKey;
/**
* Removes a private key from the private key keyring at the specified index
* @param {Integer} index the index of the private key within the privateKeys array
* @return {openpgp_msg_privatekey} The private key object which has been removed
*/
function removePrivateKey(index) {
var removed = this.privateKeys.splice(index,1);
this.store();
return removed;
}
this.removePrivateKey = removePrivateKey;
}
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
/**
* @class
* @classdesc A generic message containing one or more literal packets.
*/
function openpgp_message() {
this.packets = new openpgp_packetlist();
function generic_decrypt(packets, passphrase) {
var sessionkey;
for(var i = 0; i < packets.length; i++) {
if(packets[i].tag == openpgp_packet.tags.public_key_encrypted_session_key) {
var key = openpgp.keyring.getKeyById(packets[i].public_key_id);
}
}
}
/**
* Decrypts a message and generates user interface message out of the found.
* MDC will be verified as well as message signatures
* @param {openpgp_msg_privatekey} private_key the private the message is encrypted with (corresponding to the session key)
* @param {openpgp_packet_encryptedsessionkey} sessionkey the session key to be used to decrypt the message
* @return {} plaintext of the message or null on error
*/
this.decrypt = function(key) {
return this.decryptAndVerifySignature(private_key, sessionkey)
}
/**
* Decrypts a message and generates user interface message out of the found.
* MDC will be verified as well as message signatures
* @param {openpgp_msg_privatekey} private_key the private the message is encrypted with (corresponding to the session key)
* @param {openpgp_packet_encryptedsessionkey} sessionkey the session key to be used to decrypt the message
* @param {openpgp_msg_publickey} pubkey Array of public keys to check signature against. If not provided, checks local keystore.
* @return {String} plaintext of the message or null on error
*/
function decryptAndVerifySignature(private_key, sessionkey, pubkey) {
if (private_key == null || sessionkey == null || sessionkey == "")
return null;
var decrypted = sessionkey.decrypt(this, private_key.keymaterial);
if (decrypted == null)
return null;
var packet;
var position = 0;
var len = decrypted.length;
var validSignatures = new Array();
util.print_debug_hexstr_dump("openpgp.msg.messge decrypt:\n",decrypted);
var messages = openpgp.read_messages_dearmored({text: decrypted, openpgp: decrypted});
for(var m in messages){
if(messages[m].data){
this.text = messages[m].data;
}
if(messages[m].signature){
validSignatures.push(messages[m].verifySignature(pubkey));
}
}
return {text:this.text, validSignatures:validSignatures};
}
/**
* Verifies a message signature. This function can be called after read_message if the message was signed only.
* @param {openpgp_msg_publickey} pubkey Array of public keys to check signature against. If not provided, checks local keystore.
* @return {boolean} true if the signature was correct; otherwise false
*/
function verifySignature(pubkey) {
var result = false;
if (this.signature.tagType == 2) {
if(!pubkey || pubkey.length == 0){
var pubkey;
if (this.signature.version == 4) {
pubkey = openpgp.keyring.getPublicKeysForKeyId(this.signature.issuerKeyId);
} else if (this.signature.version == 3) {
pubkey = openpgp.keyring.getPublicKeysForKeyId(this.signature.keyId);
} else {
util.print_error("unknown signature type on message!");
return false;
}
}
if (pubkey.length == 0)
util.print_warning("Unable to verify signature of issuer: "+util.hexstrdump(this.signature.issuerKeyId)+". Public key not found in keyring.");
else {
for (var i = 0 ; i < pubkey.length; i++) {
var tohash = this.text.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n");
if (this.signature.verify(tohash, pubkey[i])) {
util.print_info("Found Good Signature from "+pubkey[i].obj.userIds[0].text+" (0x"+util.hexstrdump(pubkey[i].obj.getKeyId()).substring(8)+")");
result = true;
} else {
util.print_error("Signature verification failed: Bad Signature from "+pubkey[i].obj.userIds[0].text+" (0x"+util.hexstrdump(pubkey[0].obj.getKeyId()).substring(8)+")");
}
}
}
}
return result;
}
}
var enums = require('../enums.js');
// This is pretty ugly, but browserify needs to have the requires explicitly written.
module.exports = {
compressed: require('./compressed.js'),
sym_encrypted_integrity_protected: require('./sym_encrypted_integrity_protected.js'),
public_key_encrypted_session_key: require('./public_key_encrypted_session_key.js'),
sym_encrypted_session_key: require('./sym_encrypted_session_key.js'),
literal: require('./literal.js'),
public_key: require('./public_key.js'),
symmetrically_encrypted: require('./symmetrically_encrypted.js'),
marker: require('./marker.js'),
public_subkey: require('./public_subkey.js'),
user_attribute: require('./user_attribute.js'),
one_pass_signature: require('./one_pass_signature.js'),
secret_key: require('./secret_key.js'),
userid: require('./userid.js'),
secret_subkey: require('./secret_subkey.js'),
signature: require('./signature.js'),
trust: require('./trust.js')
}
for(var i in enums.packet) {
var packetClass = module.exports[i];
if(packetClass != undefined)
packetClass.prototype.tag = enums.packet[i];
}
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
var enums = require('../enums.js'),
JXG = require('../compression/jxg.js'),
base64 = require('../encoding/base64.js');
/**
* @class
* @classdesc Implementation of the Compressed Data Packet (Tag 8)
*
* RFC4880 5.6:
* The Compressed Data packet contains compressed data. Typically, this
* packet is found as the contents of an encrypted packet, or following
* a Signature or One-Pass Signature packet, and contains a literal data
* packet.
*/
module.exports = function packet_compressed() {
/** @type {packetlist} */
this.packets;
/** @type {compression} */
this.algorithm = 'uncompressed';
this.compressed = null;
/**
* Parsing function for the packet.
* @param {String} input Payload of a tag 8 packet
* @param {Integer} position Position to start reading from the input string
* @parAM {iNTEGER} LEN lENGTH OF the packet or the remaining length of
* input at position
* @return {openpgp_packet_compressed} Object representation
*/
this.read = function(bytes) {
// One octet that gives the algorithm used to compress the packet.
this.algorithm = enums.read(enums.compression, bytes.charCodeAt(0));
// Compressed data, which makes up the remainder of the packet.
this.compressed = bytes.substr(1);
this.decompress();
}
this.write = function() {
if(this.compressed == null)
this.compress();
return String.fromCharCode(enums.write(enums.compression, this.algorithm))
+ this.compressed;
}
/**
* Decompression method for decompressing the compressed data
* read by read_packet
* @return {String} The decompressed data
*/
this.decompress = function() {
var decompressed;
switch (this.algorithm) {
case 'uncompressed':
decompressed = this.compressed;
break;
case 'zip':
var compData = this.compressed;
var radix = base64.encode(compData).replace(/\n/g,"");
// no header in this case, directly call deflate
var jxg_obj = new JXG.Util.Unzip(JXG.Util.Base64.decodeAsArray(radix));
decompressed = unescape(jxg_obj.deflate()[0][0]);
break;
case 'zlib':
//RFC 1950. Bits 0-3 Compression Method
var compressionMethod = this.compressed.charCodeAt(0) % 0x10;
//Bits 4-7 RFC 1950 are LZ77 Window. Generally this value is 7 == 32k window size.
// 2nd Byte in RFC 1950 is for "FLAGs" Allows for a Dictionary
// (how is this defined). Basic checksum, and compression level.
if (compressionMethod == 8) { //CM 8 is for DEFLATE, RFC 1951
// remove 4 bytes ADLER32 checksum from the end
var compData = this.compressed.substring(0, this.compressed.length - 4);
var radix = base64.encode(compData).replace(/\n/g,"");
//TODO check ADLER32 checksum
decompressed = JXG.decompress(radix);
break;
} else {
util.print_error("Compression algorithm ZLIB only supports " +
"DEFLATE compression method.");
}
break;
case 'bzip2':
// TODO: need to implement this
throw new Error('Compression algorithm BZip2 [BZ2] is not implemented.');
break;
default:
throw new Error("Compression algorithm unknown :" + this.alogrithm);
break;
}
this.packets.read(decompressed);
}
/**
* Compress the packet data (member decompressedData)
* @param {Integer} type Algorithm to be used // See RFC 4880 9.3
* @param {String} data Data to be compressed
* @return {String} The compressed data stored in attribute compressedData
*/
this.compress = function() {
switch (this.algorithm) {
case 'uncompressed': // - Uncompressed
this.compressed = this.packets.write();
break;
case 'zip': // - ZIP [RFC1951]
util.print_error("Compression algorithm ZIP [RFC1951] is not implemented.");
break;
case 'zlib': // - ZLIB [RFC1950]
// TODO: need to implement this
util.print_error("Compression algorithm ZLIB [RFC1950] is not implemented.");
break;
case 'bzip2': // - BZip2 [BZ2]
// TODO: need to implement this
util.print_error("Compression algorithm BZip2 [BZ2] is not implemented.");
break;
default:
util.print_error("Compression algorithm unknown :"+this.type);
break;
}
}
};
var enums = require('../enums.js');
module.exports = {
list: require('./packetlist.js'),
}
var packets = require('./all_packets.js');
for(var i in packets)
module.exports[i] = packets[i];
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
var util = require('../util'),
enums = require('../enums.js');
/**
* @class
* @classdesc Implementation of the Literal Data Packet (Tag 11)
*
* RFC4880 5.9: A Literal Data packet contains the body of a message; data that
* is not to be further interpreted.
*/
module.exports = function packet_literal() {
this.format = 'utf8';
this.data = '';
this.date = new Date();
/**
* Set the packet data to a javascript native string or a squence of
* bytes. Conversion to a proper utf8 encoding takes place when the
* packet is written.
* @param {String} str Any native javascript string
* @param {openpgp_packet_literaldata.format} format
*/
this.set = function(str, format) {
this.format = format;
this.data = str;
}
/**
* Set the packet data to value represented by the provided string
* of bytes together with the appropriate conversion format.
* @param {String} bytes The string of bytes
* @param {openpgp_packet_literaldata.format} format
*/
this.setBytes = function(bytes, format) {
this.format = format;
if(format == 'utf8')
bytes = util.decode_utf8(bytes);
this.data = bytes;
}
/**
* Get the byte sequence representing the literal packet data
* @returns {String} A sequence of bytes
*/
this.getBytes = function() {
if(this.format == 'utf8')
return util.encode_utf8(this.data);
else
return this.data;
}
/**
* Parsing function for a literal data packet (tag 11).
*
* @param {String} input Payload of a tag 11 packet
* @param {Integer} position
* Position to start reading from the input string
* @param {Integer} len
* Length of the packet or the remaining length of
* input at position
* @return {openpgp_packet_encrypteddata} object representation
*/
this.read = function(bytes) {
// - A one-octet field that describes how the data is formatted.
var format = enums.read(enums.literal, bytes[0].charCodeAt());
var filename_len = bytes.charCodeAt(1);
this.filename = util.decode_utf8(bytes.substr(2, filename_len));
this.date = util.readDate(bytes.substr(2
+ filename_len, 4));
var data = bytes.substring(6 + filename_len);
this.setBytes(data, format);
}
/**
* Creates a string representation of the packet
*
* @param {String} data The data to be inserted as body
* @return {String} string-representation of the packet
*/
this.write = function() {
var filename = util.encode_utf8("msg.txt");
var data = this.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;
}
}
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
/**
* @class
* @classdesc Implementation of the strange "Marker packet" (Tag 10)
*
* RFC4880 5.8: An experimental version of PGP used this packet as the Literal
* packet, but no released version of PGP generated Literal packets with this
* tag. With PGP 5.x, this packet has been reassigned and is reserved for use as
* the Marker packet.
*
* Such a packet MUST be ignored when received.
*/
function packet_marker() {
/**
* Parsing function for a literal data packet (tag 10).
*
* @param {String} input Payload of a tag 10 packet
* @param {Integer} position
* Position to start reading from the input string
* @param {Integer} len
* Length of the packet or the remaining length of
* input at position
* @return {openpgp_packet_encrypteddata} Object representation
*/
this.read = function(bytes) {
if (bytes[0].charCodeAt() == 0x50 && // P
bytes[1].charCodeAt() == 0x47 && // G
bytes[2].charCodeAt() == 0x50) // P
return true;
// marker packet does not contain "PGP"
return false;
}
}
module.exports = packet_marker;
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
/**
* @class
* @classdesc Implementation of the One-Pass Signature Packets (Tag 4)
*
* RFC4880 5.4:
* The One-Pass Signature packet precedes the signed data and contains
* enough information to allow the receiver to begin calculating any
* 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.
*/
var enums = require('../enums.js'),
type_keyid = require('../type/keyid.js');
module.exports = function packet_one_pass_signature() {
this.version = null; // A one-octet version number. The current version is 3.
this.type = null; // A one-octet signature type. Signature types are described in RFC4880 Section 5.2.1.
this.hashAlgorithm = null; // A one-octet number describing the hash algorithm used. (See RFC4880 9.4)
this.publicKeyAlgorithm = null; // A one-octet number describing the public-key algorithm used. (See RFC4880 9.1)
this.signingKeyId = null; // An eight-octet number holding the Key ID of the signing key.
this.flags = null; // 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.
/**
* parsing function for a one-pass signature packet (tag 4).
* @param {String} bytes payload of a tag 4 packet
* @param {Integer} position position to start reading from the bytes string
* @param {Integer} len length of the packet or the remaining length of bytes at position
* @return {openpgp_packet_encrypteddata} object representation
*/
this.read = function(bytes) {
var mypos = 0;
// A one-octet version number. The current version is 3.
this.version = bytes.charCodeAt(mypos++);
// A one-octet signature type. Signature types are described in
// Section 5.2.1.
this.type = enums.read(enums.signature, bytes.charCodeAt(mypos++));
// A one-octet number describing the hash algorithm used.
this.hashAlgorithm = enums.read(enums.hash, bytes.charCodeAt(mypos++));
// A one-octet number describing the public-key algorithm used.
this.publicKeyAlgorithm = enums.read(enums.publicKey, bytes.charCodeAt(mypos++));
// An eight-octet number holding the Key ID of the signing key.
this.signingKeyId = new type_keyid();
this.signingKeyId.read(bytes.substr(mypos));
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++);
return this;
}
/**
* creates a string representation of a one-pass signature packet
* @param {Integer} type Signature types as described in RFC4880 Section 5.2.1.
* @param {Integer} hashalgorithm the hash algorithm used within the signature
* @param {openpgp_msg_privatekey} privatekey the private key used to generate the signature
* @param {Integer} length length of data to be signed
* @param {boolean} nested boolean showing whether the signature is nested.
* "true" indicates that the next packet is another One-Pass Signature packet
* that describes another signature to be applied to the same message data.
* @return {String} a string representation of a one-pass signature packet
*/
this.write = function(type, hashalgorithm, privatekey, length, nested) {
var result ="";
result += String.fromCharCode(3);
result += String.fromCharCode(enums.write(enums.signature, type));
result += String.fromCharCode(enums.write(enums.hash, this.hashAlgorithm));
result += String.fromCharCode(enums.write(enums.publicKey, privatekey.algorithm));
result += privatekey.getKeyId();
if (nested)
result += String.fromCharCode(0);
else
result += String.fromCharCode(1);
return result;
}
};
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
var enums = require('../enums.js'),
util = require('../util');
module.exports = {
readSimpleLength: function(bytes) {
var len = 0,
offset,
type = bytes[0].charCodeAt();
if (type < 192) {
len = bytes[0].charCodeAt();
offset = 1;
} else if (type < 255) {
len = ((bytes[0].charCodeAt() - 192) << 8) + (bytes[1].charCodeAt()) + 192;
offset = 2;
} else if (type == 255) {
len = util.readNumber(bytes.substr(1, 4));
offset = 5;
}
return { len: len, offset: offset };
},
/**
* Encodes a given integer of length to the openpgp length specifier to a
* string
*
* @param {Integer} length The length to encode
* @return {String} String with openpgp length representation
*/
writeSimpleLength: function(length) {
var result = "";
if (length < 192) {
result += String.fromCharCode(length);
} else if (length > 191 && length < 8384) {
/*
* let a = (total data packet length) - 192 let bc = two octet
* representation of a let d = b + 192
*/
result += String.fromCharCode(((length - 192) >> 8) + 192);
result += String.fromCharCode((length - 192) & 0xFF);
} else {
result += String.fromCharCode(255);
result += util.writeNumber(length, 4);
}
return result;
},
/**
* Writes a packet header version 4 with the given tag_type and length to a
* string
*
* @param {Integer} tag_type Tag type
* @param {Integer} length Length of the payload
* @return {String} String of the header
*/
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;
},
/**
* Writes a packet header Version 3 with the given tag_type and length to a
* string
*
* @param {Integer} tag_type Tag type
* @param {Integer} length Length of the payload
* @return {String} String of the header
*/
writeOldHeader: function(tag_type, length) {
var result = "";
if (length < 256) {
result += String.fromCharCode(0x80 | (tag_type << 2));
result += String.fromCharCode(length);
} else if (length < 65536) {
result += String.fromCharCode(0x80 | (tag_type << 2) | 1);
result += util.writeNumber(length, 2);
} else {
result += String.fromCharCode(0x80 | (tag_type << 2) | 2);
result += util.writeNumber(length, 4);
}
return result;
},
/**
* Generic static Packet Parser function
*
* @param {String} input Input stream as string
* @param {integer} position Position to start parsing
* @param {integer} len Length of the input from position on
* @return {Object} Returns a parsed openpgp_packet
*/
read: function(input, position, len) {
// some sanity checks
if (input == null || input.length <= position
|| input.substring(position).length < 2
|| (input[position].charCodeAt() & 0x80) == 0) {
util
.print_error("Error during parsing. This message / key is probably not containing a valid OpenPGP format.");
return null;
}
var mypos = position;
var tag = -1;
var format = -1;
var packet_length;
format = 0; // 0 = old format; 1 = new format
if ((input[mypos].charCodeAt() & 0x40) != 0) {
format = 1;
}
var packet_length_type;
if (format) {
// new format header
tag = input[mypos].charCodeAt() & 0x3F; // bit 5-0
} else {
// old format header
tag = (input[mypos].charCodeAt() & 0x3F) >> 2; // bit 5-2
packet_length_type = input[mypos].charCodeAt() & 0x03; // bit 1-0
}
// header octet parsing done
mypos++;
// parsed length from length field
var bodydata = null;
// used for partial body lengths
var real_packet_length = -1;
if (!format) {
// 4.2.1. Old Format Packet Lengths
switch (packet_length_type) {
case 0: // The packet has a one-octet length. The header is 2 octets
// long.
packet_length = input[mypos++].charCodeAt();
break;
case 1: // The packet has a two-octet length. The header is 3 octets
// long.
packet_length = (input[mypos++].charCodeAt() << 8)
| input[mypos++].charCodeAt();
break;
case 2: // The packet has a four-octet length. The header is 5
// octets long.
packet_length = (input[mypos++].charCodeAt() << 24)
| (input[mypos++].charCodeAt() << 16)
| (input[mypos++].charCodeAt() << 8)
| input[mypos++].charCodeAt();
break;
default:
// 3 - The packet is of indeterminate length. The header is 1
// octet long, and the implementation must determine how long
// the packet is. If the packet is in a file, this means that
// the packet extends until the end of the file. In general,
// an implementation SHOULD NOT use indeterminate-length
// packets except where the end of the data will be clear
// from the context, and even then it is better to use a
// definite length, or a new format header. The new format
// headers described below have a mechanism for precisely
// encoding data of indeterminate length.
packet_length = len;
break;
}
} else // 4.2.2. New Format Packet Lengths
{
// 4.2.2.1. One-Octet Lengths
if (input[mypos].charCodeAt() < 192) {
packet_length = input[mypos++].charCodeAt();
util.print_debug("1 byte length:" + packet_length);
// 4.2.2.2. Two-Octet Lengths
} else if (input[mypos].charCodeAt() >= 192
&& input[mypos].charCodeAt() < 224) {
packet_length = ((input[mypos++].charCodeAt() - 192) << 8)
+ (input[mypos++].charCodeAt()) + 192;
util.print_debug("2 byte length:" + packet_length);
// 4.2.2.4. Partial Body Lengths
} else if (input[mypos].charCodeAt() > 223
&& input[mypos].charCodeAt() < 255) {
packet_length = 1 << (input[mypos++].charCodeAt() & 0x1F);
util.print_debug("4 byte length:" + packet_length);
// EEEK, we're reading the full data here...
var mypos2 = mypos + packet_length;
bodydata = input.substring(mypos, mypos + packet_length);
while (true) {
if (input[mypos2].charCodeAt() < 192) {
var tmplen = input[mypos2++].charCodeAt();
packet_length += tmplen;
bodydata += input.substring(mypos2, mypos2 + tmplen);
mypos2 += tmplen;
break;
} else if (input[mypos2].charCodeAt() >= 192
&& input[mypos2].charCodeAt() < 224) {
var tmplen = ((input[mypos2++].charCodeAt() - 192) << 8)
+ (input[mypos2++].charCodeAt()) + 192;
packet_length += tmplen;
bodydata += input.substring(mypos2, mypos2 + tmplen);
mypos2 += tmplen;
break;
} else if (input[mypos2].charCodeAt() > 223
&& input[mypos2].charCodeAt() < 255) {
var tmplen = 1 << (input[mypos2++].charCodeAt() & 0x1F);
packet_length += tmplen;
bodydata += input.substring(mypos2, mypos2 + tmplen);
mypos2 += tmplen;
} else {
mypos2++;
var tmplen = (input[mypos2++].charCodeAt() << 24)
| (input[mypos2++].charCodeAt() << 16)
| (input[mypos2++].charCodeAt() << 8)
| input[mypos2++].charCodeAt();
bodydata += input.substring(mypos2, mypos2 + tmplen);
packet_length += tmplen;
mypos2 += tmplen;
break;
}
}
real_packet_length = mypos2;
// 4.2.2.3. Five-Octet Lengths
} else {
mypos++;
packet_length = (input[mypos++].charCodeAt() << 24)
| (input[mypos++].charCodeAt() << 16)
| (input[mypos++].charCodeAt() << 8)
| input[mypos++].charCodeAt();
}
}
// if there was'nt a partial body length: use the specified
// packet_length
if (real_packet_length == -1) {
real_packet_length = packet_length;
}
if (bodydata == null) {
bodydata = input.substring(mypos, mypos + real_packet_length);
}
return {
tag: tag,
packet: bodydata,
offset: mypos + real_packet_length
};
}
}
var packetParser = require('./packet.js'),
packets = require('./all_packets.js'),
enums = require('../enums.js');
/**
* @class
* @classdesc This class represents a list of openpgp packets.
* Take care when iterating over it - the packets themselves
* are stored as numerical indices.
*/
module.exports = function packetlist() {
/** The number of packets contained within the list.
* @readonly
* @type {Integer} */
this.length = 0;
/**
* Reads a stream of binary data and interprents it as a list of packets.
* @param {openpgp_bytearray} An array of bytes.
*/
this.read = function(bytes) {
var i = 0;
while(i < bytes.length) {
var parsed = packetParser.read(bytes, i, bytes.length - i);
i = parsed.offset;
var tag = enums.read(enums.packet, parsed.tag);
var packet = new packets[tag]();
this.push(packet);
packet.read(parsed.packet);
}
}
/**
* Creates a binary representation of openpgp objects contained within the
* class instance.
* @returns {openpgp_bytearray} An array of bytes containing valid openpgp packets.
*/
this.write = function() {
var bytes = '';
for(var i = 0; i < this.length; i++) {
var packetbytes = this[i].write();
bytes += packetParser.writeHeader(this[i].tag, packetbytes.length);
bytes += packetbytes;
}
return bytes;
}
/**
* Adds a packet to the list. This is the only supported method of doing so;
* writing to packetlist[i] directly will result in an error.
*/
this.push = function(packet) {
packet.packets = new packetlist();
this[this.length] = packet;
this.length++;
}
}
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
var util = require('../util'),
type_mpi = require('../type/mpi.js'),
enums = require('../enums.js'),
crypto = require('../crypto');
/**
* @class
* @classdesc Implementation of the Key Material Packet (Tag 5,6,7,14)
*
* RFC4480 5.5:
* A key material packet contains all the information about a public or
* private key. There are four variants of this packet type, and two
* major versions. Consequently, this section is complex.
*/
module.exports = function packet_public_key() {
/** Key creation date.
* @type {Date} */
this.created = new Date();
/** A list of multiprecision integers
* @type {openpgp_type_mpi} */
this.mpi = [];
/** Public key algorithm
* @type {openpgp.publickey} */
this.algorithm = 'rsa_sign';
/**
* Internal Parser for public keys as specified in RFC 4880 section
* 5.5.2 Public-Key Packet Formats
* called by read_tag<num>
* @param {String} input Input string to read the packet from
* @param {Integer} position Start position for the parser
* @param {Integer} len Length of the packet or remaining length of input
* @return {Object} This object with attributes set by the parser
*/
this.readPublicKey = this.read = function(bytes) {
// A one-octet version number (3 or 4).
var version = bytes[0].charCodeAt();
if (version == 4) {
// - A four-octet number denoting the time that the key was created.
this.created = util.readDate(bytes.substr(1, 4));
// - A one-octet number denoting the public-key algorithm of this key.
this.algorithm = enums.read(enums.publicKey, bytes[5].charCodeAt());
var mpicount = crypto.getPublicMpiCount(this.algorithm);
this.mpi = [];
var bmpi = bytes.substr(6);
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))
if(p > bmpi.length)
util.print_error("openpgp.packet.keymaterial.js\n"
+'error reading MPI @:'+p);
}
return p + 6;
} else {
throw new Error('Version ' + version + ' of the key packet is unsupported.');
}
}
/*
* Same as write_private_key, but has less information because of
* public key.
* @param {Integer} keyType Follows the OpenPGP algorithm standard,
* IE 1 corresponds to RSA.
* @param {RSA.keyObject} key
* @param timePacket
* @return {Object} {body: [string]OpenPGP packet body contents,
* header: [string] OpenPGP packet header, string: [string] header+body}
*/
this.writePublicKey = this.write = function() {
// Version
var result = String.fromCharCode(4);
result += util.writeDate(this.created);
result += String.fromCharCode(enums.write(enums.publicKey, this.algorithm));
var mpicount = crypto.getPublicMpiCount(this.algorithm);
for(var i = 0; i < mpicount; i++) {
result += this.mpi[i].write();
}
return result;
}
// Write an old version packet - it's used by some of the internal routines.
this.writeOld = function() {
var bytes = this.writePublicKey();
return String.fromCharCode(0x99) +
util.writeNumber(bytes.length, 2) +
bytes;
}
/**
* Calculates the key id of the key
* @return {String} A 8 byte key id
*/
this.getKeyId = function() {
return this.getFingerprint().substr(12, 8);
}
/**
* Calculates the fingerprint of the key
* @return {String} A string containing the fingerprint
*/
this.getFingerprint = function() {
var toHash = this.writeOld();
return crypto.hash.sha1(toHash, toHash.length);
}
}
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
var type_keyid = require('../type/keyid.js'),
util = require('../util'),
type_mpi = require('../type/mpi.js'),
enums = require('../enums.js'),
crypto = require('../crypto');
/**
* @class
* @classdesc Public-Key Encrypted Session Key Packets (Tag 1)
*
* RFC4880 5.1: A Public-Key Encrypted Session Key packet holds the session key
* used to encrypt a message. Zero or more Public-Key Encrypted Session Key
* packets and/or Symmetric-Key Encrypted Session Key packets may precede a
* Symmetrically Encrypted Data Packet, which holds an encrypted message. The
* message is encrypted with the session key, and the session key is itself
* encrypted and stored in the Encrypted Session Key packet(s). The
* Symmetrically Encrypted Data Packet is preceded by one Public-Key Encrypted
* Session Key packet for each OpenPGP key to which the message is encrypted.
* 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.
*/
module.exports = function packet_public_key_encrypted_session_key() {
this.version = 3;
this.publicKeyId = new type_keyid();
this.publicKeyAlgorithm = 'rsa_encrypt';
this.sessionKey = null;
this.sessionKeyAlgorithm = 'aes256';
/** @type {openpgp_type_mpi[]} */
this.encrypted = [];
/**
* Parsing function for a publickey encrypted session key packet (tag 1).
*
* @param {String} 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
* @return {openpgp_packet_encrypteddata} Object representation
*/
this.read = function(bytes) {
this.version = bytes[0].charCodeAt();
this.publicKeyId.read(bytes.substr(1));
this.publicKeyAlgorithm = enums.read(enums.publicKey, bytes[9].charCodeAt());
var i = 10;
var integerCount = (function(algo) {
switch (algo) {
case 'rsa_encrypt':
case 'rsa_encrypt_sign':
return 1;
case 'elgamal':
return 2;
default:
throw new Error("Invalid algorithm.");
}
})(this.publicKeyAlgorithm);
this.encrypted = [];
for(var j = 0; j < integerCount; j++) {
var mpi = new type_mpi();
i += mpi.read(bytes.substr(i));
this.encrypted.push(mpi);
}
}
/**
* Create a string representation of a tag 1 packet
*
* @param {String} publicKeyId
* The public key id corresponding to publicMPIs key as string
* @param {openpgp_type_mpi[]} publicMPIs
* Multiprecision integer objects describing the public key
* @param {Integer} pubalgo
* The corresponding public key algorithm // See RFC4880 9.1
* @param {Integer} symmalgo
* The symmetric cipher algorithm used to encrypt the data
* within an encrypteddatapacket or encryptedintegrity-
* protecteddatapacket
* following this packet //See RFC4880 9.2
* @param {String} sessionkey
* A string of randombytes representing the session key
* @return {String} The string representation
*/
this.write = function() {
var result = String.fromCharCode(this.version);
result += this.publicKeyId.write();
result += String.fromCharCode(
enums.write(enums.publicKey, this.publicKeyAlgorithm));
for ( var i = 0; i < this.encrypted.length; i++) {
result += this.encrypted[i].write()
}
return result;
}
this.encrypt = function(key) {
var data = String.fromCharCode(
enums.write(enums.symmetric, this.sessionKeyAlgorithm));
data += this.sessionKey;
var checksum = util.calc_checksum(this.sessionKey);
data += util.writeNumber(checksum, 2);
var mpi = new type_mpi();
mpi.fromBytes(crypto.pkcs1.eme.encode(
data,
key.mpi[0].byteLength()));
this.encrypted = crypto.publicKeyEncrypt(
this.publicKeyAlgorithm,
key.mpi,
mpi);
}
/**
* Decrypts the session key (only for public key encrypted session key
* packets (tag 1)
*
* @param {openpgp_msg_message} msg
* The message object (with member encryptedData
* @param {openpgp_msg_privatekey} key
* Private key with secMPIs unlocked
* @return {String} The unencrypted session key
*/
this.decrypt = function(key) {
var result = crypto.publicKeyDecrypt(
this.publicKeyAlgorithm,
key.mpi,
this.encrypted).toBytes();
var checksum = util.readNumber(result.substr(result.length - 2));
var decoded = crypto.pkcs1.eme.decode(
result,
key.mpi[0].byteLength());
var key = decoded.substring(1, decoded.length - 2);
if(checksum != util.calc_checksum(key)) {
throw new Error('Checksum mismatch');
}
else {
this.sessionKey = key;
this.sessionKeyAlgorithm =
enums.read(enums.symmetric, decoded.charCodeAt(0));
}
}
};
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
var public_key = require('./public_key.js');
module.exports = function public_subkey() {
public_key.call(this);
}
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
var publicKey = require('./public_key.js'),
enums = require('../enums.js'),
util = require('../util'),
crypto = require('../crypto'),
type_mpi = require('../type/mpi.js'),
type_s2k = require('../type/s2k.js');
/**
* @class
* @classdesc Implementation of the Key Material Packet (Tag 5,6,7,14)
*
* RFC4480 5.5:
* A key material packet contains all the information about a public or
* private key. There are four variants of this packet type, and two
* major versions. Consequently, this section is complex.
*/
function packet_secret_key() {
publicKey.call(this);
this.encrypted = null;
function get_hash_len(hash) {
if(hash == 'sha1')
return 20;
else
return 2;
}
function get_hash_fn(hash) {
if(hash == 'sha1')
return crypto.hash.sha1;
else
return function(c) {
return util.writeNumber(util.calc_checksum(c), 2);
}
}
// Helper function
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 hash = hashfn(cleartext);
if(hash != hashtext)
throw new Error("Hash mismatch.");
var mpis = crypto.getPrivateMpiCount(algorithm);
var j = 0;
var mpi = [];
for(var i = 0; i < mpis && j < cleartext.length; i++) {
mpi[i] = new type_mpi();
j += mpi[i].read(cleartext.substr(j));
}
return mpi;
}
function write_cleartext_mpi(hash_algorithm, algorithm, mpi) {
var bytes= '';
var discard = crypto.getPublicMpiCount(algorithm);
for(var i = discard; i < mpi.length; i++) {
bytes += mpi[i].write();
}
bytes += get_hash_fn(hash_algorithm)(bytes);
return bytes;
}
// 5.5.3. Secret-Key Packet Formats
/**
* Internal parser for private keys as specified in RFC 4880 section 5.5.3
* @param {String} bytes Input string to read the packet from
* @param {Integer} position Start position for the parser
* @param {Integer} len Length of the packet or remaining length of bytes
* @return {Object} This object with attributes set by the parser
*/
this.read = function(bytes) {
// - A Public-Key or Public-Subkey packet, as described above.
var len = this.readPublicKey(bytes);
bytes = bytes.substr(len);
// - 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[0].charCodeAt();
if(isEncrypted) {
this.encrypted = bytes;
} else {
// - Plain or encrypted multiprecision integers comprising the secret
// key data. These algorithm-specific fields are as described
// below.
this.mpi = this.mpi.concat(parse_cleartext_mpi('mod', bytes.substr(1),
this.algorithm));
}
}
/*
* Creates an OpenPGP key packet for the given key. much
* TODO in regards to s2k, subkeys.
* @param {Integer} keyType Follows the OpenPGP algorithm standard,
* IE 1 corresponds to RSA.
* @param {RSA.keyObject} key
* @param passphrase
* @param s2kHash
* @param symmetricEncryptionAlgorithm
* @param timePacket
* @return {Object} {body: [string]OpenPGP packet body contents,
header: [string] OpenPGP packet header, string: [string] header+body}
*/
this.write = function() {
var bytes = this.writePublicKey();
if(!this.encrypted) {
bytes += String.fromCharCode(0);
bytes += write_cleartext_mpi('mod', this.algorithm, this.mpi);
} else {
bytes += this.encrypted;
}
return bytes;
}
/** Encrypt the payload. By default, we use aes256 and iterated, salted string
* to key specifier
* @param {String} passphrase
*/
this.encrypt = function(passphrase) {
var s2k = new type_s2k(),
symmetric = 'aes256',
cleartext = write_cleartext_mpi('sha1', this.algorithm, this.mpi),
key = produceEncryptionKey(s2k, passphrase, symmetric),
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;
this.encrypted += crypto.cfb.normalEncrypt(symmetric, key, cleartext, iv);
}
function produceEncryptionKey(s2k, passphrase, algorithm) {
return s2k.produce_key(passphrase,
crypto.cipher[algorithm].keySize);
}
/**
* Decrypts the private key MPIs which are needed to use the key.
* openpgp_packet_keymaterial.hasUnencryptedSecretKeyData should be
* false otherwise
* a call to this function is not needed
*
* @param {String} str_passphrase The passphrase for this private key
* as string
* @return {Boolean} True if the passphrase was correct; false if not
*/
this.decrypt = function(passphrase) {
if (!this.encrypted)
return;
var i = 0,
symmetric,
key;
var s2k_usage = this.encrypted[i++].charCodeAt();
// - [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[i++].charCodeAt();
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));
key = produceEncryptionKey(s2k, passphrase, symmetric);
} else {
symmetric = s2k_usage;
symmetric = enums.read(enums.symmetric, symmetric);
key = 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);
i += iv.length;
var cleartext,
ciphertext = this.encrypted.substr(i);
cleartext = crypto.cfb.normalDecrypt(symmetric, key, ciphertext, iv);
var hash = s2k_usage == 254 ?
'sha1' :
'mod';
this.mpi = this.mpi.concat(parse_cleartext_mpi(hash, cleartext,
this.algorithm));
}
this.generate = function(bits) {
}
}
packet_secret_key.prototype = new publicKey;
module.exports = packet_secret_key;
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
var secret_key = require('./secret_key.js');
module.exports = function secret_subkey() {
secret_key.call(this);
}
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
var util = require('../util'),
packet = require('./packet.js'),
enums = require('../enums.js'),
crypto = require('../crypto'),
type_mpi = require('../type/mpi.js');
/**
* @class
* @classdesc Implementation of the Signature Packet (Tag 2)
*
* RFC4480 5.2:
* A Signature packet describes a binding between some public key and
* some data. The most common signatures are a signature of a file or a
* block of text, and a signature that is a certification of a User ID.
*/
module.exports = function packet_signature() {
this.signatureType = null;
this.hashAlgorithm = null;
this.publicKeyAlgorithm = null;
this.signatureData = null;
this.signedHashValue = null;
this.mpi = null;
this.created = null;
this.signatureExpirationTime = null;
this.signatureNeverExpires = null;
this.exportable = null;
this.trustLevel = null;
this.trustAmount = null;
this.regularExpression = null;
this.revocable = null;
this.keyExpirationTime = null;
this.keyNeverExpires = null;
this.preferredSymmetricAlgorithms = null;
this.revocationKeyClass = null;
this.revocationKeyAlgorithm = null;
this.revocationKeyFingerprint = null;
this.issuerKeyId = null;
this.notation = {};
this.preferredHashAlgorithms = null;
this.preferredCompressionAlgorithms = null;
this.keyServerPreferences = null;
this.preferredKeyServer = null;
this.isPrimaryUserID = null;
this.policyURI = null;
this.keyFlags = null;
this.signersUserId = null;
this.reasonForRevocationFlag = null;
this.reasonForRevocationString = null;
this.signatureTargetPublicKeyAlgorithm = null;
this.signatureTargetHashAlgorithm = null;
this.signatureTargetHash = null;
this.embeddedSignature = null;
this.verified = false;
/**
* parsing function for a signature packet (tag 2).
* @param {String} bytes payload of a tag 2 packet
* @param {Integer} position position to start reading from the bytes string
* @param {Integer} len length of the packet or the remaining length of bytes at position
* @return {openpgp_packet_encrypteddata} object representation
*/
this.read = function(bytes) {
var i = 0;
var version = bytes[i++].charCodeAt();
// switch on version (3 and 4)
switch (version) {
case 3:
// One-octet length of following hashed material. MUST be 5.
if (bytes[i++].charCodeAt() != 5)
util.print_debug("openpgp.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[i++].charCodeAt();
// Four-octet creation time.
this.created = util.readDate(bytes.substr(i, 4));
i += 4;
// storing data appended to data which gets verified
this.signatureData = bytes.substring(position, i);
// Eight-octet Key ID of signer.
this.issuerKeyId = bytes.substring(i, i +8);
i += 8;
// One-octet public-key algorithm.
this.publicKeyAlgorithm = bytes[i++].charCodeAt();
// One-octet hash algorithm.
this.hashAlgorithm = bytes[i++].charCodeAt();
break;
case 4:
this.signatureType = bytes[i++].charCodeAt();
this.publicKeyAlgorithm = bytes[i++].charCodeAt();
this.hashAlgorithm = bytes[i++].charCodeAt();
function subpackets(bytes, signed) {
// Two-octet scalar octet count for following hashed subpacket
// data.
var subpacket_length = util.readNumber(
bytes.substr(0, 2));
var i = 2;
// Hashed subpacket data set (zero or more subpackets)
var subpacked_read = 0;
while (i < 2 + subpacket_length) {
var len = packet.readSimpleLength(bytes.substr(i));
i += len.offset;
// Since it is trivial to add data to the unhashed portion of
// the packet we simply ignore all unauthenticated data.
if(signed)
this.read_sub_packet(bytes.substr(i, len.len));
i += len.len;
}
return i;
}
i += subpackets.call(this, bytes.substr(i), true);
// A V4 signature hashes the packet body
// starting from its first field, the version number, through the end
// of the hashed subpacket data. Thus, the fields hashed are the
// 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);
i += subpackets.call(this, bytes.substr(i), false);
break;
default:
throw new Error('Version ' + version + ' of the signature is unsupported.');
break;
}
// Two-octet field holding left 16 bits of signed hash value.
this.signedHashValue = bytes.substr(i, 2);
i += 2;
this.signature = bytes.substr(i);
}
this.write = function() {
return this.signatureData +
util.writeNumber(0, 2) + // Number of unsigned subpackets.
this.signedHashValue +
this.signature;
}
/**
* Signs provided data. This needs to be done prior to serialization.
* @param {Object} data Contains packets to be signed.
* @param {openpgp_msg_privatekey} privatekey private key used to sign the message.
*/
this.sign = function(key, data) {
var signatureType = enums.write(enums.signature, this.signatureType),
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);
// Add subpackets here
result += util.writeNumber(0, 2);
this.signatureData = result;
var trailer = this.calculateTrailer();
var toHash = this.toSign(signatureType, data) +
this.signatureData + trailer;
var hash = crypto.hash.digest(hashAlgorithm, toHash);
this.signedHashValue = hash.substr(0, 2);
this.signature = crypto.signature.sign(hashAlgorithm,
publicKeyAlgorithm, key.mpi, toHash);
}
/**
* creates a string representation of a sub signature packet (See RFC 4880 5.2.3.1)
* @param {Integer} type subpacket signature type. Signature types as described
* in RFC4880 Section 5.2.3.2
* @param {String} data data to be included
* @return {String} a string-representation of a sub signature packet (See 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;
}
// V4 signature sub packets
this.read_sub_packet = function(bytes) {
var mypos = 0;
function read_array(prop, bytes) {
this[prop] = [];
for (var i = 0; i < bytes.length; i++) {
this[prop].push(bytes[i].charCodeAt());
}
}
// The leftwost bit denotes a "critical" packet, but we ignore it.
var type = bytes[mypos++].charCodeAt() & 0x7F;
// subpacket type
switch (type) {
case 2: // Signature Creation Time
this.created = util.readDate(bytes.substr(mypos));
break;
case 3: // Signature Expiration Time
var time = util.readDate(bytes.substr(mypos));
this.signatureNeverExpires = time.getTime() == 0;
this.signatureExpirationTime = time;
break;
case 4: // Exportable Certification
this.exportable = bytes[mypos++].charCodeAt() == 1;
break;
case 5: // Trust Signature
this.trustLevel = bytes[mypos++].charCodeAt();
this.trustAmount = bytes[mypos++].charCodeAt();
break;
case 6: // Regular Expression
this.regularExpression = bytes.substr(mypos);
break;
case 7: // Revocable
this.revocable = bytes[mypos++].charCodeAt() == 1;
break;
case 9: // Key Expiration Time
var time = util.readDate(bytes.substr(mypos));
this.keyExpirationTime = time;
this.keyNeverExpires = time.getTime() == 0;
break;
case 11: // Preferred Symmetric Algorithms
this.preferredSymmetricAlgorithms = [];
while(mypos != bytes.length) {
this.preferredSymmetricAlgorithms.push(bytes[mypos++].charCodeAt());
}
break;
case 12: // Revocation Key
// (1 octet of class, 1 octet of public-key algorithm ID, 20
// octets of
// fingerprint)
this.revocationKeyClass = bytes[mypos++].charCodeAt();
this.revocationKeyAlgorithm = bytes[mypos++].charCodeAt();
this.revocationKeyFingerprint = bytes.substr(mypos, 20);
break;
case 16: // Issuer
this.issuerKeyId = bytes.substr(mypos, 8);
break;
case 20: // Notation Data
// We don't know how to handle anything but a text flagged data.
if(bytes[mypos].charCodeAt() == 0x80) {
// We extract key/value tuple from the byte stream.
mypos += 4;
var m = util.writeNumber(bytes.substr(mypos, 2));
mypos += 2
var n = util.writeNumber(bytes.substr(mypos, 2));
mypos += 2
var name = bytes.substr(mypos, m),
value = bytes.substr(mypos + m, n);
this.notation[name] = value;
}
else throw new Error("Unsupported notation flag.");
break;
case 21: // Preferred Hash Algorithms
read_array.call(this, 'preferredHashAlgorithms', bytes.substr(mypos));
break;
case 22: // Preferred Compression Algorithms
read_array.call(this, 'preferredCompressionAlgorithms ', bytes.substr(mypos));
break;
case 23: // Key Server Preferences
read_array.call(this, 'keyServerPreferencess', bytes.substr(mypos));
break;
case 24: // Preferred Key Server
this.preferredKeyServer = bytes.substr(mypos);
break;
case 25: // Primary User ID
this.isPrimaryUserID = bytes[mypos++] != 0;
break;
case 26: // Policy URI
this.policyURI = bytes.substr(mypos);
break;
case 27: // Key Flags
read_array.call(this, 'keyFlags', bytes.substr(mypos));
break;
case 28: // Signer's User ID
this.signersUserId += bytes.substr(mypos);
break;
case 29: // Reason for Revocation
this.reasonForRevocationFlag = bytes[mypos++].charCodeAt();
this.reasonForRevocationString = bytes.substr(mypos);
break;
case 30: // Features
read_array.call(this, 'features', bytes.substr(mypos));
break;
case 31: // Signature Target
// (1 octet public-key algorithm, 1 octet hash algorithm, N octets hash)
this.signatureTargetPublicKeyAlgorithm = bytes[mypos++].charCodeAt();
this.signatureTargetHashAlgorithm = bytes[mypos++].charCodeAt();
var len = crypto.getHashByteLength(this.signatureTargetHashAlgorithm);
this.signatureTargetHash = bytes.substr(mypos, len);
break;
case 32: // Embedded Signature
this.embeddedSignature = new packet_signature();
this.embeddedSignature.read(bytes.substr(mypos));
break;
default:
util.print_error("openpgp.packet.signature.js\n"+
'unknown signature subpacket type '+type+" @:"+mypos+
" subplen:"+subplen+" len:"+len);
break;
}
};
// Produces data to produce signature on
this.toSign = function(type, data) {
var t = enums.signature
switch(type) {
case t.binary:
return data.literal.getBytes();
case t.text:
return this.toSign(t.binary, data)
.replace(/\r\n/g, '\n')
.replace(/\n/g, '\r\n');
case t.standalone:
return ''
case t.cert_generic:
case t.cert_persona:
case t.cert_casual:
case t.cert_positive:
case t.cert_revocation:
{
var packet, tag;
if(data.userid != undefined) {
tag = 0xB4;
packet = data.userid;
}
else if(data.userattribute != undefined) {
tag = 0xD1
packet = data.userattribute;
}
else throw new Error('Either a userid or userattribute packet needs to be ' +
'supplied for certification.');
var bytes = packet.write();
return this.toSign(t.key, data) +
String.fromCharCode(tag) +
util.writeNumber(bytes.length, 4) +
bytes;
}
case t.subkey_binding:
case t.key_binding:
{
return 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 sigtature.');
return data.key.writeOld();
}
case t.key_revocation:
case t.subkey_revocation:
return this.toSign(t.key, data);
case t.timestamp:
return '';
case t.thrid_party:
throw new Error('Not implemented');
break;
default:
throw new Error('Unknown signature type.')
}
}
this.calculateTrailer = function() {
// calculating the trailer
var trailer = '';
trailer += String.fromCharCode(4); // Version
trailer += String.fromCharCode(0xFF);
trailer += util.writeNumber(this.signatureData.length, 4);
return trailer
}
/**
* verifys the signature packet. Note: not signature types are implemented
* @param {String} data data which on the signature applies
* @param {openpgp_msg_privatekey} key the public key to verify the signature
* @return {boolean} True if message is verified, else false.
*/
this.verify = function(key, data) {
var signatureType = enums.write(enums.signature, this.signatureType),
publicKeyAlgorithm = enums.write(enums.publicKey, this.publicKeyAlgorithm),
hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm);
var bytes = this.toSign(signatureType, data),
trailer = this.calculateTrailer();
var mpicount = 0;
// Algorithm-Specific Fields for RSA signatures:
// - multiprecision number (MPI) of RSA signature value m**d mod n.
if (publicKeyAlgorithm > 0 && publicKeyAlgorithm < 4)
mpicount = 1;
// Algorithm-Specific Fields for DSA signatures:
// - MPI of DSA value r.
// - MPI of DSA value s.
else if (publicKeyAlgorithm == 17)
mpicount = 2;
var mpi = [], i = 0;
for (var j = 0; j < mpicount; j++) {
mpi[j] = new type_mpi();
i += mpi[j].read(this.signature.substr(i));
}
this.verified = crypto.signature.verify(publicKeyAlgorithm,
hashAlgorithm, mpi, key.mpi,
bytes + this.signatureData + trailer);
return this.verified;
}
}
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
var util = require('../util'),
crypto = require('../crypto');
/**
* @class
* @classdesc Implementation of the Sym. Encrypted Integrity Protected Data
* Packet (Tag 18)
*
* RFC4880 5.13: The Symmetrically Encrypted Integrity Protected Data packet is
* a variant of the Symmetrically Encrypted Data packet. It is a new feature
* created for OpenPGP that addresses the problem of detecting a modification to
* encrypted data. It is used in combination with a Modification Detection Code
* packet.
*/
module.exports = function packet_sym_encrypted_integrity_protected() {
/** The encrypted payload. */
this.encrypted = null; // string
/** @type {Boolean}
* If after decrypting the packet this is set to true,
* a modification has been detected and thus the contents
* should be discarded.
*/
this.modification = false;
this.packets;
this.read = function(bytes) {
// - A one-octet version number. The only currently defined value is
// 1.
var version = bytes[0].charCodeAt();
if (version != 1) {
throw new Error('Invalid packet version.');
}
// - 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.write = function() {
return String.fromCharCode(1) // Version
+ this.encrypted;
}
this.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;
// Modification detection code packet.
tohash += String.fromCharCode(0xD3);
tohash += String.fromCharCode(0x14);
tohash += crypto.hash.sha1(prefix + tohash);
this.encrypted = crypto.cfb.encrypt(prefixrandom,
sessionKeyAlgorithm, tohash, key, false).substring(0,
prefix.length + tohash.length);
}
/**
* Decrypts the encrypted data contained in this object read_packet must
* have been called before
*
* @param {Integer} sessionKeyAlgorithm
* The selected symmetric encryption algorithm to be used
* @param {String} key The key of cipher blocksize length to be used
* @return {String} The decrypted data of this packet
*/
this.decrypt = function(sessionKeyAlgorithm, key) {
var decrypted = crypto.cfb.decrypt(
sessionKeyAlgorithm, key, this.encrypted, false);
// there must be a modification detection code packet as the
// last packet and everything gets hashed except the hash itself
this.hash = crypto.hash.sha1(
crypto.cfb.mdc(sessionKeyAlgorithm, key, this.encrypted)
+ decrypted.substring(0, decrypted.length - 20));
var mdc = decrypted.substr(decrypted.length - 20, 20);
if(this.hash != mdc) {
throw new Error('Modification detected.');
}
else
this.packets.read(decrypted.substr(0, decrypted.length - 22));
}
};
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
var type_s2k = require('../type/s2k.js'),
enums = require('../enums.js'),
crypto = require('../crypto');
/**
* @class
* @classdesc Public-Key Encrypted Session Key Packets (Tag 1)
*
* RFC4880 5.1: A Public-Key Encrypted Session Key packet holds the session key
* used to encrypt a message. Zero or more Public-Key Encrypted Session Key
* packets and/or Symmetric-Key Encrypted Session Key packets may precede a
* Symmetrically Encrypted Data Packet, which holds an encrypted message. The
* message is encrypted with the session key, and the session key is itself
* encrypted and stored in the Encrypted Session Key packet(s). The
* Symmetrically Encrypted Data Packet is preceded by one Public-Key Encrypted
* Session Key packet for each OpenPGP key to which the message is encrypted.
* 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.
*/
module.exports = function packet_sym_encrypted_session_key() {
this.tag = 3;
this.sessionKeyEncryptionAlgorithm = null;
this.sessionKeyAlgorithm = 'aes256';
this.encrypted = null;
this.s2k = new type_s2k();
/**
* Parsing function for a symmetric encrypted session key packet (tag 3).
*
* @param {String} 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
* @return {openpgp_packet_encrypteddata} Object representation
*/
this.read = function(bytes) {
// A one-octet version number. The only currently defined version is 4.
this.version = bytes[0].charCodeAt();
// A one-octet number describing the symmetric algorithm used.
var algo = enums.read(enums.symmetric, bytes[1].charCodeAt());
// A string-to-key (S2K) specifier, length as defined above.
var s2klength = this.s2k.read(bytes.substr(2));
// 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.sessionKeyEncryptionAlgorithm = algo
}
else
this.sessionKeyAlgorithm = algo;
}
this.write = function() {
var algo = this.encrypted == null ?
this.sessionKeyAlgorithm :
this.sessionKeyEncryptionAlgorithm;
var bytes = String.fromCharCode(this.version) +
String.fromCharCode(enums.write(enums.symmetric, algo)) +
this.s2k.write();
if(this.encrypted != null)
bytes += this.encrypted;
return bytes;
}
/**
* Decrypts the session key (only for public key encrypted session key
* packets (tag 1)
*
* @param {openpgp_msg_message} msg
* The message object (with member encryptedData
* @param {openpgp_msg_privatekey} key
* Private key with secMPIs unlocked
* @return {String} The unencrypted session key
*/
this.decrypt = function(passphrase) {
var algo = this.sessionKeyEncryptionAlgorithm != null ?
this.sessionKeyEncryptionAlgorithm :
this.sessionKeyAlgorithm;
var length = crypto.cipher[algo].keySize;
var key = this.s2k.produce_key(passphrase, length);
if(this.encrypted == null) {
this.sessionKey = key;
} else {
var decrypted = crypto.cfb.decrypt(
this.sessionKeyEncryptionAlgorithm, key, this.encrypted, true);
this.sessionKeyAlgorithm = enums.read(enums.symmetric,
decrypted[0].keyCodeAt());
this.sessionKey = decrypted.substr(1);
}
}
this.encrypt = function(passphrase) {
var length = crypto.getKeyLength(this.sessionKeyEncryptionAlgorithm);
var key = this.s2k.produce_key(passphrase, length);
var private_key = String.fromCharCode(
enums.write(enums.symmetric, this.sessionKeyAlgorithm)) +
crypto.getRandomBytes(
crypto.getKeyLength(this.sessionKeyAlgorithm));
this.encrypted = crypto.cfb.encrypt(
crypto.getPrefixRandom(this.sessionKeyEncryptionAlgorithm),
this.sessionKeyEncryptionAlgorithm, key, private_key, true);
}
};
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
var crypto = require('../crypto');
/**
* @class
* @classdesc Implementation of the Symmetrically Encrypted Data Packet (Tag 9)
*
* RFC4880 5.7: The Symmetrically Encrypted Data packet contains data encrypted
* with a symmetric-key algorithm. When it has been decrypted, it contains other
* packets (usually a literal data packet or compressed data packet, but in
* theory other Symmetrically Encrypted Data packets or sequences of packets
* that form whole OpenPGP messages).
*/
module.exports = function packet_symmetrically_encrypted() {
this.encrypted = null;
/** Decrypted packets contained within.
* @type {openpgp_packetlist} */
this.packets;
this.read = function(bytes) {
this.encrypted = bytes;
}
this.write = function() {
return this.encrypted;
}
/**
* Symmetrically decrypt the packet data
*
* @param {Integer} sessionKeyAlgorithm
* Symmetric key algorithm to use // See RFC4880 9.2
* @param {String} key
* Key as string with the corresponding length to the
* algorithm
* @return The decrypted data;
*/
this.decrypt = function(sessionKeyAlgorithm, key) {
var decrypted = crypto.cfb.decrypt(
sessionKeyAlgorithm, key, this.encrypted, true);
this.packets.read(decrypted);
}
this.encrypt = function(algo, key) {
var data = this.packets.write();
this.encrypted = crypto.cfb.encrypt(
crypto.getPrefixRandom(algo), algo, data, key, true);
}
};
module.exports = function packet_trust() {
};
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
/**
* @class
* @classdesc Implementation of the User Attribute Packet (Tag 17)
* The User Attribute packet is a variation of the User ID packet. It
* is capable of storing more types of data than the User ID packet,
* which is limited to text. Like the User ID packet, a User Attribute
* packet may be certified by the key owner ("self-signed") or any other
* key owner who cares to certify it. Except as noted, a User Attribute
* packet may be used anywhere that a User ID packet may be used.
*
* While User Attribute packets are not a required part of the OpenPGP
* standard, implementations SHOULD provide at least enough
* compatibility to properly handle a certification signature on the
* User Attribute packet. A simple way to do this is by treating the
* User Attribute packet as a User ID packet with opaque contents, but
* an implementation may use any method desired.
*/
module.exports = function packet_user_attribute() {
this.tag = 17;
this.attributes = [];
/**
* parsing function for a user attribute packet (tag 17).
* @param {String} input payload of a tag 17 packet
* @param {Integer} position position to start reading from the input string
* @param {Integer} len length of the packet or the remaining length of input at position
* @return {openpgp_packet_encrypteddata} object representation
*/
this.read = function(bytes) {
var i = 0;
while(i < bytes.length) {
var len = openpgp_packet.read_simple_length(bytes);
i += len.offset;
this.attributes.push(bytes.substr(i, len.len));
i += len.len;
}
}
};
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
var util = require('../util');
/**
* @class
* @classdesc Implementation of the User ID Packet (Tag 13)
* A User ID packet consists of UTF-8 text that is intended to represent
* the name and email address of the key holder. By convention, it
* includes an RFC 2822 [RFC2822] mail name-addr, but there are no
* restrictions on its content. The packet length in the header
* specifies the length of the User ID.
*/
module.exports = function packet_userid() {
/** @type {String} A string containing the user id. Usually in the form
* John Doe
*/
this.userid = '';
/**
* Parsing function for a user id packet (tag 13).
* @param {String} input payload of a tag 13 packet
* @param {Integer} position position to start reading from the input string
* @param {Integer} len length of the packet or the remaining length of input
* at position
* @return {openpgp_packet_encrypteddata} object representation
*/
this.read = function(bytes) {
this.userid = util.decode_utf8(bytes);
}
/**
* Creates a string representation of the user id packet
* @param {String} user_id the user id as string ("John Doe > 4) + expbias);
}
/**
* Parsing function for a string-to-key specifier (RFC 4880 3.7).
* @param {String} input Payload of string-to-key specifier
* @return {Integer} Actual length of the object
*/
this.read = function(bytes) {
var i = 0;
this.type = enums.read(enums.s2k, bytes[i++].charCodeAt());
this.algorithm = enums.read(enums.hash, bytes[i++].charCodeAt());
switch (this.type) {
case 'simple':
break;
case 'salted':
this.salt = bytes.substr(i, 8);
i += 8;
break;
case 'iterated':
this.salt = bytes.substr(i, 8);
i += 8;
// Octet 10: count, a one-octet, coded value
this.c = bytes[i++].charCodeAt();
break;
case 'gnu':
if(bytes.substr(i, 3) == "GNU") {
i += 3; // GNU
var gnuExtType = 1000 + bytes[i++].charCodeAt();
if(gnuExtType == 1001) {
this.type = gnuExtType;
// GnuPG extension mode 1001 -- don't write secret key at all
} else {
throw new Error("Unknown s2k gnu protection mode.");
}
} else {
throw new Error("Unknown s2k type.");
}
break;
default:
throw new Error("Unknown s2k type.");
break;
}
return i;
}
/**
* writes an s2k hash based on the inputs.
* @return {String} Produced key of hashAlgorithm hash length
*/
this.write = function() {
var bytes = String.fromCharCode(enums.write(enums.s2k, this.type));
bytes += String.fromCharCode(enums.write(enums.hash, this.algorithm));
switch(this.type) {
case 'simple':
break;
case 'salted':
bytes += this.salt;
break;
case 'iterated':
bytes += this.salt;
bytes += String.fromCharCode(this.c);
break;
};
return bytes;
}
/**
* 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
* hashAlgorithm hash length
*/
this.produce_key = function(passphrase, numBytes) {
passphrase = util.encode_utf8(passphrase);
function round(prefix, s2k) {
var algorithm = enums.write(enums.hash, s2k.algorithm);
switch(s2k.type) {
case 'simple':
return crypto.hash.digest(algorithm, prefix + passphrase);
case 'salted':
return crypto.hash.digest(algorithm,
prefix + s2k.salt + passphrase);
case 'iterated':
var isp = [],
count = s2k.get_count();
data = s2k.salt + passphrase;
while (isp.length * data.length < count)
isp.push(data);
isp = isp.join('');
if (isp.length > count)
isp = isp.substr(0, count);
return crypto.hash.digest(algorithm, prefix + isp);
};
}
var result = '',
prefix = '';
while(result.length <= numBytes) {
result += round(prefix, this);
prefix += String.fromCharCode(0);
}
return result.substr(0, numBytes);
}
}
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
var Util = function() {
this.readNumber = function (bytes) {
var n = 0;
for(var i = 0; i < bytes.length; i++) {
n <<= 8;
n += bytes[i].charCodeAt()
}
return n;
}
this.writeNumber = function(n, bytes) {
var b = '';
for(var i = 0; i < bytes; i++) {
b += String.fromCharCode((n >> (8 * (bytes- i - 1))) & 0xFF);
}
return b;
}
this.readDate = function(bytes) {
var n = this.readNumber(bytes);
var d = new Date();
d.setTime(n * 1000);
return d;
}
this.writeDate = function(time) {
var numeric = Math.round(time.getTime() / 1000);
return this.writeNumber(numeric, 4);
}
this.emailRegEx = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/;
this.debug = false;
this.hexdump = function(str) {
var r=[];
var e=str.length;
var c=0;
var h;
var i = 0;
while(c'
* @param {String} str String of the debug message
* @return {String} An HTML tt entity containing a paragraph with a
* style attribute where the debug message is HTMLencoded in.
*/
this.print_debug = function(str) {
if (this.debug) {
console.log(str);
}
};
/**
* Helper function to print a debug message. Debug
* messages are only printed if
* openpgp.config.debug is set to true. The calling
* Javascript context MUST define
* a "showMessages(text)" function. Line feeds ('\n')
* are automatically converted to HTML line feeds '
'
* Different than print_debug because will call hexstrdump iff necessary.
* @param {String} str String of the debug message
* @return {String} An HTML tt entity containing a paragraph with a
* style attribute where the debug message is HTMLencoded in.
*/
this.print_debug_hexstr_dump = function(str,strToHex) {
if (this.debug) {
str = str + this.hexstrdump(strToHex);
console.log(str);
}
};
/**
* Helper function to print an error message.
* The calling Javascript context MUST define
* a "showMessages(text)" function. Line feeds ('\n')
* are automatically converted to HTML line feeds '
'
* @param {String} str String of the error message
* @return {String} A HTML paragraph entity with a style attribute
* containing the HTML encoded error message
*/
this.print_error = function(str) {
if(this.debug)
throw str;
console.log(str);
};
/**
* Helper function to print an info message.
* The calling Javascript context MUST define
* a "showMessages(text)" function. Line feeds ('\n')
* are automatically converted to HTML line feeds '
'.
* @param {String} str String of the info message
* @return {String} A HTML paragraph entity with a style attribute
* containing the HTML encoded info message
*/
this.print_info = function(str) {
if(this.debug)
console.log(str);
};
this.print_warning = function(str) {
console.log(str);
};
this.getLeftNBits = function (string, bitcount) {
var rest = bitcount % 8;
if (rest == 0)
return string.substring(0, bitcount / 8);
var bytes = (bitcount - rest) / 8 +1;
var result = string.substring(0, bytes);
return this.shiftRight(result, 8-rest); // +String.fromCharCode(string.charCodeAt(bytes -1) << (8-rest) & 0xFF);
};
/**
* Shifting a string to n bits right
* @param {String} value The string to shift
* @param {Integer} bitcount Amount of bits to shift (MUST be smaller
* than 9)
* @return {String} Resulting string.
*/
this.shiftRight = function(value, bitcount) {
var temp = util.str2bin(value);
if (bitcount % 8 != 0) {
for (var i = temp.length-1; i >= 0; i--) {
temp[i] >>= bitcount % 8;
if (i > 0)
temp[i] |= (temp[i - 1] << (8 - (bitcount % 8))) & 0xFF;
}
} else {
return value;
}
return util.bin2str(temp);
};
/**
* Return the algorithm type as string
* @return {String} String representing the message type
*/
this.get_hashAlgorithmString = function(algo) {
switch(algo) {
case 1:
return "MD5";
case 2:
return "SHA1";
case 3:
return "RIPEMD160";
case 8:
return "SHA256";
case 9:
return "SHA384";
case 10:
return "SHA512";
case 11:
return "SHA224";
}
return "unknown";
};
};
/**
* an instance that should be used.
*/
module.exports = new Util();