remove old files
This commit is contained in:
parent
3d1575bb85
commit
3d67721fb5
|
@ -1,720 +0,0 @@
|
|||
/*
|
||||
* 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))<<this.DB)|this[0];
|
||||
}
|
||||
|
||||
// (public) return value as byte
|
||||
function bnByteValue() { return (this.t==0)?this.s:(this[0]<<24)>>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<<t)-1); else x[0] = 0;
|
||||
this.fromString(x,256);
|
||||
}
|
||||
}
|
||||
|
||||
// (public) convert to bigendian byte array
|
||||
function bnToByteArray() {
|
||||
var i = this.t, r = new Array();
|
||||
r[0] = this.s;
|
||||
var p = this.DB-(i*this.DB)%8, d, k = 0;
|
||||
if(i-- > 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)-1))<<(8-p);
|
||||
d |= this[--i]>>(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<<n)
|
||||
function bnpChangeBit(n,op) {
|
||||
var r = BigInteger.ONE.shiftLeft(n);
|
||||
this.bitwiseTo(r,op,r);
|
||||
return r;
|
||||
}
|
||||
|
||||
// (public) this | (1<<n)
|
||||
function bnSetBit(n) { return this.changeBit(n,op_or); }
|
||||
|
||||
// (public) this & ~(1<<n)
|
||||
function bnClearBit(n) { return this.changeBit(n,op_andnot); }
|
||||
|
||||
// (public) this ^ (1<<n)
|
||||
function bnFlipBit(n) { return this.changeBit(n,op_xor); }
|
||||
|
||||
// (protected) r = this + a
|
||||
function bnpAddTo(a,r) {
|
||||
var i = 0, c = 0, m = Math.min(a.t,this.t);
|
||||
while(i < m) {
|
||||
c += this[i]+a[i];
|
||||
r[i++] = c&this.DM;
|
||||
c >>= 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<<k)-1;
|
||||
g[1] = z.convert(this);
|
||||
if(k > 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<<i)) == 0) {
|
||||
z.sqrTo(r,r2); t = r; r = r2; r2 = t;
|
||||
if(--i < 0) { i = this.DB-1; --j; }
|
||||
}
|
||||
}
|
||||
return z.revert(r);
|
||||
}
|
||||
|
||||
// (public) gcd(this,a) (HAC 14.54)
|
||||
function bnGCD(a) {
|
||||
var x = (this.s<0)?this.negate():this.clone();
|
||||
var y = (a.s<0)?a.negate():a.clone();
|
||||
if(x.compareTo(y) < 0) { var t = x; x = y; y = t; }
|
||||
var i = x.getLowestSetBit(), g = y.getLowestSetBit();
|
||||
if(g < 0) return x;
|
||||
if(i < g) g = i;
|
||||
if(g > 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();
|
||||
var j, bases = [];
|
||||
for(var i = 0; i < t; ++i) {
|
||||
//Pick bases at random, instead of starting at 2
|
||||
for (;;) {
|
||||
j = lowprimes[Math.floor(Math.random() * lowprimes.length)];
|
||||
if (bases.indexOf(j) == -1) break;
|
||||
}
|
||||
bases.push(j);
|
||||
a.fromInt(j);
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
|
@ -1,431 +0,0 @@
|
|||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
// The GPG4Browsers crypto interface
|
||||
|
||||
/**
|
||||
* Encrypts data using the specified public key multiprecision integers
|
||||
* and the specified algorithm.
|
||||
* @param {Integer} algo Algorithm to be used (See RFC4880 9.1)
|
||||
* @param {openpgp_type_mpi[]} publicMPIs Algorithm dependent multiprecision integers
|
||||
* @param {openpgp_type_mpi} data Data to be encrypted as MPI
|
||||
* @return {(openpgp_type_mpi|openpgp_type_mpi[])} if RSA an openpgp_type_mpi;
|
||||
* if elgamal encryption an array of two openpgp_type_mpi is returned; otherwise null
|
||||
*/
|
||||
function openpgp_crypto_asymetricEncrypt(algo, publicMPIs, 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 RSA();
|
||||
var n = publicMPIs[0].toBigInteger();
|
||||
var e = publicMPIs[1].toBigInteger();
|
||||
var m = data.toBigInteger();
|
||||
return rsa.encrypt(m,e,n).toMPI();
|
||||
case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
|
||||
var elgamal = new Elgamal();
|
||||
var p = publicMPIs[0].toBigInteger();
|
||||
var g = publicMPIs[1].toBigInteger();
|
||||
var y = publicMPIs[2].toBigInteger();
|
||||
var m = data.toBigInteger();
|
||||
return elgamal.encrypt(m,g,p,y);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts data using the specified public key multiprecision integers of the private key,
|
||||
* the specified secretMPIs of the private key and the specified algorithm.
|
||||
* @param {Integer} algo Algorithm to be used (See RFC4880 9.1)
|
||||
* @param {openpgp_type_mpi[]} publicMPIs Algorithm dependent multiprecision integers
|
||||
* of the public key part of the private key
|
||||
* @param {openpgp_type_mpi[]} secretMPIs Algorithm dependent multiprecision integers
|
||||
* of the private key used
|
||||
* @param {openpgp_type_mpi} data Data to be encrypted as MPI
|
||||
* @return {BigInteger} returns a big integer containing the decrypted data; otherwise null
|
||||
*/
|
||||
|
||||
function openpgp_crypto_asymetricDecrypt(algo, publicMPIs, secretMPIs, dataMPIs) {
|
||||
switch(algo) {
|
||||
case 1: // RSA (Encrypt or Sign) [HAC]
|
||||
case 2: // RSA Encrypt-Only [HAC]
|
||||
case 3: // RSA Sign-Only [HAC]
|
||||
var rsa = new RSA();
|
||||
var d = secretMPIs[0].toBigInteger();
|
||||
var p = secretMPIs[1].toBigInteger();
|
||||
var q = secretMPIs[2].toBigInteger();
|
||||
var u = secretMPIs[3].toBigInteger();
|
||||
var m = dataMPIs[0].toBigInteger();
|
||||
return rsa.decrypt(m, d, p, q, u);
|
||||
case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
|
||||
var elgamal = new Elgamal();
|
||||
var x = secretMPIs[0].toBigInteger();
|
||||
var c1 = dataMPIs[0].toBigInteger();
|
||||
var c2 = dataMPIs[1].toBigInteger();
|
||||
var p = publicMPIs[0].toBigInteger();
|
||||
return elgamal.decrypt(c1,c2,p,x);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* generate random byte prefix as string for the specified algorithm
|
||||
* @param {Integer} algo Algorithm to use (see RFC4880 9.2)
|
||||
* @return {String} Random bytes with length equal to the block
|
||||
* size of the cipher
|
||||
*/
|
||||
function openpgp_crypto_getPrefixRandom(algo) {
|
||||
switch(algo) {
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
return openpgp_crypto_getRandomBytes(8);
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
return openpgp_crypto_getRandomBytes(16);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieve the MDC prefixed bytes by decrypting them
|
||||
* @param {Integer} algo Algorithm to use (see RFC4880 9.2)
|
||||
* @param {String} key Key as string. length is depending on the algorithm used
|
||||
* @param {String} data Encrypted data where the prefix is decrypted from
|
||||
* @return {String} Plain text data of the prefixed data
|
||||
*/
|
||||
function openpgp_crypto_MDCSystemBytes(algo, key, data) {
|
||||
util.print_debug_hexstr_dump("openpgp_crypto_symmetricDecrypt:\nencrypteddata:",data);
|
||||
switch(algo) {
|
||||
case 0: // Plaintext or unencrypted data
|
||||
return data;
|
||||
case 2: // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
|
||||
return openpgp_cfb_mdc(desede, 8, key, data, openpgp_cfb);
|
||||
case 3: // CAST5 (128 bit key, as per [RFC2144])
|
||||
return openpgp_cfb_mdc(cast5_encrypt, 8, key, data);
|
||||
case 4: // Blowfish (128 bit key, 16 rounds) [BLOWFISH]
|
||||
return openpgp_cfb_mdc(BFencrypt, 8, key, data);
|
||||
case 7: // AES with 128-bit key [AES]
|
||||
case 8: // AES with 192-bit key
|
||||
case 9: // AES with 256-bit key
|
||||
return openpgp_cfb_mdc(AESencrypt, 16, keyExpansion(key), data);
|
||||
case 10:
|
||||
return openpgp_cfb_mdc(TFencrypt, 16, key, data);
|
||||
case 1: // IDEA [IDEA]
|
||||
util.print_error(""+ (algo == 1 ? "IDEA Algorithm not implemented" : "Twofish Algorithm not implemented"));
|
||||
return null;
|
||||
default:
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Generating a session key for the specified symmetric algorithm
|
||||
* @param {Integer} algo Algorithm to use (see RFC4880 9.2)
|
||||
* @return {String} Random bytes as a string to be used as a key
|
||||
*/
|
||||
function openpgp_crypto_generateSessionKey(algo) {
|
||||
switch (algo) {
|
||||
case 2: // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
|
||||
case 8: // AES with 192-bit key
|
||||
return openpgp_crypto_getRandomBytes(24);
|
||||
case 3: // CAST5 (128 bit key, as per [RFC2144])
|
||||
case 4: // Blowfish (128 bit key, 16 rounds) [BLOWFISH]
|
||||
case 7: // AES with 128-bit key [AES]
|
||||
util.print_debug("length = 16:\n"+util.hexstrdump(openpgp_crypto_getRandomBytes(16)));
|
||||
return openpgp_crypto_getRandomBytes(16);
|
||||
case 9: // AES with 256-bit key
|
||||
case 10:// Twofish with 256-bit key [TWOFISH]
|
||||
return openpgp_crypto_getRandomBytes(32);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @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)
|
||||
*/
|
||||
function openpgp_crypto_verifySignature(algo, hash_algo, msg_MPIs, publickey_MPIs, data) {
|
||||
var calc_hash = openpgp_crypto_hashData(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 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 = openpgp_encoding_emsa_pkcs1_decode(hash_algo,dopublic.toMPI().substring(2));
|
||||
if (hash == -1) {
|
||||
util.print_error("PKCS1 padding in message or key incorrect. Aborting...");
|
||||
return false;
|
||||
}
|
||||
util.print_debug('hash: '+util.hexdump(hash));
|
||||
util.print_debug('calc_hash: '+util.hexdump(calc_hash));
|
||||
return hash == calc_hash;
|
||||
|
||||
case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
|
||||
util.print_error("signing with Elgamal is not defined in the OpenPGP standard.");
|
||||
return null;
|
||||
case 17: // DSA (Digital Signature Algorithm) [FIPS186] [HAC]
|
||||
var dsa = new 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:
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {(String|openpgp_type_mpi)}
|
||||
*/
|
||||
function openpgp_crypto_signData(hash_algo, algo, publicMPIs, secretMPIs, 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 RSA();
|
||||
var d = secretMPIs[0].toBigInteger();
|
||||
var n = publicMPIs[0].toBigInteger();
|
||||
var m = openpgp_encoding_emsa_pkcs1_encode(hash_algo, data,publicMPIs[0].mpiByteLength);
|
||||
util.print_debug("signing using RSA");
|
||||
return rsa.sign(m, d, n).toMPI();
|
||||
case 17: // DSA (Digital Signature Algorithm) [FIPS186] [HAC]
|
||||
var dsa = new DSA();
|
||||
util.print_debug("DSA Sign: q size in Bytes:"+publicMPIs[1].getByteLength());
|
||||
var p = publicMPIs[0].toBigInteger();
|
||||
var q = publicMPIs[1].toBigInteger();
|
||||
var g = publicMPIs[2].toBigInteger();
|
||||
var y = publicMPIs[3].toBigInteger();
|
||||
var x = secretMPIs[0].toBigInteger();
|
||||
var m = data;
|
||||
var result = dsa.sign(hash_algo,m, g, p, q, x);
|
||||
util.print_debug("signing using DSA\n result:"+util.hexstrdump(result[0])+"|"+util.hexstrdump(result[1]));
|
||||
return result[0]+result[1];
|
||||
case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
|
||||
util.print_debug("signing with Elgamal is not defined in the OpenPGP standard.");
|
||||
return null;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a hash on the specified data using the specified algorithm
|
||||
* @param {Integer} algo Hash algorithm type (see RFC4880 9.4)
|
||||
* @param {String} data Data to be hashed
|
||||
* @return {String} hash value
|
||||
*/
|
||||
function openpgp_crypto_hashData(algo, data) {
|
||||
var hash = null;
|
||||
switch(algo) {
|
||||
case 1: // - MD5 [HAC]
|
||||
hash = MD5(data);
|
||||
break;
|
||||
case 2: // - SHA-1 [FIPS180]
|
||||
hash = str_sha1(data);
|
||||
break;
|
||||
case 3: // - RIPE-MD/160 [HAC]
|
||||
hash = RMDstring(data);
|
||||
break;
|
||||
case 8: // - SHA256 [FIPS180]
|
||||
hash = str_sha256(data);
|
||||
break;
|
||||
case 9: // - SHA384 [FIPS180]
|
||||
hash = str_sha384(data);
|
||||
break;
|
||||
case 10:// - SHA512 [FIPS180]
|
||||
hash = str_sha512(data);
|
||||
break;
|
||||
case 11:// - SHA224 [FIPS180]
|
||||
hash = str_sha224(data);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash size in bytes of the specified hash algorithm type
|
||||
* @param {Integer} algo Hash algorithm type (See RFC4880 9.4)
|
||||
* @return {Integer} Size in bytes of the resulting hash
|
||||
*/
|
||||
function openpgp_crypto_getHashByteLength(algo) {
|
||||
var hash = null;
|
||||
switch(algo) {
|
||||
case 1: // - MD5 [HAC]
|
||||
return 16;
|
||||
case 2: // - SHA-1 [FIPS180]
|
||||
case 3: // - RIPE-MD/160 [HAC]
|
||||
return 20;
|
||||
case 8: // - SHA256 [FIPS180]
|
||||
return 32;
|
||||
case 9: // - SHA384 [FIPS180]
|
||||
return 48
|
||||
case 10:// - SHA512 [FIPS180]
|
||||
return 64;
|
||||
case 11:// - SHA224 [FIPS180]
|
||||
return 28;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve secure random byte string of the specified length
|
||||
* @param {Integer} length Length in bytes to generate
|
||||
* @return {String} Random byte string
|
||||
*/
|
||||
function openpgp_crypto_getRandomBytes(length) {
|
||||
var result = '';
|
||||
for (var i = 0; i < length; i++) {
|
||||
result += String.fromCharCode(openpgp_crypto_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
|
||||
*/
|
||||
function openpgp_crypto_getPseudoRandom(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
|
||||
*/
|
||||
function openpgp_crypto_getSecureRandom(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)));
|
||||
}
|
||||
|
||||
function openpgp_crypto_getSecureRandomOctet() {
|
||||
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
|
||||
*/
|
||||
function openpgp_crypto_getRandomBigInteger(bits) {
|
||||
if (bits < 0)
|
||||
return null;
|
||||
var numBytes = Math.floor((bits+7)/8);
|
||||
|
||||
var randomBits = openpgp_crypto_getRandomBytes(numBytes);
|
||||
if (bits % 8 > 0) {
|
||||
|
||||
randomBits = String.fromCharCode(
|
||||
(Math.pow(2,bits % 8)-1) &
|
||||
randomBits.charCodeAt(0)) +
|
||||
randomBits.substring(1);
|
||||
}
|
||||
return new openpgp_type_mpi().create(randomBits).toBigInteger();
|
||||
}
|
||||
|
||||
function openpgp_crypto_getRandomBigIntegerInRange(min, max) {
|
||||
if (max.compareTo(min) <= 0)
|
||||
return;
|
||||
var range = max.subtract(min);
|
||||
var r = openpgp_crypto_getRandomBigInteger(range.bitLength());
|
||||
while (r > range) {
|
||||
r = openpgp_crypto_getRandomBigInteger(range.bitLength());
|
||||
}
|
||||
return min.add(r);
|
||||
}
|
||||
|
||||
|
||||
//This is a test method to ensure that encryption/decryption with a given 1024bit RSAKey object functions as intended
|
||||
function openpgp_crypto_testRSA(key){
|
||||
var rsa = new RSA();
|
||||
var mpi = new openpgp_type_mpi();
|
||||
mpi.create(openpgp_encoding_eme_pkcs1_encode('ABABABAB', 128));
|
||||
var msg = rsa.encrypt(mpi.toBigInteger(),key.ee,key.n);
|
||||
var result = rsa.decrypt(msg, key.d, key.p, key.q, key.u);
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} openpgp_keypair
|
||||
* @property {openpgp_packet_keymaterial} privateKey
|
||||
* @property {openpgp_packet_keymaterial} publicKey
|
||||
*/
|
||||
|
||||
/**
|
||||
* Calls the necessary crypto functions to generate a keypair.
|
||||
* Called directly by openpgp.js
|
||||
* @param {Integer} keyType Follows OpenPGP algorithm convention.
|
||||
* @param {Integer} numBits Number of bits to make the key to be generated
|
||||
* @return {openpgp_keypair}
|
||||
*/
|
||||
function openpgp_crypto_generateKeyPair(keyType, numBits, passphrase, s2kHash, symmetricEncryptionAlgorithm){
|
||||
var privKeyPacket;
|
||||
var publicKeyPacket;
|
||||
var d = new Date();
|
||||
d = d.getTime()/1000;
|
||||
var timePacket = String.fromCharCode(Math.floor(d/0x1000000%0x100)) + String.fromCharCode(Math.floor(d/0x10000%0x100)) + String.fromCharCode(Math.floor(d/0x100%0x100)) + String.fromCharCode(Math.floor(d%0x100));
|
||||
switch(keyType){
|
||||
case 1:
|
||||
var rsa = new RSA();
|
||||
var key = rsa.generate(numBits,"10001");
|
||||
privKeyPacket = new openpgp_packet_keymaterial().write_private_key(keyType, key, passphrase, s2kHash, symmetricEncryptionAlgorithm, timePacket);
|
||||
publicKeyPacket = new openpgp_packet_keymaterial().write_public_key(keyType, key, timePacket);
|
||||
break;
|
||||
default:
|
||||
util.print_error("Unknown keytype "+keyType)
|
||||
}
|
||||
return {privateKey: privKeyPacket, publicKey: publicKeyPacket};
|
||||
}
|
|
@ -1,243 +0,0 @@
|
|||
//Paul Tero, July 2001
|
||||
//http://www.tero.co.uk/des/
|
||||
//
|
||||
//Optimised for performance with large blocks by Michael Hayworth, November 2001
|
||||
//http://www.netdealing.com
|
||||
//
|
||||
// Modified by Recurity Labs GmbH
|
||||
|
||||
//THIS SOFTWARE IS PROVIDED "AS IS" AND
|
||||
//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
//IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
//ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
//FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
//DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
//OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
//HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
//OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
//SUCH DAMAGE.
|
||||
|
||||
//des
|
||||
//this takes the key, the message, and whether to encrypt or decrypt
|
||||
|
||||
// added by Recurity Labs
|
||||
function desede(block,key) {
|
||||
var key1 = key.substring(0,8);
|
||||
var key2 = key.substring(8,16);
|
||||
var key3 = key.substring(16,24);
|
||||
return util.str2bin(des(des_createKeys(key3),des(des_createKeys(key2),des(des_createKeys(key1),util.bin2str(block), true, 0,null,null), false, 0,null,null), true, 0,null,null));
|
||||
}
|
||||
|
||||
|
||||
function des (keys, message, encrypt, mode, iv, padding) {
|
||||
//declaring this locally speeds things up a bit
|
||||
var spfunction1 = new Array (0x1010400,0,0x10000,0x1010404,0x1010004,0x10404,0x4,0x10000,0x400,0x1010400,0x1010404,0x400,0x1000404,0x1010004,0x1000000,0x4,0x404,0x1000400,0x1000400,0x10400,0x10400,0x1010000,0x1010000,0x1000404,0x10004,0x1000004,0x1000004,0x10004,0,0x404,0x10404,0x1000000,0x10000,0x1010404,0x4,0x1010000,0x1010400,0x1000000,0x1000000,0x400,0x1010004,0x10000,0x10400,0x1000004,0x400,0x4,0x1000404,0x10404,0x1010404,0x10004,0x1010000,0x1000404,0x1000004,0x404,0x10404,0x1010400,0x404,0x1000400,0x1000400,0,0x10004,0x10400,0,0x1010004);
|
||||
var spfunction2 = new Array (-0x7fef7fe0,-0x7fff8000,0x8000,0x108020,0x100000,0x20,-0x7fefffe0,-0x7fff7fe0,-0x7fffffe0,-0x7fef7fe0,-0x7fef8000,-0x80000000,-0x7fff8000,0x100000,0x20,-0x7fefffe0,0x108000,0x100020,-0x7fff7fe0,0,-0x80000000,0x8000,0x108020,-0x7ff00000,0x100020,-0x7fffffe0,0,0x108000,0x8020,-0x7fef8000,-0x7ff00000,0x8020,0,0x108020,-0x7fefffe0,0x100000,-0x7fff7fe0,-0x7ff00000,-0x7fef8000,0x8000,-0x7ff00000,-0x7fff8000,0x20,-0x7fef7fe0,0x108020,0x20,0x8000,-0x80000000,0x8020,-0x7fef8000,0x100000,-0x7fffffe0,0x100020,-0x7fff7fe0,-0x7fffffe0,0x100020,0x108000,0,-0x7fff8000,0x8020,-0x80000000,-0x7fefffe0,-0x7fef7fe0,0x108000);
|
||||
var spfunction3 = new Array (0x208,0x8020200,0,0x8020008,0x8000200,0,0x20208,0x8000200,0x20008,0x8000008,0x8000008,0x20000,0x8020208,0x20008,0x8020000,0x208,0x8000000,0x8,0x8020200,0x200,0x20200,0x8020000,0x8020008,0x20208,0x8000208,0x20200,0x20000,0x8000208,0x8,0x8020208,0x200,0x8000000,0x8020200,0x8000000,0x20008,0x208,0x20000,0x8020200,0x8000200,0,0x200,0x20008,0x8020208,0x8000200,0x8000008,0x200,0,0x8020008,0x8000208,0x20000,0x8000000,0x8020208,0x8,0x20208,0x20200,0x8000008,0x8020000,0x8000208,0x208,0x8020000,0x20208,0x8,0x8020008,0x20200);
|
||||
var spfunction4 = new Array (0x802001,0x2081,0x2081,0x80,0x802080,0x800081,0x800001,0x2001,0,0x802000,0x802000,0x802081,0x81,0,0x800080,0x800001,0x1,0x2000,0x800000,0x802001,0x80,0x800000,0x2001,0x2080,0x800081,0x1,0x2080,0x800080,0x2000,0x802080,0x802081,0x81,0x800080,0x800001,0x802000,0x802081,0x81,0,0,0x802000,0x2080,0x800080,0x800081,0x1,0x802001,0x2081,0x2081,0x80,0x802081,0x81,0x1,0x2000,0x800001,0x2001,0x802080,0x800081,0x2001,0x2080,0x800000,0x802001,0x80,0x800000,0x2000,0x802080);
|
||||
var spfunction5 = new Array (0x100,0x2080100,0x2080000,0x42000100,0x80000,0x100,0x40000000,0x2080000,0x40080100,0x80000,0x2000100,0x40080100,0x42000100,0x42080000,0x80100,0x40000000,0x2000000,0x40080000,0x40080000,0,0x40000100,0x42080100,0x42080100,0x2000100,0x42080000,0x40000100,0,0x42000000,0x2080100,0x2000000,0x42000000,0x80100,0x80000,0x42000100,0x100,0x2000000,0x40000000,0x2080000,0x42000100,0x40080100,0x2000100,0x40000000,0x42080000,0x2080100,0x40080100,0x100,0x2000000,0x42080000,0x42080100,0x80100,0x42000000,0x42080100,0x2080000,0,0x40080000,0x42000000,0x80100,0x2000100,0x40000100,0x80000,0,0x40080000,0x2080100,0x40000100);
|
||||
var spfunction6 = new Array (0x20000010,0x20400000,0x4000,0x20404010,0x20400000,0x10,0x20404010,0x400000,0x20004000,0x404010,0x400000,0x20000010,0x400010,0x20004000,0x20000000,0x4010,0,0x400010,0x20004010,0x4000,0x404000,0x20004010,0x10,0x20400010,0x20400010,0,0x404010,0x20404000,0x4010,0x404000,0x20404000,0x20000000,0x20004000,0x10,0x20400010,0x404000,0x20404010,0x400000,0x4010,0x20000010,0x400000,0x20004000,0x20000000,0x4010,0x20000010,0x20404010,0x404000,0x20400000,0x404010,0x20404000,0,0x20400010,0x10,0x4000,0x20400000,0x404010,0x4000,0x400010,0x20004010,0,0x20404000,0x20000000,0x400010,0x20004010);
|
||||
var spfunction7 = new Array (0x200000,0x4200002,0x4000802,0,0x800,0x4000802,0x200802,0x4200800,0x4200802,0x200000,0,0x4000002,0x2,0x4000000,0x4200002,0x802,0x4000800,0x200802,0x200002,0x4000800,0x4000002,0x4200000,0x4200800,0x200002,0x4200000,0x800,0x802,0x4200802,0x200800,0x2,0x4000000,0x200800,0x4000000,0x200800,0x200000,0x4000802,0x4000802,0x4200002,0x4200002,0x2,0x200002,0x4000000,0x4000800,0x200000,0x4200800,0x802,0x200802,0x4200800,0x802,0x4000002,0x4200802,0x4200000,0x200800,0,0x2,0x4200802,0,0x200802,0x4200000,0x800,0x4000002,0x4000800,0x800,0x200002);
|
||||
var spfunction8 = new Array (0x10001040,0x1000,0x40000,0x10041040,0x10000000,0x10001040,0x40,0x10000000,0x40040,0x10040000,0x10041040,0x41000,0x10041000,0x41040,0x1000,0x40,0x10040000,0x10000040,0x10001000,0x1040,0x41000,0x40040,0x10040040,0x10041000,0x1040,0,0,0x10040040,0x10000040,0x10001000,0x41040,0x40000,0x41040,0x40000,0x10041000,0x1000,0x40,0x10040040,0x1000,0x41040,0x10001000,0x40,0x10000040,0x10040000,0x10040040,0x10000000,0x40000,0x10001040,0,0x10041040,0x40040,0x10000040,0x10040000,0x10001000,0x10001040,0,0x10041040,0x41000,0x41000,0x1040,0x1040,0x40040,0x10000000,0x10041000);
|
||||
|
||||
//create the 16 or 48 subkeys we will need
|
||||
var m=0, i, j, temp, temp2, right1, right2, left, right, looping;
|
||||
var cbcleft, cbcleft2, cbcright, cbcright2
|
||||
var endloop, loopinc;
|
||||
var len = message.length;
|
||||
var chunk = 0;
|
||||
//set up the loops for single and triple des
|
||||
var iterations = keys.length == 32 ? 3 : 9; //single or triple des
|
||||
if (iterations == 3) {looping = encrypt ? new Array (0, 32, 2) : new Array (30, -2, -2);}
|
||||
else {looping = encrypt ? new Array (0, 32, 2, 62, 30, -2, 64, 96, 2) : new Array (94, 62, -2, 32, 64, 2, 30, -2, -2);}
|
||||
|
||||
//pad the message depending on the padding parameter
|
||||
//only add padding if encrypting - note that you need to use the same padding option for both encrypt and decrypt
|
||||
if (encrypt) {
|
||||
message = des_addPadding(message, padding);
|
||||
len = message.length;
|
||||
}
|
||||
|
||||
//store the result here
|
||||
result = "";
|
||||
tempresult = "";
|
||||
|
||||
if (mode == 1) { //CBC mode
|
||||
cbcleft = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++);
|
||||
cbcright = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++);
|
||||
m=0;
|
||||
}
|
||||
|
||||
//loop through each 64 bit chunk of the message
|
||||
while (m < len) {
|
||||
left = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) | message.charCodeAt(m++);
|
||||
right = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) | message.charCodeAt(m++);
|
||||
|
||||
//for Cipher Block Chaining mode, xor the message with the previous result
|
||||
if (mode == 1) {if (encrypt) {left ^= cbcleft; right ^= cbcright;} else {cbcleft2 = cbcleft; cbcright2 = cbcright; cbcleft = left; cbcright = right;}}
|
||||
|
||||
//first each 64 but chunk of the message must be permuted according to IP
|
||||
temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4);
|
||||
temp = ((left >>> 16) ^ right) & 0x0000ffff; right ^= temp; left ^= (temp << 16);
|
||||
temp = ((right >>> 2) ^ left) & 0x33333333; left ^= temp; right ^= (temp << 2);
|
||||
temp = ((right >>> 8) ^ left) & 0x00ff00ff; left ^= temp; right ^= (temp << 8);
|
||||
temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1);
|
||||
|
||||
left = ((left << 1) | (left >>> 31));
|
||||
right = ((right << 1) | (right >>> 31));
|
||||
|
||||
//do this either 1 or 3 times for each chunk of the message
|
||||
for (j=0; j<iterations; j+=3) {
|
||||
endloop = looping[j+1];
|
||||
loopinc = looping[j+2];
|
||||
//now go through and perform the encryption or decryption
|
||||
for (i=looping[j]; i!=endloop; i+=loopinc) { //for efficiency
|
||||
right1 = right ^ keys[i];
|
||||
right2 = ((right >>> 4) | (right << 28)) ^ keys[i+1];
|
||||
//the result is attained by passing these bytes through the S selection functions
|
||||
temp = left;
|
||||
left = right;
|
||||
right = temp ^ (spfunction2[(right1 >>> 24) & 0x3f] | spfunction4[(right1 >>> 16) & 0x3f]
|
||||
| spfunction6[(right1 >>> 8) & 0x3f] | spfunction8[right1 & 0x3f]
|
||||
| spfunction1[(right2 >>> 24) & 0x3f] | spfunction3[(right2 >>> 16) & 0x3f]
|
||||
| spfunction5[(right2 >>> 8) & 0x3f] | spfunction7[right2 & 0x3f]);
|
||||
}
|
||||
temp = left; left = right; right = temp; //unreverse left and right
|
||||
} //for either 1 or 3 iterations
|
||||
|
||||
//move then each one bit to the right
|
||||
left = ((left >>> 1) | (left << 31));
|
||||
right = ((right >>> 1) | (right << 31));
|
||||
|
||||
//now perform IP-1, which is IP in the opposite direction
|
||||
temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1);
|
||||
temp = ((right >>> 8) ^ left) & 0x00ff00ff; left ^= temp; right ^= (temp << 8);
|
||||
temp = ((right >>> 2) ^ left) & 0x33333333; left ^= temp; right ^= (temp << 2);
|
||||
temp = ((left >>> 16) ^ right) & 0x0000ffff; right ^= temp; left ^= (temp << 16);
|
||||
temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4);
|
||||
|
||||
//for Cipher Block Chaining mode, xor the message with the previous result
|
||||
if (mode == 1) {if (encrypt) {cbcleft = left; cbcright = right;} else {left ^= cbcleft2; right ^= cbcright2;}}
|
||||
tempresult += String.fromCharCode ((left>>>24), ((left>>>16) & 0xff), ((left>>>8) & 0xff), (left & 0xff), (right>>>24), ((right>>>16) & 0xff), ((right>>>8) & 0xff), (right & 0xff));
|
||||
|
||||
chunk += 8;
|
||||
if (chunk == 512) {result += tempresult; tempresult = ""; chunk = 0;}
|
||||
} //for every 8 characters, or 64 bits in the message
|
||||
|
||||
//return the result as an array
|
||||
result += tempresult;
|
||||
|
||||
//only remove padding if decrypting - note that you need to use the same padding option for both encrypt and decrypt
|
||||
if (!encrypt) {
|
||||
result = des_removePadding(result, padding);
|
||||
}
|
||||
|
||||
return result;
|
||||
} //end of des
|
||||
|
||||
|
||||
|
||||
//des_createKeys
|
||||
//this takes as input a 64 bit key (even though only 56 bits are used)
|
||||
//as an array of 2 integers, and returns 16 48 bit keys
|
||||
function des_createKeys (key) {
|
||||
//declaring this locally speeds things up a bit
|
||||
pc2bytes0 = new Array (0,0x4,0x20000000,0x20000004,0x10000,0x10004,0x20010000,0x20010004,0x200,0x204,0x20000200,0x20000204,0x10200,0x10204,0x20010200,0x20010204);
|
||||
pc2bytes1 = new Array (0,0x1,0x100000,0x100001,0x4000000,0x4000001,0x4100000,0x4100001,0x100,0x101,0x100100,0x100101,0x4000100,0x4000101,0x4100100,0x4100101);
|
||||
pc2bytes2 = new Array (0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808,0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808);
|
||||
pc2bytes3 = new Array (0,0x200000,0x8000000,0x8200000,0x2000,0x202000,0x8002000,0x8202000,0x20000,0x220000,0x8020000,0x8220000,0x22000,0x222000,0x8022000,0x8222000);
|
||||
pc2bytes4 = new Array (0,0x40000,0x10,0x40010,0,0x40000,0x10,0x40010,0x1000,0x41000,0x1010,0x41010,0x1000,0x41000,0x1010,0x41010);
|
||||
pc2bytes5 = new Array (0,0x400,0x20,0x420,0,0x400,0x20,0x420,0x2000000,0x2000400,0x2000020,0x2000420,0x2000000,0x2000400,0x2000020,0x2000420);
|
||||
pc2bytes6 = new Array (0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002,0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002);
|
||||
pc2bytes7 = new Array (0,0x10000,0x800,0x10800,0x20000000,0x20010000,0x20000800,0x20010800,0x20000,0x30000,0x20800,0x30800,0x20020000,0x20030000,0x20020800,0x20030800);
|
||||
pc2bytes8 = new Array (0,0x40000,0,0x40000,0x2,0x40002,0x2,0x40002,0x2000000,0x2040000,0x2000000,0x2040000,0x2000002,0x2040002,0x2000002,0x2040002);
|
||||
pc2bytes9 = new Array (0,0x10000000,0x8,0x10000008,0,0x10000000,0x8,0x10000008,0x400,0x10000400,0x408,0x10000408,0x400,0x10000400,0x408,0x10000408);
|
||||
pc2bytes10 = new Array (0,0x20,0,0x20,0x100000,0x100020,0x100000,0x100020,0x2000,0x2020,0x2000,0x2020,0x102000,0x102020,0x102000,0x102020);
|
||||
pc2bytes11 = new Array (0,0x1000000,0x200,0x1000200,0x200000,0x1200000,0x200200,0x1200200,0x4000000,0x5000000,0x4000200,0x5000200,0x4200000,0x5200000,0x4200200,0x5200200);
|
||||
pc2bytes12 = new Array (0,0x1000,0x8000000,0x8001000,0x80000,0x81000,0x8080000,0x8081000,0x10,0x1010,0x8000010,0x8001010,0x80010,0x81010,0x8080010,0x8081010);
|
||||
pc2bytes13 = new Array (0,0x4,0x100,0x104,0,0x4,0x100,0x104,0x1,0x5,0x101,0x105,0x1,0x5,0x101,0x105);
|
||||
|
||||
//how many iterations (1 for des, 3 for triple des)
|
||||
var iterations = key.length > 8 ? 3 : 1; //changed by Paul 16/6/2007 to use Triple DES for 9+ byte keys
|
||||
//stores the return keys
|
||||
var keys = new Array (32 * iterations);
|
||||
//now define the left shifts which need to be done
|
||||
var shifts = new Array (0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0);
|
||||
//other variables
|
||||
var lefttemp, righttemp, m=0, n=0, temp;
|
||||
|
||||
for (var j=0; j<iterations; j++) { //either 1 or 3 iterations
|
||||
left = (key.charCodeAt(m++) << 24) | (key.charCodeAt(m++) << 16) | (key.charCodeAt(m++) << 8) | key.charCodeAt(m++);
|
||||
right = (key.charCodeAt(m++) << 24) | (key.charCodeAt(m++) << 16) | (key.charCodeAt(m++) << 8) | key.charCodeAt(m++);
|
||||
|
||||
temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4);
|
||||
temp = ((right >>> -16) ^ left) & 0x0000ffff; left ^= temp; right ^= (temp << -16);
|
||||
temp = ((left >>> 2) ^ right) & 0x33333333; right ^= temp; left ^= (temp << 2);
|
||||
temp = ((right >>> -16) ^ left) & 0x0000ffff; left ^= temp; right ^= (temp << -16);
|
||||
temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1);
|
||||
temp = ((right >>> 8) ^ left) & 0x00ff00ff; left ^= temp; right ^= (temp << 8);
|
||||
temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1);
|
||||
|
||||
//the right side needs to be shifted and to get the last four bits of the left side
|
||||
temp = (left << 8) | ((right >>> 20) & 0x000000f0);
|
||||
//left needs to be put upside down
|
||||
left = (right << 24) | ((right << 8) & 0xff0000) | ((right >>> 8) & 0xff00) | ((right >>> 24) & 0xf0);
|
||||
right = temp;
|
||||
|
||||
//now go through and perform these shifts on the left and right keys
|
||||
for (i=0; i < shifts.length; i++) {
|
||||
//shift the keys either one or two bits to the left
|
||||
if (shifts[i]) {left = (left << 2) | (left >>> 26); right = (right << 2) | (right >>> 26);}
|
||||
else {left = (left << 1) | (left >>> 27); right = (right << 1) | (right >>> 27);}
|
||||
left &= -0xf; right &= -0xf;
|
||||
|
||||
//now apply PC-2, in such a way that E is easier when encrypting or decrypting
|
||||
//this conversion will look like PC-2 except only the last 6 bits of each byte are used
|
||||
//rather than 48 consecutive bits and the order of lines will be according to
|
||||
//how the S selection functions will be applied: S2, S4, S6, S8, S1, S3, S5, S7
|
||||
lefttemp = pc2bytes0[left >>> 28] | pc2bytes1[(left >>> 24) & 0xf]
|
||||
| pc2bytes2[(left >>> 20) & 0xf] | pc2bytes3[(left >>> 16) & 0xf]
|
||||
| pc2bytes4[(left >>> 12) & 0xf] | pc2bytes5[(left >>> 8) & 0xf]
|
||||
| pc2bytes6[(left >>> 4) & 0xf];
|
||||
righttemp = pc2bytes7[right >>> 28] | pc2bytes8[(right >>> 24) & 0xf]
|
||||
| pc2bytes9[(right >>> 20) & 0xf] | pc2bytes10[(right >>> 16) & 0xf]
|
||||
| pc2bytes11[(right >>> 12) & 0xf] | pc2bytes12[(right >>> 8) & 0xf]
|
||||
| pc2bytes13[(right >>> 4) & 0xf];
|
||||
temp = ((righttemp >>> 16) ^ lefttemp) & 0x0000ffff;
|
||||
keys[n++] = lefttemp ^ temp; keys[n++] = righttemp ^ (temp << 16);
|
||||
}
|
||||
} //for each iterations
|
||||
//return the keys we've created
|
||||
return keys;
|
||||
} //end of des_createKeys
|
||||
|
||||
|
||||
function des_addPadding(message, padding) {
|
||||
var padLength = 8 - (message.length % 8);
|
||||
if ((padding == 2) && (padLength < 8)) { //pad the message with spaces
|
||||
message += " ".substr(0, padLength);
|
||||
}
|
||||
else if (padding == 1) { //PKCS7 padding
|
||||
message += String.fromCharCode(padLength, padLength, padLength, padLength, padLength, padLength, padLength, padLength).substr(0, padLength);
|
||||
}
|
||||
else if (!padding && (padLength < 8)) { //pad the message out with null bytes
|
||||
message += "\0\0\0\0\0\0\0\0".substr(0, padLength);
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
function des_removePadding(message, padding) {
|
||||
if (padding == 2) { // space padded
|
||||
message = message.replace(/ *$/g, "");
|
||||
}
|
||||
else if (padding == 1) { // PKCS7
|
||||
var padCount = message.charCodeAt(message.length - 1);
|
||||
message = message.substr(0, message.length - padCount);
|
||||
}
|
||||
else if (!padding) { // null padding
|
||||
message = message.replace(/\0*$/g, "");
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,330 +0,0 @@
|
|||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* 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 openpgp_encoding_deArmor(text) {
|
||||
var reSplit = /^-----[^-]+-----$\n/m;
|
||||
|
||||
text = text.replace(/\r/g, '');
|
||||
|
||||
var type = openpgp_encoding_get_type(text);
|
||||
|
||||
var splittedtext = text.split(reSplit);
|
||||
|
||||
// IE has a bug in split with a re. If the pattern matches the beginning of the
|
||||
// string it doesn't create an empty array element 0. So we need to detect this
|
||||
// so we know the index of the data we are interested in.
|
||||
var indexBase = 1;
|
||||
|
||||
var result, checksum;
|
||||
|
||||
if (text.search(reSplit) != splittedtext[0].length) {
|
||||
indexBase = 0;
|
||||
}
|
||||
|
||||
if (type != 2) {
|
||||
// splittedtext[indexBase] - the message and checksum
|
||||
|
||||
// chunks separated by blank lines
|
||||
var msg = openpgp_encoding_split_headers(splittedtext[indexBase].replace(/^- /mg, ''));
|
||||
var msg_sum = openpgp_encoding_split_checksum(msg.body);
|
||||
|
||||
result = {
|
||||
openpgp: openpgp_encoding_base64_decode(msg_sum.body),
|
||||
type: type
|
||||
};
|
||||
checksum = msg_sum.checksum;
|
||||
} else {
|
||||
// splittedtext[indexBase] - the message
|
||||
// splittedtext[indexBase + 1] - the signature and checksum
|
||||
|
||||
var msg = openpgp_encoding_split_headers(splittedtext[indexBase].replace(/^- /mg, '').replace(/[\t ]+\n/g, "\n"));
|
||||
var sig = openpgp_encoding_split_headers(splittedtext[indexBase + 1].replace(/^- /mg, ''));
|
||||
var sig_sum = openpgp_encoding_split_checksum(sig.body);
|
||||
|
||||
result = {
|
||||
text: msg.body.replace(/\n$/, "").replace(/\n/g, "\r\n"),
|
||||
openpgp: openpgp_encoding_base64_decode(sig_sum.body),
|
||||
type: type
|
||||
};
|
||||
|
||||
checksum = sig_sum.checksum;
|
||||
}
|
||||
|
||||
if (!verifyCheckSum(result.openpgp, checksum)) {
|
||||
util.print_error("Ascii armor integrity check on message failed: '"
|
||||
+ checksum
|
||||
+ "' should be '"
|
||||
+ getCheckSum(result) + "'");
|
||||
return false;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits a message into two parts, the headers and the body. This is an internal function
|
||||
* @param {String} text OpenPGP armored message part
|
||||
* @returns {(Boolean|Object)} Either false in case of an error
|
||||
* or an object with attribute "headers" containing the headers and
|
||||
* and an attribute "body" containing the body.
|
||||
*/
|
||||
function openpgp_encoding_split_headers(text) {
|
||||
var reEmptyLine = /^[\t ]*\n/m;
|
||||
var headers = "";
|
||||
var body = text;
|
||||
|
||||
var matchResult = reEmptyLine.exec(text);
|
||||
|
||||
if (matchResult != null) {
|
||||
headers = text.slice(0, matchResult.index);
|
||||
body = text.slice(matchResult.index + matchResult[0].length);
|
||||
}
|
||||
|
||||
return { headers: headers, body: body };
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits a message into two parts, the body and the checksum. This is an internal function
|
||||
* @param {String} text OpenPGP armored message part
|
||||
* @returns {(Boolean|Object)} Either false in case of an error
|
||||
* or an object with attribute "body" containing the body
|
||||
* and an attribute "checksum" containing the checksum.
|
||||
*/
|
||||
function openpgp_encoding_split_checksum(text) {
|
||||
var reChecksumStart = /^=/m;
|
||||
var body = text;
|
||||
var checksum = "";
|
||||
|
||||
var matchResult = reChecksumStart.exec(text);
|
||||
|
||||
if (matchResult != null) {
|
||||
body = text.slice(0, matchResult.index);
|
||||
checksum = text.slice(matchResult.index + 1);
|
||||
}
|
||||
|
||||
return { body: body, checksum: checksum };
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 openpgp_encoding_get_type(text) {
|
||||
var reHeader = /^-----([^-]+)-----$\n/m;
|
||||
|
||||
var header = text.match(reHeader);
|
||||
// BEGIN PGP MESSAGE, PART X/Y
|
||||
// Used for multi-part messages, where the armor is split amongst Y
|
||||
// parts, and this is the Xth part out of Y.
|
||||
if (header[1].match(/BEGIN PGP MESSAGE, PART \d+\/\d+/)) {
|
||||
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 (header[1].match(/BEGIN PGP MESSAGE, PART \d+/)) {
|
||||
return 1;
|
||||
|
||||
} else
|
||||
// BEGIN PGP SIGNED MESSAGE
|
||||
// Used for detached signatures, OpenPGP/MIME signatures, and
|
||||
// cleartext signatures. Note that PGP 2.x uses BEGIN PGP MESSAGE
|
||||
// for detached signatures.
|
||||
if (header[1].match(/BEGIN PGP SIGNED MESSAGE/)) {
|
||||
return 2;
|
||||
|
||||
} else
|
||||
// BEGIN PGP MESSAGE
|
||||
// Used for signed, encrypted, or compressed files.
|
||||
if (header[1].match(/BEGIN PGP MESSAGE/)) {
|
||||
return 3;
|
||||
|
||||
} else
|
||||
// BEGIN PGP PUBLIC KEY BLOCK
|
||||
// Used for armoring public keys.
|
||||
if (header[1].match(/BEGIN PGP PUBLIC KEY BLOCK/)) {
|
||||
return 4;
|
||||
|
||||
} else
|
||||
// BEGIN PGP PRIVATE KEY BLOCK
|
||||
// Used for armoring private keys.
|
||||
if (header[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 openpgp_encoding_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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 openpgp_encoding_armor(messagetype, data, partindex, parttotal) {
|
||||
var result = "";
|
||||
switch(messagetype) {
|
||||
case 0:
|
||||
result += "-----BEGIN PGP MESSAGE, PART "+partindex+"/"+parttotal+"-----\r\n";
|
||||
result += openpgp_encoding_armor_addheader();
|
||||
result += openpgp_encoding_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 += openpgp_encoding_armor_addheader();
|
||||
result += openpgp_encoding_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 += openpgp_encoding_armor_addheader();
|
||||
result += openpgp_encoding_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 += openpgp_encoding_armor_addheader();
|
||||
result += openpgp_encoding_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 += openpgp_encoding_armor_addheader();
|
||||
result += openpgp_encoding_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 += openpgp_encoding_armor_addheader();
|
||||
result += openpgp_encoding_base64_encode(data);
|
||||
result += "\r\n="+getCheckSum(data)+"\r\n";
|
||||
result += "-----END PGP PRIVATE KEY BLOCK-----\r\n";
|
||||
break;
|
||||
}
|
||||
|
||||
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 openpgp_encoding_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;
|
||||
}
|
||||
|
|
@ -1,136 +0,0 @@
|
|||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @class
|
||||
* @classdesc Top-level message object. Contains information from one or more packets
|
||||
*/
|
||||
|
||||
function openpgp_msg_message() {
|
||||
|
||||
// -1 = no valid passphrase submitted
|
||||
// -2 = no private key found
|
||||
// -3 = decryption error
|
||||
// text = valid decryption
|
||||
this.text = "";
|
||||
this.messagePacket = null;
|
||||
this.type = null;
|
||||
|
||||
/**
|
||||
* 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 {String} plaintext of the message or null on error
|
||||
*/
|
||||
function decrypt(private_key, sessionkey) {
|
||||
return this.decryptAndVerifySignature(private_key, sessionkey).text;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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++) {
|
||||
if (this.signature.verify(this.text, 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;
|
||||
break;
|
||||
} 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;
|
||||
}
|
||||
|
||||
function toString() {
|
||||
var result = "Session Keys:\n";
|
||||
if (this.sessionKeys !=null)
|
||||
for (var i = 0; i < this.sessionKeys.length; i++) {
|
||||
result += this.sessionKeys[i].toString();
|
||||
}
|
||||
result += "\n\n EncryptedData:\n";
|
||||
if(this.encryptedData != null)
|
||||
result += this.encryptedData.toString();
|
||||
|
||||
result += "\n\n Signature:\n";
|
||||
if(this.signature != null)
|
||||
result += this.signature.toString();
|
||||
|
||||
result += "\n\n Text:\n"
|
||||
if(this.signature != null)
|
||||
result += this.text;
|
||||
return result;
|
||||
}
|
||||
this.decrypt = decrypt;
|
||||
this.decryptAndVerifySignature = decryptAndVerifySignature;
|
||||
this.verifySignature = verifySignature;
|
||||
this.toString = toString;
|
||||
}
|
|
@ -1,265 +0,0 @@
|
|||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @classdesc Decoded public key object for internal openpgp.js use
|
||||
*/
|
||||
function openpgp_msg_publickey() {
|
||||
this.tostring = "OPENPGP PUBLIC KEY\n";
|
||||
this.bindingSignature = null;
|
||||
this.publicKeyPacket = null;
|
||||
this.userIds = new Array();
|
||||
this.userAttributes = new Array();
|
||||
this.revocationSignatures = new Array();
|
||||
this.subKeys = new Array();
|
||||
this.arbitraryPacket = new Array();
|
||||
this.directSignatures = new Array();
|
||||
/**
|
||||
*
|
||||
* @return last position
|
||||
*/
|
||||
function read_nodes(parent_node, input, position, len) {
|
||||
this.publicKeyPacket = parent_node;
|
||||
var exit = false;
|
||||
var pos = position;
|
||||
var l = len;
|
||||
while (input.length != pos) {
|
||||
var result = openpgp_packet.read_packet(input, pos, input.length - pos);
|
||||
if (result == null) {
|
||||
util.print_error("openpgp.msg.publickey read_nodes:\n"+'[pub_key]parsing ends here @:' + pos + " l:" + l);
|
||||
break;
|
||||
} else {
|
||||
switch (result.tagType) {
|
||||
case 2: // public key revocation signature
|
||||
if (result.signatureType == 32)
|
||||
this.revocationSignatures[this.revocationSignatures.length] = result;
|
||||
else if (result.signatureType == 16 || result.signatureType == 17 || result.signatureType == 18 || result.signatureType == 19)
|
||||
this.certificationSignature = result;
|
||||
else if (result.signatureType == 25) {
|
||||
this.bindingSignature = result;
|
||||
} else if (result.signatureType == 31) {
|
||||
this.directSignatures[this.directSignatures.length] = result;
|
||||
} else
|
||||
util.print_error("openpgp.msg.publickey read_nodes:\n"+"unknown signature type directly on key "+result.signatureType);
|
||||
pos += result.packetLength + result.headerLength;
|
||||
break;
|
||||
case 14: // Public-Subkey Packet
|
||||
this.subKeys[this.subKeys.length] = result;
|
||||
pos += result.packetLength + result.headerLength;
|
||||
pos += result.read_nodes(this.publicKeyPacket,input, pos, input.length - pos);
|
||||
break;
|
||||
case 17: // User Attribute Packet
|
||||
this.userAttributes[this.userAttributes.length] = result;
|
||||
pos += result.packetLength + result.headerLength;
|
||||
pos += result.read_nodes(this.publicKeyPacket,input, pos, input.length - pos);
|
||||
break;
|
||||
case 13: // User ID Packet
|
||||
this.userIds[this.userIds.length] = result;
|
||||
pos += result.packetLength + result.headerLength;
|
||||
pos += result.read_nodes(this.publicKeyPacket, input, pos, input.length - pos);
|
||||
break;
|
||||
default:
|
||||
this.data = input;
|
||||
this.position = position - this.publicKeyPacket.packetLength - this.publicKeyPacket.headerLength;
|
||||
this.len = pos - position;
|
||||
return this.len;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.data = input;
|
||||
this.position = position - (this.publicKeyPacket.packetLength - this.publicKeyPacket.headerLength);
|
||||
this.len = pos - position;
|
||||
return this.len;
|
||||
}
|
||||
|
||||
function write() {
|
||||
|
||||
}
|
||||
|
||||
function getKeyId() {
|
||||
return this.publicKeyPacket.getKeyId();
|
||||
}
|
||||
|
||||
function getFingerprint() {
|
||||
return this.publicKeyPacket.getFingerprint();
|
||||
}
|
||||
|
||||
|
||||
|
||||
function validate() {
|
||||
// check revocation keys
|
||||
for (var i = 0; i < this.revocationSignatures.length; i++) {
|
||||
var tohash = this.publicKeyPacket.header+this.publicKeyPacket.data;
|
||||
if (this.revocationSignatures[i].verify(tohash, this.publicKeyPacket))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.subKeys.length != 0) {
|
||||
// search for a valid subkey
|
||||
var found = false;
|
||||
for (var i = 0; i < this.subKeys.length; i++)
|
||||
if (this.subKeys[i].verifyKey() == 3) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (!found)
|
||||
return false;
|
||||
}
|
||||
// search for one valid userid
|
||||
found = false;
|
||||
for (var i = 0; i < this.userIds.length; i++)
|
||||
if (this.userIds[i].verify(this.publicKeyPacket) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (!found)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* verifies all signatures
|
||||
* @return a 2 dimensional array. the first dimension corresponds to the userids available
|
||||
*/
|
||||
function verifyCertificationSignatures() {
|
||||
var result = new Array();
|
||||
for (var i = 0; i < this.userIds.length; i++) {
|
||||
result[i] = this.userIds[i].verifyCertificationSignatures(this.publicKeyPacket);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
this.verifyCertificationSignatures = verifyCertificationSignatures;
|
||||
|
||||
/**
|
||||
* verifies:
|
||||
* - revocation certificates directly on key
|
||||
* - self signatures
|
||||
* - subkey binding and revocation certificates
|
||||
*
|
||||
* This is useful for validating the key
|
||||
* @returns {Boolean} true if the basic signatures are all valid
|
||||
*/
|
||||
function verifyBasicSignatures() {
|
||||
for (var i = 0; i < this.revocationSignatures.length; i++) {
|
||||
var tohash = this.publicKeyPacket.header+this.publicKeyPacket.data;
|
||||
if (this.revocationSignatures[i].verify(tohash, this.publicKeyPacket))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.subKeys.length != 0) {
|
||||
// search for a valid subkey
|
||||
var found = false;
|
||||
for (var i = 0; i < this.subKeys.length; i++) {
|
||||
if (this.subKeys[i] == null)
|
||||
continue;
|
||||
var result = this.subKeys[i].verifyKey();
|
||||
if (result == 3) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
return false;
|
||||
}
|
||||
var keyId = this.getKeyId();
|
||||
for (var i = 0; i < this.userIds.length; i++) {
|
||||
for (var j = 0; j < this.userIds[i].certificationRevocationSignatures.length; j++) {
|
||||
if (this.userIds[i].certificationSignatures[j].getIssuer == keyId &&
|
||||
this.userIds[i].certificationSignatures[j].verifyBasic(this.publicKeyPacket) != 4)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function toString() {
|
||||
var result = " OPENPGP Public Key\n length: "+this.len+"\n";
|
||||
result += " Revocation Signatures:\n"
|
||||
for (var i=0; i < this.revocationSignatures.length; i++) {
|
||||
result += " "+this.revocationSignatures[i].toString();
|
||||
}
|
||||
result += " User Ids:\n";
|
||||
for (var i=0; i < this.userIds.length; i++) {
|
||||
result += " "+this.userIds[i].toString();
|
||||
}
|
||||
result += " User Attributes:\n";
|
||||
for (var i=0; i < this.userAttributes.length; i++) {
|
||||
result += " "+this.userAttributes[i].toString();
|
||||
}
|
||||
result += " Public Key SubKeys:\n";
|
||||
for (var i=0; i < this.subKeys.length; i++) {
|
||||
result += " "+this.subKeys[i].toString();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* finds an encryption key for this public key
|
||||
* @returns null if no encryption key has been found
|
||||
*/
|
||||
function getEncryptionKey() {
|
||||
// V4: by convention subkeys are prefered for encryption service
|
||||
// V3: keys MUST NOT have subkeys
|
||||
for (var j = 0; j < this.subKeys.length; j++)
|
||||
if (this.subKeys[j].publicKeyAlgorithm != 17 &&
|
||||
this.subKeys[j].publicKeyAlgorithm != 3 &&
|
||||
this.subKeys[j].verifyKey()) {
|
||||
return this.subKeys[j];
|
||||
}
|
||||
// if no valid subkey for encryption, use primary key
|
||||
if (this.publicKeyPacket.publicKeyAlgorithm != 17 && this.publicKeyPacket.publicKeyAlgorithm != 3
|
||||
&& this.publicKeyPacket.verifyKey()) {
|
||||
return this.publicKeyPacket;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getSigningKey() {
|
||||
if ((this.publicKeyPacket.publicKeyAlgorithm == 17 ||
|
||||
this.publicKeyPacket.publicKeyAlgorithm != 2))
|
||||
return this.publicKeyPacket;
|
||||
else if (this.publicKeyPacket.version == 4) // V3 keys MUST NOT have subkeys.
|
||||
for (var j = 0; j < this.subKeys.length; j++) {
|
||||
if ((this.subKeys[j].publicKeyAlgorithm == 17 ||
|
||||
this.subKeys[j].publicKeyAlgorithm != 2) &&
|
||||
this.subKeys[j].verifyKey())
|
||||
return this.subKeys[j];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Returns the i-th subKey as a openpgp_msg_publickey object */
|
||||
function getSubKeyAsKey(i) {
|
||||
var ret = new openpgp_msg_publickey();
|
||||
ret.userIds = this.userIds;
|
||||
ret.userAttributes = this.userAttributes;
|
||||
ret.publicKeyPacket = this.subKeys[i];
|
||||
return ret;
|
||||
}
|
||||
|
||||
this.getEncryptionKey = getEncryptionKey;
|
||||
this.getSigningKey = getSigningKey;
|
||||
this.read_nodes = read_nodes;
|
||||
this.write = write;
|
||||
this.toString = toString;
|
||||
this.validate = validate;
|
||||
this.getFingerprint = getFingerprint;
|
||||
this.getKeyId = getKeyId;
|
||||
this.verifyBasicSignatures = verifyBasicSignatures;
|
||||
this.getSubKeyAsKey = getSubKeyAsKey;
|
||||
}
|
|
@ -1,155 +0,0 @@
|
|||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @classdesc Implementation of the 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.
|
||||
*/
|
||||
|
||||
function openpgp_packet_encryptedintegrityprotecteddata() {
|
||||
this.tagType = 18;
|
||||
this.version = null; // integer == 1
|
||||
this.packetLength = null; // integer
|
||||
this.encryptedData = null; // string
|
||||
this.decrytpedData = null; // string
|
||||
this.hash = null; // string
|
||||
/**
|
||||
* Parsing function for the packet.
|
||||
*
|
||||
* @param {String} input Payload of a tag 18 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_encryptedintegrityprotecteddata} object
|
||||
* representation
|
||||
*/
|
||||
function read_packet(input, position, len) {
|
||||
this.packetLength = len;
|
||||
// - A one-octet version number. The only currently defined value is
|
||||
// 1.
|
||||
this.version = input.charCodeAt(position);
|
||||
if (this.version != 1) {
|
||||
util
|
||||
.print_error('openpgp.packet.encryptedintegrityprotecteddata.js\nunknown encrypted integrity protected data packet version: '
|
||||
+ this.version
|
||||
+ " , @ "
|
||||
+ position
|
||||
+ "hex:"
|
||||
+ util.hexstrdump(input));
|
||||
return null;
|
||||
}
|
||||
// - Encrypted data, the output of the selected symmetric-key cipher
|
||||
// operating in Cipher Feedback mode with shift amount equal to the
|
||||
// block size of the cipher (CFB-n where n is the block size).
|
||||
this.encryptedData = input.substring(position + 1, position + 1 + len);
|
||||
util.print_debug("openpgp.packet.encryptedintegrityprotecteddata.js\n"
|
||||
+ this.toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string representation of a Sym. Encrypted Integrity Protected
|
||||
* Data Packet (tag 18) (see RFC4880 5.13)
|
||||
*
|
||||
* @param {Integer} symmetric_algorithm
|
||||
* The selected symmetric encryption algorithm to be used
|
||||
* @param {String} key The key of cipher blocksize length to be used
|
||||
* @param {String} data
|
||||
* Plaintext data to be encrypted within the packet
|
||||
* @return {String} A string representation of the packet
|
||||
*/
|
||||
function write_packet(symmetric_algorithm, key, data) {
|
||||
|
||||
var prefixrandom = openpgp_crypto_getPrefixRandom(symmetric_algorithm);
|
||||
var prefix = prefixrandom
|
||||
+ prefixrandom.charAt(prefixrandom.length - 2)
|
||||
+ prefixrandom.charAt(prefixrandom.length - 1);
|
||||
var tohash = data;
|
||||
tohash += String.fromCharCode(0xD3);
|
||||
tohash += String.fromCharCode(0x14);
|
||||
util.print_debug_hexstr_dump("data to be hashed:"
|
||||
, prefix + tohash);
|
||||
tohash += str_sha1(prefix + tohash);
|
||||
util.print_debug_hexstr_dump("hash:"
|
||||
, tohash.substring(tohash.length - 20,
|
||||
tohash.length));
|
||||
var result = openpgp_crypto_symmetricEncrypt(prefixrandom,
|
||||
symmetric_algorithm, key, tohash, false).substring(0,
|
||||
prefix.length + tohash.length);
|
||||
var header = openpgp_packet.write_packet_header(18, result.length + 1)
|
||||
+ String.fromCharCode(1);
|
||||
this.encryptedData = result;
|
||||
return header + result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts the encrypted data contained in this object read_packet must
|
||||
* have been called before
|
||||
*
|
||||
* @param {Integer} symmetric_algorithm_type
|
||||
* 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
|
||||
*/
|
||||
function decrypt(symmetric_algorithm_type, key) {
|
||||
this.decryptedData = openpgp_crypto_symmetricDecrypt(
|
||||
symmetric_algorithm_type, key, this.encryptedData, false);
|
||||
// there must be a modification detection code packet as the
|
||||
// last packet and everything gets hashed except the hash itself
|
||||
this.hash = str_sha1(openpgp_crypto_MDCSystemBytes(
|
||||
symmetric_algorithm_type, key, this.encryptedData)
|
||||
+ this.decryptedData.substring(0,
|
||||
this.decryptedData.length - 20));
|
||||
util.print_debug_hexstr_dump("calc hash = ", this.hash);
|
||||
if (this.hash == this.decryptedData.substring(
|
||||
this.decryptedData.length - 20, this.decryptedData.length))
|
||||
return this.decryptedData;
|
||||
else
|
||||
util
|
||||
.print_error("Decryption stopped: discovered a modification of encrypted data.");
|
||||
return null;
|
||||
}
|
||||
|
||||
function toString() {
|
||||
var data = '';
|
||||
if(openpgp.config.debug)
|
||||
data = ' data: Bytes ['
|
||||
+ util.hexstrdump(this.encryptedData) + ']';
|
||||
|
||||
return '5.13. Sym. Encrypted Integrity Protected Data Packet (Tag 18)\n'
|
||||
+ ' length: '
|
||||
+ this.packetLength
|
||||
+ '\n'
|
||||
+ ' version: '
|
||||
+ this.version
|
||||
+ '\n'
|
||||
+ data;
|
||||
}
|
||||
|
||||
this.write_packet = write_packet;
|
||||
this.read_packet = read_packet;
|
||||
this.toString = toString;
|
||||
this.decrypt = decrypt;
|
||||
};
|
|
@ -1,226 +0,0 @@
|
|||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @classdesc 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.
|
||||
*/
|
||||
function openpgp_packet_encryptedsessionkey() {
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
function read_pub_key_packet(input, position, len) {
|
||||
this.tagType = 1;
|
||||
this.packetLength = len;
|
||||
var mypos = position;
|
||||
if (len < 10) {
|
||||
util
|
||||
.print_error("openpgp.packet.encryptedsessionkey.js\n" + 'invalid length');
|
||||
return null;
|
||||
}
|
||||
|
||||
this.version = input.charCodeAt(mypos++);
|
||||
this.keyId = new openpgp_type_keyid();
|
||||
this.keyId.read_packet(input, mypos);
|
||||
mypos += 8;
|
||||
this.publicKeyAlgorithmUsed = input.charCodeAt(mypos++);
|
||||
|
||||
switch (this.publicKeyAlgorithmUsed) {
|
||||
case 1:
|
||||
case 2: // RSA
|
||||
this.MPIs = new Array();
|
||||
this.MPIs[0] = new openpgp_type_mpi();
|
||||
this.MPIs[0].read(input, mypos, mypos - position);
|
||||
break;
|
||||
case 16: // Elgamal
|
||||
this.MPIs = new Array();
|
||||
this.MPIs[0] = new openpgp_type_mpi();
|
||||
this.MPIs[0].read(input, mypos, mypos - position);
|
||||
mypos += this.MPIs[0].packetLength;
|
||||
this.MPIs[1] = new openpgp_type_mpi();
|
||||
this.MPIs[1].read(input, mypos, mypos - position);
|
||||
break;
|
||||
default:
|
||||
util.print_error("openpgp.packet.encryptedsessionkey.js\n"
|
||||
+ "unknown public key packet algorithm type "
|
||||
+ this.publicKeyAlgorithmType);
|
||||
break;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
function write_pub_key_packet(publicKeyId, publicMPIs, pubalgo, symmalgo,
|
||||
sessionkey) {
|
||||
var result = String.fromCharCode(3);
|
||||
var data = String.fromCharCode(symmalgo);
|
||||
data += sessionkey;
|
||||
var checksum = util.calc_checksum(sessionkey);
|
||||
data += String.fromCharCode((checksum >> 8) & 0xFF);
|
||||
data += String.fromCharCode((checksum) & 0xFF);
|
||||
result += publicKeyId;
|
||||
result += String.fromCharCode(pubalgo);
|
||||
var mpi = new openpgp_type_mpi();
|
||||
var mpiresult = openpgp_crypto_asymetricEncrypt(pubalgo, publicMPIs,
|
||||
mpi.create(openpgp_encoding_eme_pkcs1_encode(data,
|
||||
publicMPIs[0].mpiByteLength)));
|
||||
for ( var i = 0; i < mpiresult.length; i++) {
|
||||
result += mpiresult[i];
|
||||
}
|
||||
result = openpgp_packet.write_packet_header(1, result.length) + result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
function read_symmetric_key_packet(input, position, len) {
|
||||
this.tagType = 3;
|
||||
var mypos = position;
|
||||
// A one-octet version number. The only currently defined version is 4.
|
||||
this.version = input[mypos++];
|
||||
|
||||
// A one-octet number describing the symmetric algorithm used.
|
||||
this.symmetricKeyAlgorithmUsed = input[mypos++];
|
||||
// A string-to-key (S2K) specifier, length as defined above.
|
||||
this.s2k = new openpgp_type_s2k();
|
||||
this.s2k.read(input, mypos);
|
||||
|
||||
// Optionally, the encrypted session key itself, which is decrypted
|
||||
// with the string-to-key object.
|
||||
if ((s2k.s2kLength + mypos) < len) {
|
||||
this.encryptedSessionKey = new Array();
|
||||
for ( var i = (mypos - position); i < len; i++) {
|
||||
this.encryptedSessionKey[i] = input[mypos++];
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
function decrypt(msg, key) {
|
||||
if (this.tagType == 1) {
|
||||
var result = openpgp_crypto_asymetricDecrypt(
|
||||
this.publicKeyAlgorithmUsed, key.publicKey.MPIs,
|
||||
key.secMPIs, this.MPIs).toMPI();
|
||||
var checksum = ((result.charCodeAt(result.length - 2) << 8) + result
|
||||
.charCodeAt(result.length - 1));
|
||||
var decoded = openpgp_encoding_eme_pkcs1_decode(result.substring(2, result.length - 2), key.publicKey.MPIs[0].getByteLength());
|
||||
var sesskey = decoded.substring(1);
|
||||
var algo = decoded.charCodeAt(0);
|
||||
if (msg.encryptedData.tagType == 18)
|
||||
return msg.encryptedData.decrypt(algo, sesskey);
|
||||
else
|
||||
return msg.encryptedData.decrypt_sym(algo, sesskey);
|
||||
} else if (this.tagType == 3) {
|
||||
util
|
||||
.print_error("Symmetric encrypted sessionkey is not supported!");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string representation of this object (useful for debug
|
||||
* purposes)
|
||||
*
|
||||
* @return {String} The string containing a openpgp description
|
||||
*/
|
||||
function toString() {
|
||||
if (this.tagType == 1) {
|
||||
var result = '5.1. Public-Key Encrypted Session Key Packets (Tag 1)\n'
|
||||
+ ' KeyId: '
|
||||
+ this.keyId.toString()
|
||||
+ '\n'
|
||||
+ ' length: '
|
||||
+ this.packetLength
|
||||
+ '\n'
|
||||
+ ' version:'
|
||||
+ this.version
|
||||
+ '\n'
|
||||
+ ' pubAlgUs:'
|
||||
+ this.publicKeyAlgorithmUsed + '\n';
|
||||
for ( var i = 0; i < this.MPIs.length; i++) {
|
||||
result += this.MPIs[i].toString();
|
||||
}
|
||||
return result;
|
||||
} else
|
||||
return '5.3 Symmetric-Key Encrypted Session Key Packets (Tag 3)\n'
|
||||
+ ' KeyId: ' + this.keyId.toString() + '\n'
|
||||
+ ' length: ' + this.packetLength + '\n'
|
||||
+ ' version:' + this.version + '\n' + ' symKeyA:'
|
||||
+ this.symmetricKeyAlgorithmUsed + '\n' + ' s2k: '
|
||||
+ this.s2k + '\n';
|
||||
}
|
||||
|
||||
this.read_pub_key_packet = read_pub_key_packet;
|
||||
this.read_symmetric_key_packet = read_symmetric_key_packet;
|
||||
this.write_pub_key_packet = write_pub_key_packet;
|
||||
this.toString = toString;
|
||||
this.decrypt = decrypt;
|
||||
};
|
||||
|
|
@ -1,407 +0,0 @@
|
|||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @classdesc Parent openpgp packet class. Operations focus on determining
|
||||
* packet types and packet header.
|
||||
*/
|
||||
function _openpgp_packet() {
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
function encode_length(length) {
|
||||
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 += String.fromCharCode((length >> 24) & 0xFF);
|
||||
result += String.fromCharCode((length >> 16) & 0xFF);
|
||||
result += String.fromCharCode((length >> 8) & 0xFF);
|
||||
result += String.fromCharCode(length & 0xFF);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
this.encode_length = encode_length;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
function write_packet_header(tag_type, length) {
|
||||
/* we're only generating v4 packet headers here */
|
||||
var result = "";
|
||||
result += String.fromCharCode(0xC0 | tag_type);
|
||||
result += encode_length(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
|
||||
*/
|
||||
function write_old_packet_header(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 += String.fromCharCode(length >> 8);
|
||||
result += String.fromCharCode(length & 0xFF);
|
||||
} else {
|
||||
result += String.fromCharCode(0x80 | (tag_type << 2) | 2);
|
||||
result += String.fromCharCode((length >> 24) & 0xFF);
|
||||
result += String.fromCharCode((length >> 16) & 0xFF);
|
||||
result += String.fromCharCode((length >> 8) & 0xFF);
|
||||
result += String.fromCharCode(length & 0xFF);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
this.write_old_packet_header = write_old_packet_header;
|
||||
this.write_packet_header = write_packet_header;
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
function read_packet(input, position, len) {
|
||||
// some sanity checks
|
||||
if (input == null || input.length <= position
|
||||
|| input.substring(position).length < 2
|
||||
|| (input.charCodeAt(position) & 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;
|
||||
|
||||
format = 0; // 0 = old format; 1 = new format
|
||||
if ((input.charCodeAt(mypos) & 0x40) != 0) {
|
||||
format = 1;
|
||||
}
|
||||
|
||||
var packet_length_type;
|
||||
if (format) {
|
||||
// new format header
|
||||
tag = input.charCodeAt(mypos) & 0x3F; // bit 5-0
|
||||
} else {
|
||||
// old format header
|
||||
tag = (input.charCodeAt(mypos) & 0x3F) >> 2; // bit 5-2
|
||||
packet_length_type = input.charCodeAt(mypos) & 0x03; // bit 1-0
|
||||
}
|
||||
|
||||
// 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.charCodeAt(mypos++);
|
||||
break;
|
||||
case 1: // The packet has a two-octet length. The header is 3 octets
|
||||
// long.
|
||||
packet_length = (input.charCodeAt(mypos++) << 8)
|
||||
| input.charCodeAt(mypos++);
|
||||
break;
|
||||
case 2: // The packet has a four-octet length. The header is 5
|
||||
// octets long.
|
||||
packet_length = (input.charCodeAt(mypos++) << 24)
|
||||
| (input.charCodeAt(mypos++) << 16)
|
||||
| (input.charCodeAt(mypos++) << 8)
|
||||
| input.charCodeAt(mypos++);
|
||||
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.charCodeAt(mypos) < 192) {
|
||||
packet_length = input.charCodeAt(mypos++);
|
||||
util.print_debug("1 byte length:" + packet_length);
|
||||
// 4.2.2.2. Two-Octet Lengths
|
||||
} else if (input.charCodeAt(mypos) >= 192
|
||||
&& input.charCodeAt(mypos) < 224) {
|
||||
packet_length = ((input.charCodeAt(mypos++) - 192) << 8)
|
||||
+ (input.charCodeAt(mypos++)) + 192;
|
||||
util.print_debug("2 byte length:" + packet_length);
|
||||
// 4.2.2.4. Partial Body Lengths
|
||||
} else if (input.charCodeAt(mypos) > 223
|
||||
&& input.charCodeAt(mypos) < 255) {
|
||||
packet_length = 1 << (input.charCodeAt(mypos++) & 0x1F);
|
||||
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.charCodeAt(mypos2) < 192) {
|
||||
var tmplen = input.charCodeAt(mypos2++);
|
||||
packet_length += tmplen;
|
||||
bodydata += input.substring(mypos2, mypos2 + tmplen);
|
||||
mypos2 += tmplen;
|
||||
break;
|
||||
} else if (input.charCodeAt(mypos2) >= 192
|
||||
&& input.charCodeAt(mypos2) < 224) {
|
||||
var tmplen = ((input.charCodeAt(mypos2++) - 192) << 8)
|
||||
+ (input.charCodeAt(mypos2++)) + 192;
|
||||
packet_length += tmplen;
|
||||
bodydata += input.substring(mypos2, mypos2 + tmplen);
|
||||
mypos2 += tmplen;
|
||||
break;
|
||||
} else if (input.charCodeAt(mypos2) > 223
|
||||
&& input.charCodeAt(mypos2) < 255) {
|
||||
var tmplen = 1 << (input.charCodeAt(mypos2++) & 0x1F);
|
||||
packet_length += tmplen;
|
||||
bodydata += input.substring(mypos2, mypos2 + tmplen);
|
||||
mypos2 += tmplen;
|
||||
} else {
|
||||
mypos2++;
|
||||
var tmplen = (input.charCodeAt(mypos2++) << 24)
|
||||
| (input.charCodeAt(mypos2++) << 16)
|
||||
| (input.charCodeAt(mypos2++) << 8)
|
||||
| input.charCodeAt(mypos2++);
|
||||
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.charCodeAt(mypos++) << 24)
|
||||
| (input.charCodeAt(mypos++) << 16)
|
||||
| (input.charCodeAt(mypos++) << 8)
|
||||
| input.charCodeAt(mypos++);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// alert('tag type: '+this.tag+' length: '+packet_length);
|
||||
var version = 1; // (old format; 2= new format)
|
||||
// if (input.charCodeAt(mypos++) > 15)
|
||||
// version = 2;
|
||||
|
||||
switch (tag) {
|
||||
case 0: // Reserved - a packet tag MUST NOT have this value
|
||||
break;
|
||||
case 1: // Public-Key Encrypted Session Key Packet
|
||||
var result = new openpgp_packet_encryptedsessionkey();
|
||||
if (result.read_pub_key_packet(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 2: // Signature Packet
|
||||
var result = new openpgp_packet_signature();
|
||||
if (result.read_packet(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 3: // Symmetric-Key Encrypted Session Key Packet
|
||||
var result = new openpgp_packet_encryptedsessionkey();
|
||||
if (result.read_symmetric_key_packet(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 4: // One-Pass Signature Packet
|
||||
var result = new openpgp_packet_onepasssignature();
|
||||
if (result.read_packet(bodydata, 0, packet_length)) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 5: // Secret-Key Packet
|
||||
var result = new openpgp_packet_keymaterial();
|
||||
result.header = input.substring(position, mypos);
|
||||
if (result.read_tag5(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 6: // Public-Key Packet
|
||||
var result = new openpgp_packet_keymaterial();
|
||||
result.header = input.substring(position, mypos);
|
||||
if (result.read_tag6(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 7: // Secret-Subkey Packet
|
||||
var result = new openpgp_packet_keymaterial();
|
||||
if (result.read_tag7(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 8: // Compressed Data Packet
|
||||
var result = new openpgp_packet_compressed();
|
||||
if (result.read_packet(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 9: // Symmetrically Encrypted Data Packet
|
||||
var result = new openpgp_packet_encrypteddata();
|
||||
if (result.read_packet(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 10: // Marker Packet = PGP (0x50, 0x47, 0x50)
|
||||
var result = new openpgp_packet_marker();
|
||||
if (result.read_packet(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 11: // Literal Data Packet
|
||||
var result = new openpgp_packet_literaldata();
|
||||
if (result.read_packet(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.header = input.substring(position, mypos);
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 12: // Trust Packet
|
||||
// TODO: to be implemented
|
||||
break;
|
||||
case 13: // User ID Packet
|
||||
var result = new openpgp_packet_userid();
|
||||
if (result.read_packet(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 14: // Public-Subkey Packet
|
||||
var result = new openpgp_packet_keymaterial();
|
||||
result.header = input.substring(position, mypos);
|
||||
if (result.read_tag14(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 17: // User Attribute Packet
|
||||
var result = new openpgp_packet_userattribute();
|
||||
if (result.read_packet(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 18: // Sym. Encrypted and Integrity Protected Data Packet
|
||||
var result = new openpgp_packet_encryptedintegrityprotecteddata();
|
||||
if (result.read_packet(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 19: // Modification Detection Code Packet
|
||||
var result = new openpgp_packet_modificationdetectioncode();
|
||||
if (result.read_packet(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
util.print_error("openpgp.packet.js\n"
|
||||
+ "[ERROR] openpgp_packet: failed to parse packet @:"
|
||||
+ mypos + "\nchar:'"
|
||||
+ util.hexstrdump(input.substring(mypos)) + "'\ninput:"
|
||||
+ util.hexstrdump(input));
|
||||
return null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.read_packet = read_packet;
|
||||
}
|
||||
|
||||
var openpgp_packet = new _openpgp_packet();
|
|
@ -1,819 +0,0 @@
|
|||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @classdesc Implementation of the 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 openpgp_packet_keymaterial() {
|
||||
// members:
|
||||
this.publicKeyAlgorithm = null;
|
||||
this.tagType = null;
|
||||
this.creationTime = null;
|
||||
this.version = null;
|
||||
this.expiration = null;// V3
|
||||
this.MPIs = null;
|
||||
this.secMPIs = null;
|
||||
this.publicKey = null;
|
||||
this.symmetricEncryptionAlgorithm = null;
|
||||
this.s2kUsageConventions = null;
|
||||
this.IVLength = null;
|
||||
this.encryptedMPIData = null;
|
||||
this.hasUnencryptedSecretKeyData = null;
|
||||
this.checksum = null;
|
||||
this.parentNode = null;
|
||||
this.subKeySignature = null;
|
||||
this.subKeyRevocationSignature = null;
|
||||
|
||||
// 5.5.1. Key Packet Variants
|
||||
|
||||
// 5.5.1.3. Secret-Key Packet (Tag 5)
|
||||
/**
|
||||
* This function reads the payload of a secret key packet (Tag 5)
|
||||
* and initializes the openpgp_packet_keymaterial
|
||||
* @param {String} input Input string to read the packet from
|
||||
* @param {Integer} position Start position for the parser
|
||||
* @param {Intefer} len Length of the packet or remaining length of input
|
||||
* @return {openpgp_packet_keymaterial}
|
||||
*/
|
||||
function read_tag5(input, position, len) {
|
||||
this.tagType = 5;
|
||||
this.read_priv_key(input, position, len);
|
||||
return this;
|
||||
}
|
||||
|
||||
// 5.5.1.1. Public-Key Packet (Tag 6)
|
||||
/**
|
||||
* This function reads the payload of a public key packet (Tag 6)
|
||||
* and initializes the openpgp_packet_keymaterial
|
||||
* @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 {openpgp_packet_keymaterial}
|
||||
*/
|
||||
function read_tag6(input, position, len) {
|
||||
// A Public-Key packet starts a series of packets that forms an OpenPGP
|
||||
// key (sometimes called an OpenPGP certificate).
|
||||
this.tagType = 6;
|
||||
this.packetLength = len;
|
||||
this.read_pub_key(input, position,len);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// 5.5.1.4. Secret-Subkey Packet (Tag 7)
|
||||
/**
|
||||
* This function reads the payload of a secret key sub packet (Tag 7)
|
||||
* and initializes the openpgp_packet_keymaterial
|
||||
* @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 {openpgp_packet_keymaterial}
|
||||
*/
|
||||
function read_tag7(input, position, len) {
|
||||
this.tagType = 7;
|
||||
this.packetLength = len;
|
||||
return this.read_priv_key(input, position, len);
|
||||
}
|
||||
|
||||
// 5.5.1.2. Public-Subkey Packet (Tag 14)
|
||||
/**
|
||||
* This function reads the payload of a public key sub packet (Tag 14)
|
||||
* and initializes the openpgp_packet_keymaterial
|
||||
* @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 {openpgp_packet_keymaterial}
|
||||
*/
|
||||
function read_tag14(input, position, len) {
|
||||
this.subKeySignature = null;
|
||||
this.subKeyRevocationSignature = new Array();
|
||||
this.tagType = 14;
|
||||
this.packetLength = len;
|
||||
this.read_pub_key(input, position,len);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
function read_pub_key(input, position, len) {
|
||||
var mypos = position;
|
||||
// A one-octet version number (3 or 4).
|
||||
this.version = input.charCodeAt(mypos++);
|
||||
if (this.version == 3) {
|
||||
// A four-octet number denoting the time that the key was created.
|
||||
this.creationTime = new Date(((input.charCodeAt(mypos++) << 24) |
|
||||
(input.charCodeAt(mypos++) << 16) |
|
||||
(input.charCodeAt(mypos++) << 8) |
|
||||
(input.charCodeAt(mypos++)))*1000);
|
||||
|
||||
// - A two-octet number denoting the time in days that this key is
|
||||
// valid. If this number is zero, then it does not expire.
|
||||
this.expiration = (input.charCodeAt(mypos++) << 8) | input.charCodeAt(mypos++);
|
||||
|
||||
// - A one-octet number denoting the public-key algorithm of this key.
|
||||
this.publicKeyAlgorithm = input.charCodeAt(mypos++);
|
||||
var mpicount = 0;
|
||||
// - A series of multiprecision integers comprising the key material:
|
||||
// Algorithm-Specific Fields for RSA public keys:
|
||||
// - a multiprecision integer (MPI) of RSA public modulus n;
|
||||
// - an MPI of RSA public encryption exponent e.
|
||||
if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4)
|
||||
mpicount = 2;
|
||||
// Algorithm-Specific Fields for Elgamal public keys:
|
||||
// - MPI of Elgamal prime p;
|
||||
// - MPI of Elgamal group generator g;
|
||||
// - MPI of Elgamal public key value y (= g**x mod p where x is secret).
|
||||
|
||||
else if (this.publicKeyAlgorithm == 16)
|
||||
mpicount = 3;
|
||||
// Algorithm-Specific Fields for DSA public keys:
|
||||
// - MPI of DSA prime p;
|
||||
// - MPI of DSA group order q (q is a prime divisor of p-1);
|
||||
// - MPI of DSA group generator g;
|
||||
// - MPI of DSA public-key value y (= g**x mod p where x is secret).
|
||||
else if (this.publicKeyAlgorithm == 17)
|
||||
mpicount = 4;
|
||||
|
||||
this.MPIs = new Array();
|
||||
for (var i = 0; i < mpicount; i++) {
|
||||
this.MPIs[i] = new openpgp_type_mpi();
|
||||
if (this.MPIs[i].read(input, mypos, (mypos-position)) != null &&
|
||||
!this.packetLength < (mypos-position)) {
|
||||
mypos += this.MPIs[i].packetLength;
|
||||
} else {
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+'error reading MPI @:'+mypos);
|
||||
}
|
||||
}
|
||||
this.packetLength = mypos-position;
|
||||
} else if (this.version == 4) {
|
||||
// - A four-octet number denoting the time that the key was created.
|
||||
this.creationTime = new Date(((input.charCodeAt(mypos++) << 24) |
|
||||
(input.charCodeAt(mypos++) << 16) |
|
||||
(input.charCodeAt(mypos++) << 8) |
|
||||
(input.charCodeAt(mypos++)))*1000);
|
||||
|
||||
// - A one-octet number denoting the public-key algorithm of this key.
|
||||
this.publicKeyAlgorithm = input.charCodeAt(mypos++);
|
||||
var mpicount = 0;
|
||||
// - A series of multiprecision integers comprising the key material:
|
||||
// Algorithm-Specific Fields for RSA public keys:
|
||||
// - a multiprecision integer (MPI) of RSA public modulus n;
|
||||
// - an MPI of RSA public encryption exponent e.
|
||||
if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4)
|
||||
mpicount = 2;
|
||||
// Algorithm-Specific Fields for Elgamal public keys:
|
||||
// - MPI of Elgamal prime p;
|
||||
// - MPI of Elgamal group generator g;
|
||||
// - MPI of Elgamal public key value y (= g**x mod p where x is secret).
|
||||
else if (this.publicKeyAlgorithm == 16)
|
||||
mpicount = 3;
|
||||
|
||||
// Algorithm-Specific Fields for DSA public keys:
|
||||
// - MPI of DSA prime p;
|
||||
// - MPI of DSA group order q (q is a prime divisor of p-1);
|
||||
// - MPI of DSA group generator g;
|
||||
// - MPI of DSA public-key value y (= g**x mod p where x is secret).
|
||||
else if (this.publicKeyAlgorithm == 17)
|
||||
mpicount = 4;
|
||||
|
||||
this.MPIs = new Array();
|
||||
var i = 0;
|
||||
for (var i = 0; i < mpicount; i++) {
|
||||
this.MPIs[i] = new openpgp_type_mpi();
|
||||
if (this.MPIs[i].read(input, mypos, (mypos-position)) != null &&
|
||||
!this.packetLength < (mypos-position)) {
|
||||
mypos += this.MPIs[i].packetLength;
|
||||
} else {
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+'error reading MPI @:'+mypos);
|
||||
}
|
||||
}
|
||||
this.packetLength = mypos-position;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
this.data = input.substring(position, mypos);
|
||||
this.packetdata = input.substring(position, mypos);
|
||||
return this;
|
||||
}
|
||||
|
||||
// 5.5.3. Secret-Key Packet Formats
|
||||
|
||||
/**
|
||||
* Internal parser for private keys as specified in RFC 4880 section 5.5.3
|
||||
* @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
|
||||
*/
|
||||
function read_priv_key(input,position, len) {
|
||||
// - A Public-Key or Public-Subkey packet, as described above.
|
||||
this.publicKey = new openpgp_packet_keymaterial();
|
||||
if (this.publicKey.read_pub_key(input,position, len) == null) {
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+"Failed reading public key portion of a private key: "+input.charCodeAt(position)+" "+position+" "+len+"\n Aborting here...");
|
||||
return null;
|
||||
}
|
||||
this.publicKey.header = openpgp_packet.write_old_packet_header(6,this.publicKey.packetLength);
|
||||
// this.publicKey.header = String.fromCharCode(0x99) + String.fromCharCode(this.publicKey.packetLength >> 8 & 0xFF)+String.fromCharCode(this.publicKey.packetLength & 0xFF);
|
||||
var mypos = position + this.publicKey.data.length;
|
||||
this.packetLength = 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.
|
||||
this.s2kUsageConventions = input.charCodeAt(mypos++);
|
||||
|
||||
if (this.s2kUsageConventions == 0)
|
||||
this.hasUnencryptedSecretKeyData = true;
|
||||
|
||||
// - [Optional] If string-to-key usage octet was 255 or 254, a one-
|
||||
// octet symmetric encryption algorithm.
|
||||
if (this.s2kUsageConventions == 255 || this.s2kUsageConventions == 254) {
|
||||
this.symmetricEncryptionAlgorithm = input.charCodeAt(mypos++);
|
||||
}
|
||||
|
||||
// - [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.
|
||||
if (this.s2kUsageConventions == 255 || this.s2kUsageConventions == 254) {
|
||||
this.s2k = new openpgp_type_s2k();
|
||||
this.s2k.read(input, mypos);
|
||||
mypos +=this.s2k.s2kLength;
|
||||
}
|
||||
|
||||
// - [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.
|
||||
this.symkeylength = 0;
|
||||
if (this.s2kUsageConventions != 0 && this.s2kUsageConventions != 255 &&
|
||||
this.s2kUsageConventions != 254) {
|
||||
this.symmetricEncryptionAlgorithm = this.s2kUsageConventions;
|
||||
}
|
||||
if (this.s2kUsageConventions != 0 && this.s2k.type != 1001) {
|
||||
this.hasIV = true;
|
||||
switch (this.symmetricEncryptionAlgorithm) {
|
||||
case 1: // - IDEA [IDEA]
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+"symmetric encrytryption algorithim: IDEA is not implemented");
|
||||
return null;
|
||||
case 2: // - TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
|
||||
case 3: // - CAST5 (128 bit key, as per [RFC2144])
|
||||
this.IVLength = 8;
|
||||
break;
|
||||
case 4: // - Blowfish (128 bit key, 16 rounds) [BLOWFISH]
|
||||
case 7: // - AES with 128-bit key [AES]
|
||||
case 8: // - AES with 192-bit key
|
||||
case 9: // - AES with 256-bit key
|
||||
this.IVLength = 16;
|
||||
break;
|
||||
case 10: // - Twofish with 256-bit key [TWOFISH]
|
||||
this.IVLength = 32;
|
||||
break;
|
||||
case 5: // - Reserved
|
||||
case 6: // - Reserved
|
||||
default:
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+"unknown encryption algorithm for secret key :"+this.symmetricEncryptionAlgorithm);
|
||||
return null;
|
||||
}
|
||||
mypos++;
|
||||
this.IV = input.substring(mypos, mypos+this.IVLength);
|
||||
mypos += this.IVLength;
|
||||
}
|
||||
// - Plain or encrypted multiprecision integers comprising the secret
|
||||
// key data. These algorithm-specific fields are as described
|
||||
// below.
|
||||
|
||||
// s2k type 1001 corresponds to GPG specific extension without primary key secrets
|
||||
// http://www.gnupg.org/faq/GnuPG-FAQ.html#how-can-i-use-gnupg-in-an-automated-environment
|
||||
if (this.s2kUsageConventions != 0 && this.s2k.type == 1001) {
|
||||
this.secMPIs = null;
|
||||
this.encryptedMPIData = null;
|
||||
} else if (!this.hasUnencryptedSecretKeyData) {
|
||||
this.encryptedMPIData = input.substring(mypos, len);
|
||||
mypos += this.encryptedMPIData.length;
|
||||
} else {
|
||||
if (this.publicKey.publicKeyAlgorithm > 0 && this.publicKey.publicKeyAlgorithm < 4) {
|
||||
// Algorithm-Specific Fields for RSA secret keys:
|
||||
// - multiprecision integer (MPI) of RSA secret exponent d.
|
||||
// - MPI of RSA secret prime value p.
|
||||
// - MPI of RSA secret prime value q (p < q).
|
||||
// - MPI of u, the multiplicative inverse of p, mod q.
|
||||
this.secMPIs = new Array();
|
||||
this.secMPIs[0] = new openpgp_type_mpi();
|
||||
this.secMPIs[0].read(input, mypos, len-2- (mypos - position));
|
||||
mypos += this.secMPIs[0].packetLength;
|
||||
this.secMPIs[1] = new openpgp_type_mpi();
|
||||
this.secMPIs[1].read(input, mypos, len-2- (mypos - position));
|
||||
mypos += this.secMPIs[1].packetLength;
|
||||
this.secMPIs[2] = new openpgp_type_mpi();
|
||||
this.secMPIs[2].read(input, mypos, len-2- (mypos - position));
|
||||
mypos += this.secMPIs[2].packetLength;
|
||||
this.secMPIs[3] = new openpgp_type_mpi();
|
||||
this.secMPIs[3].read(input, mypos, len-2- (mypos - position));
|
||||
mypos += this.secMPIs[3].packetLength;
|
||||
} else if (this.publicKey.publicKeyAlgorithm == 16) {
|
||||
// Algorithm-Specific Fields for Elgamal secret keys:
|
||||
// - MPI of Elgamal secret exponent x.
|
||||
this.secMPIs = new Array();
|
||||
this.secMPIs[0] = new openpgp_type_mpi();
|
||||
this.secMPIs[0].read(input, mypos, len-2- (mypos - position));
|
||||
mypos += this.secMPIs[0].packetLength;
|
||||
} else if (this.publicKey.publicKeyAlgorithm == 17) {
|
||||
// Algorithm-Specific Fields for DSA secret keys:
|
||||
// - MPI of DSA secret exponent x.
|
||||
this.secMPIs = new Array();
|
||||
this.secMPIs[0] = new openpgp_type_mpi();
|
||||
this.secMPIs[0].read(input, mypos, len-2- (mypos - position));
|
||||
mypos += this.secMPIs[0].packetLength;
|
||||
}
|
||||
// checksum because s2k usage convention is 0
|
||||
this.checksum = new Array();
|
||||
this.checksum[0] = input.charCodeAt(mypos++);
|
||||
this.checksum[1] = input.charCodeAt(mypos++);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
function decryptSecretMPIs(str_passphrase) {
|
||||
if (this.hasUnencryptedSecretKeyData)
|
||||
return this.secMPIs;
|
||||
// creating a key out of the passphrase
|
||||
var key = this.s2k.produce_key(str_passphrase);
|
||||
var cleartextMPIs = "";
|
||||
switch (this.symmetricEncryptionAlgorithm) {
|
||||
case 1: // - IDEA [IDEA]
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+"symmetric encryption algorithim: IDEA is not implemented");
|
||||
return false;
|
||||
case 2: // - TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
|
||||
cleartextMPIs = normal_cfb_decrypt(function(block, key) {
|
||||
return des(key, block,1,null,0);
|
||||
}, this.IVLength, key, this.encryptedMPIData, this.IV);
|
||||
break;
|
||||
case 3: // - CAST5 (128 bit key, as per [RFC2144])
|
||||
cleartextMPIs = normal_cfb_decrypt(function(block, key) {
|
||||
var cast5 = new openpgp_symenc_cast5();
|
||||
cast5.setKey(key);
|
||||
return cast5.encrypt(util.str2bin(block));
|
||||
}, this.IVLength, util.str2bin(key.substring(0,16)), this.encryptedMPIData, this.IV);
|
||||
break;
|
||||
case 4: // - Blowfish (128 bit key, 16 rounds) [BLOWFISH]
|
||||
cleartextMPIs = normal_cfb_decrypt(function(block, key) {
|
||||
var blowfish = new Blowfish(key);
|
||||
return blowfish.encrypt(block);
|
||||
}, this.IVLength, key, this.encryptedMPIData, this.IV);
|
||||
break;
|
||||
case 7: // - AES with 128-bit key [AES]
|
||||
case 8: // - AES with 192-bit key
|
||||
case 9: // - AES with 256-bit key
|
||||
var numBytes = 16;
|
||||
//This is a weird way to achieve this. If's within a switch is probably not ideal.
|
||||
if(this.symmetricEncryptionAlgorithm == 8){
|
||||
numBytes = 24;
|
||||
key = this.s2k.produce_key(str_passphrase,numBytes);
|
||||
}
|
||||
if(this.symmetricEncryptionAlgorithm == 9){
|
||||
numBytes = 32;
|
||||
key = this.s2k.produce_key(str_passphrase,numBytes);
|
||||
}
|
||||
cleartextMPIs = normal_cfb_decrypt(function(block,key){
|
||||
return AESencrypt(util.str2bin(block),key);
|
||||
},
|
||||
this.IVLength, keyExpansion(key.substring(0,numBytes)), this.encryptedMPIData, this.IV);
|
||||
break;
|
||||
case 10: // - Twofish with 256-bit key [TWOFISH]
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+"Key material is encrypted with twofish: not implemented");
|
||||
return false;
|
||||
case 5: // - Reserved
|
||||
case 6: // - Reserved
|
||||
default:
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+"unknown encryption algorithm for secret key :"+this.symmetricEncryptionAlgorithm);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cleartextMPIs == null) {
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+"cleartextMPIs was null");
|
||||
return false;
|
||||
}
|
||||
|
||||
var cleartextMPIslength = cleartextMPIs.length;
|
||||
|
||||
if (this.s2kUsageConventions == 254 &&
|
||||
str_sha1(cleartextMPIs.substring(0,cleartextMPIs.length - 20)) ==
|
||||
cleartextMPIs.substring(cleartextMPIs.length - 20)) {
|
||||
cleartextMPIslength -= 20;
|
||||
} else if (this.s2kUsageConventions != 254 && util.calc_checksum(cleartextMPIs.substring(0,cleartextMPIs.length - 2)) ==
|
||||
(cleartextMPIs.charCodeAt(cleartextMPIs.length -2) << 8 | cleartextMPIs.charCodeAt(cleartextMPIs.length -1))) {
|
||||
cleartextMPIslength -= 2;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.publicKey.publicKeyAlgorithm > 0 && this.publicKey.publicKeyAlgorithm < 4) {
|
||||
// Algorithm-Specific Fields for RSA secret keys:
|
||||
// - multiprecision integer (MPI) of RSA secret exponent d.
|
||||
// - MPI of RSA secret prime value p.
|
||||
// - MPI of RSA secret prime value q (p < q).
|
||||
// - MPI of u, the multiplicative inverse of p, mod q.
|
||||
var mypos = 0;
|
||||
this.secMPIs = new Array();
|
||||
this.secMPIs[0] = new openpgp_type_mpi();
|
||||
this.secMPIs[0].read(cleartextMPIs, 0, cleartextMPIslength);
|
||||
mypos += this.secMPIs[0].packetLength;
|
||||
this.secMPIs[1] = new openpgp_type_mpi();
|
||||
this.secMPIs[1].read(cleartextMPIs, mypos, cleartextMPIslength-mypos);
|
||||
mypos += this.secMPIs[1].packetLength;
|
||||
this.secMPIs[2] = new openpgp_type_mpi();
|
||||
this.secMPIs[2].read(cleartextMPIs, mypos, cleartextMPIslength-mypos);
|
||||
mypos += this.secMPIs[2].packetLength;
|
||||
this.secMPIs[3] = new openpgp_type_mpi();
|
||||
this.secMPIs[3].read(cleartextMPIs, mypos, cleartextMPIslength-mypos);
|
||||
mypos += this.secMPIs[3].packetLength;
|
||||
} else if (this.publicKey.publicKeyAlgorithm == 16) {
|
||||
// Algorithm-Specific Fields for Elgamal secret keys:
|
||||
// - MPI of Elgamal secret exponent x.
|
||||
this.secMPIs = new Array();
|
||||
this.secMPIs[0] = new openpgp_type_mpi();
|
||||
this.secMPIs[0].read(cleartextMPIs, 0, cleartextMPIs);
|
||||
} else if (this.publicKey.publicKeyAlgorithm == 17) {
|
||||
// Algorithm-Specific Fields for DSA secret keys:
|
||||
// - MPI of DSA secret exponent x.
|
||||
this.secMPIs = new Array();
|
||||
this.secMPIs[0] = new openpgp_type_mpi();
|
||||
this.secMPIs[0].read(cleartextMPIs, 0, cleartextMPIslength);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates Debug output
|
||||
* @return String which gives some information about the keymaterial
|
||||
*/
|
||||
function toString() {
|
||||
var result = "";
|
||||
switch (this.tagType) {
|
||||
case 6:
|
||||
result += '5.5.1.1. Public-Key Packet (Tag 6)\n'+
|
||||
' length: '+this.packetLength+'\n'+
|
||||
' version: '+this.version+'\n'+
|
||||
' creation time: '+this.creationTime+'\n'+
|
||||
' expiration time: '+this.expiration+'\n'+
|
||||
' publicKeyAlgorithm: '+this.publicKeyAlgorithm+'\n';
|
||||
break;
|
||||
case 14:
|
||||
result += '5.5.1.2. Public-Subkey Packet (Tag 14)\n'+
|
||||
' length: '+this.packetLength+'\n'+
|
||||
' version: '+this.version+'\n'+
|
||||
' creation time: '+this.creationTime+'\n'+
|
||||
' expiration time: '+this.expiration+'\n'+
|
||||
' publicKeyAlgorithm: '+this.publicKeyAlgorithm+'\n';
|
||||
break;
|
||||
case 5:
|
||||
result +='5.5.1.3. Secret-Key Packet (Tag 5)\n'+
|
||||
' length: '+this.packetLength+'\n'+
|
||||
' version: '+this.publicKey.version+'\n'+
|
||||
' creation time: '+this.publicKey.creationTime+'\n'+
|
||||
' expiration time: '+this.publicKey.expiration+'\n'+
|
||||
' publicKeyAlgorithm: '+this.publicKey.publicKeyAlgorithm+'\n';
|
||||
break;
|
||||
case 7:
|
||||
result += '5.5.1.4. Secret-Subkey Packet (Tag 7)\n'+
|
||||
' length: '+this.packetLength+'\n'+
|
||||
' version[1]: '+(this.version == 4)+'\n'+
|
||||
' creationtime[4]: '+this.creationTime+'\n'+
|
||||
' expiration[2]: '+this.expiration+'\n'+
|
||||
' publicKeyAlgorithm: '+this.publicKeyAlgorithm+'\n';
|
||||
break;
|
||||
default:
|
||||
result += 'unknown key material packet\n';
|
||||
}
|
||||
if (this.MPIs != null) {
|
||||
result += "Public Key MPIs:\n";
|
||||
for (var i = 0; i < this.MPIs.length; i++) {
|
||||
result += this.MPIs[i].toString();
|
||||
}
|
||||
}
|
||||
if (this.publicKey != null && this.publicKey.MPIs != null) {
|
||||
result += "Public Key MPIs:\n";
|
||||
for (var i = 0; i < this.publicKey.MPIs.length; i++) {
|
||||
result += this.publicKey.MPIs[i].toString();
|
||||
}
|
||||
}
|
||||
if (this.secMPIs != null) {
|
||||
result += "Secret Key MPIs:\n";
|
||||
for (var i = 0; i < this.secMPIs.length; i++) {
|
||||
result += this.secMPIs[i].toString();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.subKeySignature != null)
|
||||
result += "subKey Signature:\n"+this.subKeySignature.toString();
|
||||
|
||||
if (this.subKeyRevocationSignature != null )
|
||||
result += "subKey Revocation Signature:\n"+this.subKeyRevocationSignature.toString();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Continue parsing packets belonging to the key material such as signatures
|
||||
* @param {Object} parent_node The parent object
|
||||
* @param {String} input Input string to read the packet(s) from
|
||||
* @param {Integer} position Start position for the parser
|
||||
* @param {Integer} len Length of the packet(s) or remaining length of input
|
||||
* @return {Integer} Length of nodes read
|
||||
*/
|
||||
function read_nodes(parent_node, input, position, len) {
|
||||
this.parentNode = parent_node;
|
||||
if (this.tagType == 14) { // public sub-key packet
|
||||
var pos = position;
|
||||
var result = null;
|
||||
while (input.length != pos) {
|
||||
var l = input.length - pos;
|
||||
result = openpgp_packet.read_packet(input, pos, l);
|
||||
if (result == null) {
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+'[user_keymat_pub]parsing ends here @:' + pos + " l:" + l);
|
||||
break;
|
||||
} else {
|
||||
|
||||
switch (result.tagType) {
|
||||
case 2: // Signature Packet certification signature
|
||||
if (result.signatureType == 24) { // subkey binding signature
|
||||
this.subKeySignature = result;
|
||||
pos += result.packetLength + result.headerLength;
|
||||
break;
|
||||
} else if (result.signatureType == 40) { // subkey revocation signature
|
||||
this.subKeyRevocationSignature[this.subKeyRevocationSignature.length] = result;
|
||||
pos += result.packetLength + result.headerLength;
|
||||
break;
|
||||
} else {
|
||||
util.print_error("openpgp.packet.keymaterial.js\nunknown signature:"+result.toString());
|
||||
}
|
||||
|
||||
default:
|
||||
this.data = input;
|
||||
this.position = position - this.parentNode.packetLength;
|
||||
this.len = pos - position;
|
||||
return this.len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.data = input;
|
||||
this.position = position - this.parentNode.packetLength;
|
||||
this.len = pos - position;
|
||||
return this.len;
|
||||
} else if (this.tagType == 7) { // private sub-key packet
|
||||
var pos = position;
|
||||
while (input.length != pos) {
|
||||
var result = openpgp_packet.read_packet(input, pos, len - (pos - position));
|
||||
if (result == null) {
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+'[user_keymat_priv] parsing ends here @:' + pos);
|
||||
break;
|
||||
} else {
|
||||
switch (result.tagType) {
|
||||
case 2: // Signature Packet certification signature
|
||||
if (result.signatureType == 24) // subkey embedded signature
|
||||
this.subKeySignature = result;
|
||||
else if (result.signatureType == 40) // subkey revocation signature
|
||||
this.subKeyRevocationSignature[this.subKeyRevocationSignature.length] = result;
|
||||
pos += result.packetLength + result.headerLength;
|
||||
break;
|
||||
default:
|
||||
this.data = input;
|
||||
this.position = position - this.parentNode.packetLength;
|
||||
this.len = pos - position;
|
||||
return this.len;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.data = input;
|
||||
this.position = position - this.parentNode.packetLength;
|
||||
this.len = pos - position;
|
||||
return this.len;
|
||||
} else {
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+"unknown parent node for a key material packet "+parent_node.tagType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the validity for usage of this (sub)key
|
||||
* @return {Integer} 0 = bad key, 1 = expired, 2 = revoked, 3 = valid
|
||||
*/
|
||||
function verifyKey() {
|
||||
if (this.tagType == 14) {
|
||||
if (this.subKeySignature == null) {
|
||||
return 0;
|
||||
}
|
||||
if (this.subKeySignature.version == 4 &&
|
||||
this.subKeySignature.keyNeverExpires != null &&
|
||||
!this.subKeySignature.keyNeverExpires &&
|
||||
new Date((this.subKeySignature.keyExpirationTime*1000)+ this.creationTime.getTime()) < new Date()) {
|
||||
return 1;
|
||||
}
|
||||
var hashdata = String.fromCharCode(0x99)+this.parentNode.header.substring(1)+this.parentNode.data+
|
||||
String.fromCharCode(0x99)+this.header.substring(1)+this.packetdata;
|
||||
if (!this.subKeySignature.verify(hashdata,this.parentNode)) {
|
||||
return 0;
|
||||
}
|
||||
for (var i = 0; i < this.subKeyRevocationSignature.length; i++) {
|
||||
if (this.getKeyId() == this.subKeyRevocationSignature[i].keyId){
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the key id of they key
|
||||
* @return {String} A 8 byte key id
|
||||
*/
|
||||
function getKeyId() {
|
||||
if (this.version == 4) {
|
||||
var f = this.getFingerprint();
|
||||
return f.substring(12,20);
|
||||
} else if (this.version == 3 && this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4) {
|
||||
var key_id = this.MPIs[0].MPI.substring((this.MPIs[0].mpiByteLength-8));
|
||||
util.print_debug("openpgp.msg.publickey read_nodes:\n"+"V3 key ID: "+key_id);
|
||||
return key_id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the fingerprint of the key
|
||||
* @return {String} A string containing the fingerprint
|
||||
*/
|
||||
function getFingerprint() {
|
||||
if (this.version == 4) {
|
||||
tohash = String.fromCharCode(0x99)+ String.fromCharCode(((this.packetdata.length) >> 8) & 0xFF)
|
||||
+ String.fromCharCode((this.packetdata.length) & 0xFF)+this.packetdata;
|
||||
util.print_debug("openpgp.msg.publickey creating subkey fingerprint by hashing:"+util.hexstrdump(tohash)+"\npublickeyalgorithm: "+this.publicKeyAlgorithm);
|
||||
return str_sha1(tohash, tohash.length);
|
||||
} else if (this.version == 3 && this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4) {
|
||||
return MD5(this.MPIs[0].MPI);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 password
|
||||
* @param s2kHash
|
||||
* @param symmetricEncryptionAlgorithm
|
||||
* @param timePacket
|
||||
* @return {Object} {body: [string]OpenPGP packet body contents,
|
||||
header: [string] OpenPGP packet header, string: [string] header+body}
|
||||
*/
|
||||
function write_private_key(keyType, key, password, s2kHash, symmetricEncryptionAlgorithm, timePacket){
|
||||
this.symmetricEncryptionAlgorithm = symmetricEncryptionAlgorithm;
|
||||
var tag = 5;
|
||||
var body = String.fromCharCode(4);
|
||||
body += timePacket;
|
||||
switch(keyType){
|
||||
case 1:
|
||||
body += String.fromCharCode(keyType);//public key algo
|
||||
body += key.n.toMPI();
|
||||
body += key.ee.toMPI();
|
||||
var algorithmStart = body.length;
|
||||
//below shows ske/s2k
|
||||
if(password){
|
||||
body += String.fromCharCode(254); //octet of 254 indicates s2k with SHA1
|
||||
//if s2k == 255,254 then 1 octet symmetric encryption algo
|
||||
body += String.fromCharCode(this.symmetricEncryptionAlgorithm);
|
||||
//if s2k == 255,254 then s2k specifier
|
||||
body += String.fromCharCode(3); //s2k salt+iter
|
||||
body += String.fromCharCode(s2kHash);
|
||||
//8 octet salt value
|
||||
//1 octet count
|
||||
var cleartextMPIs = key.d.toMPI() + key.p.toMPI() + key.q.toMPI() + key.u.toMPI();
|
||||
var sha1Hash = str_sha1(cleartextMPIs);
|
||||
util.print_debug_hexstr_dump('write_private_key sha1: ',sha1Hash);
|
||||
var salt = openpgp_crypto_getRandomBytes(8);
|
||||
util.print_debug_hexstr_dump('write_private_key Salt: ',salt);
|
||||
body += salt;
|
||||
var c = 96; //c of 96 translates to count of 65536
|
||||
body += String.fromCharCode(c);
|
||||
util.print_debug('write_private_key c: '+ c);
|
||||
var s2k = new openpgp_type_s2k();
|
||||
var hashKey = s2k.write(3, s2kHash, password, salt, c);
|
||||
//if s2k, IV of same length as cipher's block
|
||||
switch(this.symmetricEncryptionAlgorithm){
|
||||
case 3:
|
||||
this.IVLength = 8;
|
||||
this.IV = openpgp_crypto_getRandomBytes(this.IVLength);
|
||||
ciphertextMPIs = normal_cfb_encrypt(function(block, key) {
|
||||
var cast5 = new openpgp_symenc_cast5();
|
||||
cast5.setKey(key);
|
||||
return cast5.encrypt(util.str2bin(block));
|
||||
}, this.IVLength, util.str2bin(hashKey.substring(0,16)), cleartextMPIs + sha1Hash, this.IV);
|
||||
body += this.IV + ciphertextMPIs;
|
||||
break;
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
this.IVLength = 16;
|
||||
this.IV = openpgp_crypto_getRandomBytes(this.IVLength);
|
||||
ciphertextMPIs = normal_cfb_encrypt(AESencrypt,
|
||||
this.IVLength, hashKey, cleartextMPIs + sha1Hash, this.IV);
|
||||
body += this.IV + ciphertextMPIs;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else{
|
||||
body += String.fromCharCode(0);//1 octet -- s2k, 0 for no s2k
|
||||
body += key.d.toMPI() + key.p.toMPI() + key.q.toMPI() + key.u.toMPI();
|
||||
var checksum = util.calc_checksum(key.d.toMPI() + key.p.toMPI() + key.q.toMPI() + key.u.toMPI());
|
||||
body += String.fromCharCode(checksum/0x100) + String.fromCharCode(checksum%0x100);//DEPRECATED:s2k == 0, 255: 2 octet checksum, sum all octets%65536
|
||||
util.print_debug_hexstr_dump('write_private_key basic checksum: '+ checksum);
|
||||
}
|
||||
break;
|
||||
default :
|
||||
body = "";
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+'error writing private key, unknown type :'+keyType);
|
||||
}
|
||||
var header = openpgp_packet.write_packet_header(tag,body.length);
|
||||
return {string: header+body , header: header, body: body};
|
||||
}
|
||||
|
||||
/*
|
||||
* 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}
|
||||
*/
|
||||
function write_public_key(keyType, key, timePacket){
|
||||
var tag = 6;
|
||||
var body = String.fromCharCode(4);
|
||||
body += timePacket;
|
||||
switch(keyType){
|
||||
case 1:
|
||||
body += String.fromCharCode(1);//public key algo
|
||||
body += key.n.toMPI();
|
||||
body += key.ee.toMPI();
|
||||
break;
|
||||
default:
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+'error writing private key, unknown type :'+keyType);
|
||||
}
|
||||
var header = openpgp_packet.write_packet_header(tag,body.length);
|
||||
return {string: header+body , header: header, body: body};
|
||||
}
|
||||
|
||||
|
||||
this.read_tag5 = read_tag5;
|
||||
this.read_tag6 = read_tag6;
|
||||
this.read_tag7 = read_tag7;
|
||||
this.read_tag14 = read_tag14;
|
||||
this.toString = toString;
|
||||
this.read_pub_key = read_pub_key;
|
||||
this.read_priv_key = read_priv_key;
|
||||
this.decryptSecretMPIs = decryptSecretMPIs;
|
||||
this.read_nodes = read_nodes;
|
||||
this.verifyKey = verifyKey;
|
||||
this.getKeyId = getKeyId;
|
||||
this.getFingerprint = getFingerprint;
|
||||
this.write_private_key = write_private_key;
|
||||
this.write_public_key = write_public_key;
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @classdesc Implementation of the 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 openpgp_packet_marker() {
|
||||
this.tagType = 10;
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
function read_packet(input, position, len) {
|
||||
this.packetLength = 3;
|
||||
if (input.charCodeAt(position) == 0x50 && // P
|
||||
input.charCodeAt(position + 1) == 0x47 && // G
|
||||
input.charCodeAt(position + 2) == 0x50) // P
|
||||
return this;
|
||||
// marker packet does not contain "PGP"
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates Debug output
|
||||
*
|
||||
* @return {String} String which gives some information about the
|
||||
* keymaterial
|
||||
*/
|
||||
function toString() {
|
||||
return "5.8. Marker Packet (Obsolete Literal Packet) (Tag 10)\n"
|
||||
+ " packet reads: \"PGP\"\n";
|
||||
}
|
||||
|
||||
this.read_packet = read_packet;
|
||||
this.toString = toString;
|
||||
}
|
|
@ -1,744 +0,0 @@
|
|||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @classdesc Implementation of the 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.
|
||||
*/
|
||||
function openpgp_packet_signature() {
|
||||
this.tagType = 2;
|
||||
this.signatureType = null;
|
||||
this.creationTime = null;
|
||||
this.keyId = null;
|
||||
this.signatureData = null;
|
||||
this.signatureExpirationTime = null;
|
||||
this.signatureNeverExpires = null;
|
||||
this.signedHashValue = null;
|
||||
this.MPIs = null;
|
||||
this.publicKeyAlgorithm = null;
|
||||
this.hashAlgorithm = null;
|
||||
this.exportable = null;
|
||||
this.trustLevel = null;
|
||||
this.trustAmount = null;
|
||||
this.regular_expression = 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.notationFlags = null;
|
||||
this.notationName = null;
|
||||
this.notationValue = null;
|
||||
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} input payload of a tag 2 packet
|
||||
* @param {Integer} position position to start reading from the input string
|
||||
* @param {Integer} len length of the packet or the remaining length of input at position
|
||||
* @return {openpgp_packet_encrypteddata} object representation
|
||||
*/
|
||||
function read_packet(input, position, len) {
|
||||
this.data = input.substring (position, position+len);
|
||||
if (len < 0) {
|
||||
util.print_debug("openpgp.packet.signature.js\n"+"openpgp_packet_signature read_packet length < 0 @:"+position);
|
||||
return null;
|
||||
}
|
||||
var mypos = position;
|
||||
this.packetLength = len;
|
||||
// alert('starting parsing signature: '+position+' '+this.packetLength);
|
||||
this.version = input.charCodeAt(mypos++);
|
||||
// switch on version (3 and 4)
|
||||
switch (this.version) {
|
||||
case 3:
|
||||
// One-octet length of following hashed material. MUST be 5.
|
||||
if (input.charCodeAt(mypos++) != 5)
|
||||
util.print_debug("openpgp.packet.signature.js\n"+'invalid One-octet length of following hashed material. MUST be 5. @:'+(mypos-1));
|
||||
var sigpos = mypos;
|
||||
// One-octet signature type.
|
||||
this.signatureType = input.charCodeAt(mypos++);
|
||||
|
||||
// Four-octet creation time.
|
||||
this.creationTime = new Date(((input.charCodeAt(mypos++)) << 24 |
|
||||
(input.charCodeAt(mypos++) << 16) | (input.charCodeAt(mypos++) << 8) |
|
||||
input.charCodeAt(mypos++))* 1000);
|
||||
|
||||
// storing data appended to data which gets verified
|
||||
this.signatureData = input.substring(sigpos, mypos);
|
||||
|
||||
// Eight-octet Key ID of signer.
|
||||
this.keyId = input.substring(mypos, mypos +8);
|
||||
mypos += 8;
|
||||
|
||||
// One-octet public-key algorithm.
|
||||
this.publicKeyAlgorithm = input.charCodeAt(mypos++);
|
||||
|
||||
// One-octet hash algorithm.
|
||||
this.hashAlgorithm = input.charCodeAt(mypos++);
|
||||
|
||||
// Two-octet field holding left 16 bits of signed hash value.
|
||||
this.signedHashValue = (input.charCodeAt(mypos++) << 8) | input.charCodeAt(mypos++);
|
||||
var mpicount = 0;
|
||||
// Algorithm-Specific Fields for RSA signatures:
|
||||
// - multiprecision integer (MPI) of RSA signature value m**d mod n.
|
||||
if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4)
|
||||
mpicount = 1;
|
||||
// Algorithm-Specific Fields for DSA signatures:
|
||||
// - MPI of DSA value r.
|
||||
// - MPI of DSA value s.
|
||||
else if (this.publicKeyAlgorithm == 17)
|
||||
mpicount = 2;
|
||||
|
||||
this.MPIs = new Array();
|
||||
for (var i = 0; i < mpicount; i++) {
|
||||
this.MPIs[i] = new openpgp_type_mpi();
|
||||
if (this.MPIs[i].read(input, mypos, (mypos-position)) != null &&
|
||||
!this.packetLength < (mypos-position)) {
|
||||
mypos += this.MPIs[i].packetLength;
|
||||
} else {
|
||||
util.print_error('signature contains invalid MPI @:'+mypos);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
this.signatureType = input.charCodeAt(mypos++);
|
||||
this.publicKeyAlgorithm = input.charCodeAt(mypos++);
|
||||
this.hashAlgorithm = input.charCodeAt(mypos++);
|
||||
|
||||
// Two-octet scalar octet count for following hashed subpacket
|
||||
// data.
|
||||
var hashed_subpacket_count = (input.charCodeAt(mypos++) << 8) + input.charCodeAt(mypos++);
|
||||
|
||||
// Hashed subpacket data set (zero or more subpackets)
|
||||
var subpacket_length = 0;
|
||||
while (hashed_subpacket_count != subpacket_length) {
|
||||
if (hashed_subpacket_count < subpacket_length) {
|
||||
util.print_debug("openpgp.packet.signature.js\n"+"hashed missed something: "+mypos+" c:"+hashed_subpacket_count+" l:"+subpacket_length);
|
||||
}
|
||||
|
||||
subpacket_length += this._raw_read_signature_sub_packet(input,
|
||||
mypos + subpacket_length, hashed_subpacket_count
|
||||
- subpacket_length);
|
||||
}
|
||||
|
||||
mypos += hashed_subpacket_count;
|
||||
this.signatureData = input.substring(position, mypos);
|
||||
|
||||
// alert("signatureData: "+util.hexstrdump(this.signatureData));
|
||||
|
||||
// Two-octet scalar octet count for the following unhashed subpacket
|
||||
var subpacket_count = (input.charCodeAt(mypos++) << 8) + input.charCodeAt(mypos++);
|
||||
|
||||
// Unhashed subpacket data set (zero or more subpackets).
|
||||
subpacket_length = 0;
|
||||
while (subpacket_count != subpacket_length) {
|
||||
if (subpacket_count < subpacket_length) {
|
||||
util.print_debug("openpgp.packet.signature.js\n"+"missed something: "+subpacket_length+" c:"+subpacket_count+" "+" l:"+subpacket_length);
|
||||
}
|
||||
subpacket_length += this._raw_read_signature_sub_packet(input,
|
||||
mypos + subpacket_length, subpacket_count
|
||||
- subpacket_length);
|
||||
|
||||
}
|
||||
mypos += subpacket_count;
|
||||
// Two-octet field holding the left 16 bits of the signed hash
|
||||
// value.
|
||||
this.signedHashValue = (input.charCodeAt(mypos++) << 8) | input.charCodeAt(mypos++);
|
||||
// One or more multiprecision integers comprising the signature.
|
||||
// This portion is algorithm specific, as described above.
|
||||
var mpicount = 0;
|
||||
if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4)
|
||||
mpicount = 1;
|
||||
else if (this.publicKeyAlgorithm == 17)
|
||||
mpicount = 2;
|
||||
|
||||
this.MPIs = new Array();
|
||||
for (var i = 0; i < mpicount; i++) {
|
||||
this.MPIs[i] = new openpgp_type_mpi();
|
||||
if (this.MPIs[i].read(input, mypos, (mypos-position)) != null &&
|
||||
!this.packetLength < (mypos-position)) {
|
||||
mypos += this.MPIs[i].packetLength;
|
||||
} else {
|
||||
util.print_error('signature contains invalid MPI @:'+mypos);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
util.print_error("openpgp.packet.signature.js\n"+'unknown signature packet version'+this.version);
|
||||
break;
|
||||
}
|
||||
// util.print_message("openpgp.packet.signature.js\n"+"end signature: l: "+this.packetLength+"m: "+mypos+" m-p: "+(mypos-position));
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* creates a string representation of a message signature packet (tag 2).
|
||||
* This can be only used on text data
|
||||
* @param {Integer} signature_type should be 1 (one)
|
||||
* @param {String} data data to be signed
|
||||
* @param {openpgp_msg_privatekey} privatekey private key used to sign the message. (secMPIs MUST be unlocked)
|
||||
* @return {String} string representation of a signature packet
|
||||
*/
|
||||
function write_message_signature(signature_type, data, privatekey) {
|
||||
var publickey = privatekey.privateKeyPacket.publicKey;
|
||||
var hash_algo = privatekey.getPreferredSignatureHashAlgorithm();
|
||||
var result = String.fromCharCode(4);
|
||||
result += String.fromCharCode(signature_type);
|
||||
result += String.fromCharCode(publickey.publicKeyAlgorithm);
|
||||
result += String.fromCharCode(hash_algo);
|
||||
var d = Math.round(new Date().getTime() / 1000);
|
||||
var datesubpacket = write_sub_signature_packet(2,""+
|
||||
String.fromCharCode((d >> 24) & 0xFF) +
|
||||
String.fromCharCode((d >> 16) & 0xFF) +
|
||||
String.fromCharCode((d >> 8) & 0xFF) +
|
||||
String.fromCharCode(d & 0xFF));
|
||||
var issuersubpacket = write_sub_signature_packet(16, privatekey.getKeyId());
|
||||
result += String.fromCharCode(((datesubpacket.length + issuersubpacket.length) >> 8) & 0xFF);
|
||||
result += String.fromCharCode ((datesubpacket.length + issuersubpacket.length) & 0xFF);
|
||||
result += datesubpacket;
|
||||
result += issuersubpacket;
|
||||
var trailer = '';
|
||||
|
||||
trailer += String.fromCharCode(4);
|
||||
trailer += String.fromCharCode(0xFF);
|
||||
trailer += String.fromCharCode((result.length) >> 24);
|
||||
trailer += String.fromCharCode(((result.length) >> 16) & 0xFF);
|
||||
trailer += String.fromCharCode(((result.length) >> 8) & 0xFF);
|
||||
trailer += String.fromCharCode((result.length) & 0xFF);
|
||||
var result2 = String.fromCharCode(0);
|
||||
result2 += String.fromCharCode(0);
|
||||
var hash = openpgp_crypto_hashData(hash_algo, data+result+trailer);
|
||||
util.print_debug("DSA Signature is calculated with:|"+data+result+trailer+"|\n"+util.hexstrdump(data+result+trailer)+"\n hash:"+util.hexstrdump(hash));
|
||||
result2 += hash.charAt(0);
|
||||
result2 += hash.charAt(1);
|
||||
result2 += openpgp_crypto_signData(hash_algo,privatekey.privateKeyPacket.publicKey.publicKeyAlgorithm,
|
||||
publickey.MPIs,
|
||||
privatekey.privateKeyPacket.secMPIs,
|
||||
data+result+trailer);
|
||||
return {openpgp: (openpgp_packet.write_packet_header(2, (result+result2).length)+result + result2),
|
||||
hash: util.get_hashAlgorithmString(hash_algo)};
|
||||
}
|
||||
/**
|
||||
* 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_signature_packet(type, data) {
|
||||
var result = "";
|
||||
result += openpgp_packet.encode_length(data.length+1);
|
||||
result += String.fromCharCode(type);
|
||||
result += data;
|
||||
return result;
|
||||
}
|
||||
|
||||
// V4 signature sub packets
|
||||
|
||||
this._raw_read_signature_sub_packet = function(input, position, len) {
|
||||
if (len < 0)
|
||||
util.print_debug("openpgp.packet.signature.js\n"+"_raw_read_signature_sub_packet length < 0 @:"+position);
|
||||
var mypos = position;
|
||||
var subplen = 0;
|
||||
// alert('starting signature subpackage read at position:'+position+' length:'+len);
|
||||
if (input.charCodeAt(mypos) < 192) {
|
||||
subplen = input.charCodeAt(mypos++);
|
||||
} else if (input.charCodeAt(mypos) >= 192 && input.charCodeAt(mypos) < 224) {
|
||||
subplen = ((input.charCodeAt(mypos++) - 192) << 8) + (input.charCodeAt(mypos++)) + 192;
|
||||
} else if (input.charCodeAt(mypos) > 223 && input.charCodeAt(mypos) < 255) {
|
||||
subplen = 1 << (input.charCodeAt(mypos++) & 0x1F);
|
||||
} else if (input.charCodeAt(mypos) < 255) {
|
||||
mypos++;
|
||||
subplen = (input.charCodeAt(mypos++) << 24) | (input.charCodeAt(mypos++) << 16)
|
||||
| (input.charCodeAt(mypos++) << 8) | input.charCodeAt(mypos++);
|
||||
}
|
||||
|
||||
var type = input.charCodeAt(mypos++) & 0x7F;
|
||||
// alert('signature subpacket type '+type+" with length: "+subplen);
|
||||
// subpacket type
|
||||
switch (type) {
|
||||
case 2: // Signature Creation Time
|
||||
this.creationTime = new Date(((input.charCodeAt(mypos++) << 24) | (input.charCodeAt(mypos++) << 16)
|
||||
| (input.charCodeAt(mypos++) << 8) | input.charCodeAt(mypos++))*1000);
|
||||
break;
|
||||
case 3: // Signature Expiration Time
|
||||
this.signatureExpirationTime = (input.charCodeAt(mypos++) << 24)
|
||||
| (input.charCodeAt(mypos++) << 16) | (input.charCodeAt(mypos++) << 8)
|
||||
| input.charCodeAt(mypos++);
|
||||
this.signatureNeverExpires = (this.signature_expiration_time == 0);
|
||||
|
||||
break;
|
||||
case 4: // Exportable Certification
|
||||
this.exportable = input.charCodeAt(mypos++) == 1;
|
||||
break;
|
||||
case 5: // Trust Signature
|
||||
this.trustLevel = input.charCodeAt(mypos++);
|
||||
this.trustAmount = input.charCodeAt(mypos++);
|
||||
break;
|
||||
case 6: // Regular Expression
|
||||
this.regular_expression = new String();
|
||||
for (var i = 0; i < subplen - 1; i++)
|
||||
this.regular_expression += (input[mypos++]);
|
||||
break;
|
||||
case 7: // Revocable
|
||||
this.revocable = input.charCodeAt(mypos++) == 1;
|
||||
break;
|
||||
case 9: // Key Expiration Time
|
||||
this.keyExpirationTime = (input.charCodeAt(mypos++) << 24)
|
||||
| (input.charCodeAt(mypos++) << 16) | (input.charCodeAt(mypos++) << 8)
|
||||
| input.charCodeAt(mypos++);
|
||||
this.keyNeverExpires = (this.keyExpirationTime == 0);
|
||||
break;
|
||||
case 11: // Preferred Symmetric Algorithms
|
||||
this.preferredSymmetricAlgorithms = new Array();
|
||||
for (var i = 0; i < subplen-1; i++) {
|
||||
this.preferredSymmetricAlgorithms = input.charCodeAt(mypos++);
|
||||
}
|
||||
break;
|
||||
case 12: // Revocation Key
|
||||
// (1 octet of class, 1 octet of public-key algorithm ID, 20
|
||||
// octets of
|
||||
// fingerprint)
|
||||
this.revocationKeyClass = input.charCodeAt(mypos++);
|
||||
this.revocationKeyAlgorithm = input.charCodeAt(mypos++);
|
||||
this.revocationKeyFingerprint = new Array();
|
||||
for ( var i = 0; i < 20; i++) {
|
||||
this.revocationKeyFingerprint = input.charCodeAt(mypos++);
|
||||
}
|
||||
break;
|
||||
case 16: // Issuer
|
||||
this.issuerKeyId = input.substring(mypos,mypos+8);
|
||||
mypos += 8;
|
||||
break;
|
||||
case 20: // Notation Data
|
||||
this.notationFlags = (input.charCodeAt(mypos++) << 24) |
|
||||
(input.charCodeAt(mypos++) << 16) |
|
||||
(input.charCodeAt(mypos++) << 8) |
|
||||
(input.charCodeAt(mypos++));
|
||||
var nameLength = (input.charCodeAt(mypos++) << 8) | (input.charCodeAt(mypos++));
|
||||
var valueLength = (input.charCodeAt(mypos++) << 8) | (input.charCodeAt(mypos++));
|
||||
this.notationName = "";
|
||||
for (var i = 0; i < nameLength; i++) {
|
||||
this.notationName += input[mypos++];
|
||||
}
|
||||
this.notationValue = "";
|
||||
for (var i = 0; i < valueLength; i++) {
|
||||
this.notationValue += input[mypos++];
|
||||
}
|
||||
break;
|
||||
case 21: // Preferred Hash Algorithms
|
||||
this.preferredHashAlgorithms = new Array();
|
||||
for (var i = 0; i < subplen-1; i++) {
|
||||
this.preferredHashAlgorithms = input.charCodeAt(mypos++);
|
||||
}
|
||||
break;
|
||||
case 22: // Preferred Compression Algorithms
|
||||
this.preferredCompressionAlgorithms = new Array();
|
||||
for ( var i = 0; i < subplen-1; i++) {
|
||||
this.preferredCompressionAlgorithms = input.charCodeAt(mypos++);
|
||||
}
|
||||
break;
|
||||
case 23: // Key Server Preferences
|
||||
this.keyServerPreferences = new Array();
|
||||
for ( var i = 0; i < subplen-1; i++) {
|
||||
this.keyServerPreferences = input.charCodeAt(mypos++);
|
||||
}
|
||||
break;
|
||||
case 24: // Preferred Key Server
|
||||
this.preferredKeyServer = new String();
|
||||
for ( var i = 0; i < subplen-1; i++) {
|
||||
this.preferredKeyServer += input[mypos++];
|
||||
}
|
||||
break;
|
||||
case 25: // Primary User ID
|
||||
this.isPrimaryUserID = input[mypos++] != 0;
|
||||
break;
|
||||
case 26: // Policy URI
|
||||
this.policyURI = new String();
|
||||
for ( var i = 0; i < subplen-1; i++) {
|
||||
this.policyURI += input[mypos++];
|
||||
}
|
||||
break;
|
||||
case 27: // Key Flags
|
||||
this.keyFlags = new Array();
|
||||
for ( var i = 0; i < subplen-1; i++) {
|
||||
this.keyFlags = input.charCodeAt(mypos++);
|
||||
}
|
||||
break;
|
||||
case 28: // Signer's User ID
|
||||
this.signersUserId = new String();
|
||||
for ( var i = 0; i < subplen-1; i++) {
|
||||
this.signersUserId += input[mypos++];
|
||||
}
|
||||
break;
|
||||
case 29: // Reason for Revocation
|
||||
this.reasonForRevocationFlag = input.charCodeAt(mypos++);
|
||||
this.reasonForRevocationString = new String();
|
||||
for ( var i = 0; i < subplen -2; i++) {
|
||||
this.reasonForRevocationString += input[mypos++];
|
||||
}
|
||||
break;
|
||||
case 30: // Features
|
||||
// TODO: to be implemented
|
||||
return subplen+1;
|
||||
case 31: // Signature Target
|
||||
// (1 octet public-key algorithm, 1 octet hash algorithm, N octets hash)
|
||||
this.signatureTargetPublicKeyAlgorithm = input.charCodeAt(mypos++);
|
||||
this.signatureTargetHashAlgorithm = input.charCodeAt(mypos++);
|
||||
var signatureTargetHashAlgorithmLength = 0;
|
||||
switch(this.signatureTargetHashAlgorithm) {
|
||||
case 1: // - MD5 [HAC] "MD5"
|
||||
case 2: // - SHA-1 [FIPS180] "SHA1"
|
||||
signatureTargetHashAlgorithmLength = 20;
|
||||
break;
|
||||
case 3: // - RIPE-MD/160 [HAC] "RIPEMD160"
|
||||
case 8: // - SHA256 [FIPS180] "SHA256"
|
||||
case 9: // - SHA384 [FIPS180] "SHA384"
|
||||
case 10: // - SHA512 [FIPS180] "SHA512"
|
||||
case 11: // - SHA224 [FIPS180] "SHA224"
|
||||
break;
|
||||
// 100 to 110 - Private/Experimental algorithm
|
||||
default:
|
||||
util.print_error("openpgp.packet.signature.js\n"+"unknown signature target hash algorithm:"+this.signatureTargetHashAlgorithm);
|
||||
return null;
|
||||
}
|
||||
this.signatureTargetHash = new Array();
|
||||
for (var i = 0; i < signatureTargetHashAlgorithmLength; i++) {
|
||||
this.signatureTargetHash[i] = input[mypos++];
|
||||
}
|
||||
case 32: // Embedded Signature
|
||||
this.embeddedSignature = new openpgp_packet_signature();
|
||||
this.embeddedSignature.read_packet(input, mypos, len -(mypos-position));
|
||||
return ((mypos+ this.embeddedSignature.packetLength) - position);
|
||||
break;
|
||||
case 100: // Private or experimental
|
||||
case 101: // Private or experimental
|
||||
case 102: // Private or experimental
|
||||
case 103: // Private or experimental
|
||||
case 104: // Private or experimental
|
||||
case 105: // Private or experimental
|
||||
case 106: // Private or experimental
|
||||
case 107: // Private or experimental
|
||||
case 108: // Private or experimental
|
||||
case 109: // Private or experimental
|
||||
case 110: // Private or experimental
|
||||
util.print_error("openpgp.packet.signature.js\n"+'private or experimental signature subpacket type '+type+" @:"+mypos+" subplen:"+subplen+" len:"+len);
|
||||
return subplen+1;
|
||||
break;
|
||||
case 0: // Reserved
|
||||
case 1: // Reserved
|
||||
case 8: // Reserved
|
||||
case 10: // Placeholder for backward compatibility
|
||||
case 13: // Reserved
|
||||
case 14: // Reserved
|
||||
case 15: // Reserved
|
||||
case 17: // Reserved
|
||||
case 18: // Reserved
|
||||
case 19: // Reserved
|
||||
default:
|
||||
util.print_error("openpgp.packet.signature.js\n"+'unknown signature subpacket type '+type+" @:"+mypos+" subplen:"+subplen+" len:"+len);
|
||||
return subplen+1;
|
||||
break;
|
||||
}
|
||||
return mypos -position;
|
||||
};
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
function verify(data, key) {
|
||||
// calculating the trailer
|
||||
var trailer = '';
|
||||
trailer += String.fromCharCode(this.version);
|
||||
trailer += String.fromCharCode(0xFF);
|
||||
trailer += String.fromCharCode(this.signatureData.length >> 24);
|
||||
trailer += String.fromCharCode((this.signatureData.length >> 16) &0xFF);
|
||||
trailer += String.fromCharCode((this.signatureData.length >> 8) &0xFF);
|
||||
trailer += String.fromCharCode(this.signatureData.length & 0xFF);
|
||||
switch(this.signatureType) {
|
||||
case 0: // 0x00: Signature of a binary document.
|
||||
if (this.version == 4) {
|
||||
this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
||||
this.MPIs, key.obj.publicKeyPacket.MPIs, data+this.signatureData+trailer);
|
||||
} else if (this.version == 3) {
|
||||
this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
||||
this.MPIs, key.obj.publicKeyPacket.MPIs, data+this.signatureData);
|
||||
} else {
|
||||
this.verified = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // 0x01: Signature of a canonical text document.
|
||||
var canonicalMsgText = data.replace(/\r/g,'').replace(/\n/g,"\r\n");
|
||||
if (openpgp.config.debug) {
|
||||
util.print_debug('canonicalMsgText: '+util.hexdump(canonicalMsgText));
|
||||
util.print_debug('signatureData: '+util.hexdump(this.signatureData));
|
||||
util.print_debug('trailer: '+util.hexdump(trailer));
|
||||
}
|
||||
if (this.version == 4) {
|
||||
this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
||||
this.MPIs, key.obj.publicKeyPacket.MPIs, canonicalMsgText+this.signatureData+trailer);
|
||||
} else if (this.version == 3) {
|
||||
this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
||||
this.MPIs, key.obj.publicKeyPacket.MPIs, canonicalMsgText+this.signatureData);
|
||||
} else {
|
||||
this.verified = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // 0x02: Standalone signature.
|
||||
// This signature is a signature of only its own subpacket contents.
|
||||
// It is calculated identically to a signature over a zero-length
|
||||
// binary document. Note that it doesn't make sense to have a V3
|
||||
// standalone signature.
|
||||
if (this.version == 4) {
|
||||
this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
||||
this.MPIs, key.obj.publicKeyPacket.MPIs, this.signatureData+trailer);
|
||||
} else {
|
||||
this.verified = false;
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
// 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.
|
||||
case 17:
|
||||
// 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.
|
||||
case 18:
|
||||
// 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.
|
||||
case 19:
|
||||
// 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.
|
||||
case 48:
|
||||
// 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.
|
||||
|
||||
this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
||||
this.MPIs, key.MPIs, data+this.signatureData+trailer);
|
||||
break;
|
||||
|
||||
case 24:
|
||||
// 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.
|
||||
if (this.version == 3) {
|
||||
this.verified = false;
|
||||
break;
|
||||
}
|
||||
|
||||
this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
||||
this.MPIs, key.MPIs, data+this.signatureData+trailer);
|
||||
break;
|
||||
case 25:
|
||||
// 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).
|
||||
case 31:
|
||||
// 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.
|
||||
case 32:
|
||||
// 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.
|
||||
case 40:
|
||||
// 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.
|
||||
this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
||||
this.MPIs, key.MPIs, data+this.signatureData+trailer);
|
||||
break;
|
||||
|
||||
// Key revocation signatures (types 0x20 and 0x28)
|
||||
// hash only the key being revoked.
|
||||
case 64:
|
||||
// 0x40: Timestamp signature.
|
||||
// This signature is only meaningful for the timestamp contained in
|
||||
// it.
|
||||
case 80:
|
||||
// 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.
|
||||
default:
|
||||
util.print_error("openpgp.packet.signature.js\n"+"signature verification for type"+ this.signatureType+" not implemented");
|
||||
this.verified = false;
|
||||
break;
|
||||
}
|
||||
return this.verified;
|
||||
}
|
||||
/**
|
||||
* generates debug output (pretty print)
|
||||
* @return {String} String which gives some information about the signature packet
|
||||
*/
|
||||
|
||||
function toString () {
|
||||
if (this.version == 3) {
|
||||
var result = '5.2. Signature Packet (Tag 2)\n'+
|
||||
"Packet Length: :"+this.packetLength+'\n'+
|
||||
"Packet version: :"+this.version+'\n'+
|
||||
"One-octet signature type :"+this.signatureType+'\n'+
|
||||
"Four-octet creation time. :"+this.creationTime+'\n'+
|
||||
"Eight-octet Key ID of signer. :"+util.hexidump(this.keyId)+'\n'+
|
||||
"One-octet public-key algorithm. :"+this.publicKeyAlgorithm+'\n'+
|
||||
"One-octet hash algorithm. :"+this.hashAlgorithm+'\n'+
|
||||
"Two-octet field holding left\n" +
|
||||
" 16 bits of signed hash value. :"+this.signedHashValue+'\n';
|
||||
} else {
|
||||
var result = '5.2. Signature Packet (Tag 2)\n'+
|
||||
"Packet Length: :"+this.packetLength+'\n'+
|
||||
"Packet version: :"+this.version+'\n'+
|
||||
"One-octet signature type :"+this.signatureType+'\n'+
|
||||
"One-octet public-key algorithm. :"+this.publicKeyAlgorithm+'\n'+
|
||||
"One-octet hash algorithm. :"+this.hashAlgorithm+'\n'+
|
||||
"Two-octet field holding left\n" +
|
||||
" 16 bits of signed hash value. :"+this.signedHashValue+'\n'+
|
||||
"Signature Creation Time :"+this.creationTime+'\n'+
|
||||
"Signature Expiration Time :"+this.signatureExpirationTime+'\n'+
|
||||
"Signature Never Expires :"+this.signatureNeverExpires+'\n'+
|
||||
"Exportable Certification :"+this.exportable+'\n'+
|
||||
"Trust Signature level: :"+this.trustLevel+' amount'+this.trustAmount+'\n'+
|
||||
"Regular Expression :"+this.regular_expression+'\n'+
|
||||
"Revocable :"+this.revocable+'\n'+
|
||||
"Key Expiration Time :"+this.keyExpirationTime+" "+this.keyNeverExpires+'\n'+
|
||||
"Preferred Symmetric Algorithms :"+this.preferredSymmetricAlgorithms+'\n'+
|
||||
"Revocation Key"+'\n'+
|
||||
" ( 1 octet of class, :"+this.revocationKeyClass +'\n'+
|
||||
" 1 octet of public-key ID, :" +this.revocationKeyAlgorithm+'\n'+
|
||||
" 20 octets of fingerprint) :"+this.revocationKeyFingerprint+'\n'+
|
||||
"Issuer :"+util.hexstrdump(this.issuerKeyId)+'\n'+
|
||||
"Preferred Hash Algorithms :"+this.preferredHashAlgorithms+'\n'+
|
||||
"Preferred Compression Alg. :"+this.preferredCompressionAlgorithms+'\n'+
|
||||
"Key Server Preferences :"+this.keyServerPreferences+'\n'+
|
||||
"Preferred Key Server :"+this.preferredKeyServer+'\n'+
|
||||
"Primary User ID :"+this.isPrimaryUserID+'\n'+
|
||||
"Policy URI :"+this.policyURI+'\n'+
|
||||
"Key Flags :"+this.keyFlags+'\n'+
|
||||
"Signer's User ID :"+this.signersUserId+'\n'+
|
||||
"Notation :"+this.notationName+" = "+this.notationValue+"\n"+
|
||||
"Reason for Revocation\n"+
|
||||
" Flag :"+this.reasonForRevocationFlag+'\n'+
|
||||
" Reason :"+this.reasonForRevocationString+'\nMPI:\n';
|
||||
}
|
||||
for (var i = 0; i < this.MPIs.length; i++) {
|
||||
result += this.MPIs[i].toString();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the issuer key id of this signature
|
||||
* @return {String} issuer key id as string (8bytes)
|
||||
*/
|
||||
function getIssuer() {
|
||||
if (this.version == 4)
|
||||
return this.issuerKeyId;
|
||||
if (this.version == 3)
|
||||
return this.keyId;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to get the corresponding public key out of the public keyring for the issuer created this signature
|
||||
* @return {Object} {obj: [openpgp_msg_publickey], text: [String]} if found the public key will be returned. null otherwise
|
||||
*/
|
||||
function getIssuerKey() {
|
||||
var result = null;
|
||||
if (this.version == 4) {
|
||||
result = openpgp.keyring.getPublicKeysForKeyId(this.issuerKeyId);
|
||||
} else if (this.version == 3) {
|
||||
result = openpgp.keyring.getPublicKeysForKeyId(this.keyId);
|
||||
} else return null;
|
||||
if (result.length == 0)
|
||||
return null;
|
||||
return result[0];
|
||||
}
|
||||
this.getIssuerKey = getIssuerKey;
|
||||
this.getIssuer = getIssuer;
|
||||
this.write_message_signature = write_message_signature;
|
||||
this.verify = verify;
|
||||
this.read_packet = read_packet;
|
||||
this.toString = toString;
|
||||
}
|
|
@ -1,155 +0,0 @@
|
|||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @classdesc Implementation of the 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.
|
||||
*/
|
||||
function openpgp_packet_userattribute() {
|
||||
this.tagType = 17;
|
||||
this.certificationSignatures = new Array();
|
||||
this.certificationRevocationSignatures = new Array();
|
||||
this.revocationSignatures = new Array();
|
||||
this.parentNode = null;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
function read_packet (input, position, len) {
|
||||
var total_len = 0;
|
||||
this.packetLength = len;
|
||||
this.userattributes = new Array();
|
||||
var count = 0;
|
||||
var mypos = position;
|
||||
while (len != total_len) {
|
||||
var current_len = 0;
|
||||
// 4.2.2.1. One-Octet Lengths
|
||||
if (input.charCodeAt(mypos) < 192) {
|
||||
packet_length = input.charCodeAt(mypos++);
|
||||
current_len = 1;
|
||||
// 4.2.2.2. Two-Octet Lengths
|
||||
} else if (input.charCodeAt(mypos) >= 192 && input.charCodeAt(mypos) < 224) {
|
||||
packet_length = ((input.charCodeAt(mypos++) - 192) << 8)
|
||||
+ (input.charCodeAt(mypos++)) + 192;
|
||||
current_len = 2;
|
||||
// 4.2.2.4. Partial Body Lengths
|
||||
} else if (input.charCodeAt(mypos) > 223 && input.charCodeAt(mypos) < 255) {
|
||||
packet_length = 1 << (input.charCodeAt(mypos++) & 0x1F);
|
||||
current_len = 1;
|
||||
// 4.2.2.3. Five-Octet Lengths
|
||||
} else {
|
||||
current_len = 5;
|
||||
mypos++;
|
||||
packet_length = (input.charCodeAt(mypos++) << 24) | (input.charCodeAt(mypos++) << 16)
|
||||
| (input.charCodeAt(mypos++) << 8) | input.charCodeAt(mypos++);
|
||||
}
|
||||
|
||||
var subpackettype = input.charCodeAt(mypos++);
|
||||
packet_length--;
|
||||
current_len++;
|
||||
this.userattributes[count] = new Array();
|
||||
this.userattributes[count] = input.substring(mypos, mypos + packet_length);
|
||||
mypos += packet_length;
|
||||
total_len += current_len+packet_length;
|
||||
}
|
||||
this.packetLength = mypos - position;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* generates debug output (pretty print)
|
||||
* @return {String} String which gives some information about the user attribute packet
|
||||
*/
|
||||
function toString() {
|
||||
var result = '5.12. User Attribute Packet (Tag 17)\n'+
|
||||
' AttributePackets: (count = '+this.userattributes.length+')\n';
|
||||
for (var i = 0; i < this.userattributes.length; i++) {
|
||||
result += ' ('+this.userattributes[i].length+') bytes: ['+util.hexidump(this.userattributes[i])+']\n';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Continue parsing packets belonging to the user attribute packet such as signatures
|
||||
* @param {Object} parent_node the parent object
|
||||
* @param {String} input input string to read the packet(s) from
|
||||
* @param {Integer} position start position for the parser
|
||||
* @param {Integer} len length of the packet(s) or remaining length of input
|
||||
* @return {Integer} length of nodes read
|
||||
*/
|
||||
function read_nodes(parent_node, input, position, len) {
|
||||
|
||||
this.parentNode = parent_node;
|
||||
var exit = false;
|
||||
var pos = position;
|
||||
var l = len;
|
||||
while (input.length != pos) {
|
||||
var result = openpgp_packet.read_packet(input, pos, l);
|
||||
if (result == null) {
|
||||
util.print_error("openpgp.packet.userattribute.js\n"+'[user_attr] parsing ends here @:' + pos + " l:" + l);
|
||||
break;
|
||||
} else {
|
||||
switch (result.tagType) {
|
||||
case 2: // Signature Packet
|
||||
if (result.signatureType > 15
|
||||
&& result.signatureType < 20) // certification
|
||||
// //
|
||||
// signature
|
||||
this.certificationSignatures[this.certificationSignatures.length] = result;
|
||||
else if (result.signatureType == 32) // certification revocation signature
|
||||
this.certificationRevocationSignatures[this.certificationRevocationSignatures.length] = result;
|
||||
pos += result.packetLength + result.headerLength;
|
||||
l = len - (pos - position);
|
||||
break;
|
||||
default:
|
||||
this.data = input;
|
||||
this.position = position - parent_node.packetLength;
|
||||
this.len = pos - position;
|
||||
return this.len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.data = input;
|
||||
this.position = position - parent_node.packetLength;
|
||||
this.len = pos - position;
|
||||
return this.len;
|
||||
|
||||
}
|
||||
|
||||
this.read_packet = read_packet;
|
||||
this.read_nodes = read_nodes;
|
||||
this.toString = toString;
|
||||
|
||||
};
|
|
@ -1,358 +0,0 @@
|
|||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @classdesc Implementation of the 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.
|
||||
*/
|
||||
|
||||
function openpgp_packet_userid() {
|
||||
this.text = ''
|
||||
this.tagType = 13;
|
||||
this.certificationSignatures = new Array();
|
||||
this.certificationRevocationSignatures = new Array();
|
||||
this.revocationSignatures = new Array();
|
||||
this.parentNode = null;
|
||||
|
||||
/**
|
||||
* Set the packet text field to a native javascript string
|
||||
* Conversion to a proper utf8 encoding takes place when the
|
||||
* packet is written.
|
||||
* @param {String} str Any native javascript string
|
||||
*/
|
||||
this.set_text = function(str) {
|
||||
this.text = str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the packet text to value represented by the provided string
|
||||
* of bytes.
|
||||
* @param {String} bytes A string of bytes
|
||||
*/
|
||||
this.set_text_bytes = function(bytes) {
|
||||
this.text = util.decode_utf8(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the byte sequence representing the text of this packet.
|
||||
* @returns {String} A sequence of bytes
|
||||
*/
|
||||
this.get_text_bytes = function() {
|
||||
return util.encode_utf8(this.text);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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_packet = function(input, position, len) {
|
||||
this.packetLength = len;
|
||||
this.set_text_bytes(input.substr(position, len));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string representation of the user id packet
|
||||
* @param {String} user_id the user id as string ("John Doe <john.doe@mail.us")
|
||||
* @return {String} string representation
|
||||
*/
|
||||
this.write_packet = function(user_id) {
|
||||
this.set_text(user_id);
|
||||
var bytes = this.get_text_bytes();
|
||||
|
||||
var result = openpgp_packet.write_packet_header(13, bytes.length);
|
||||
result += bytes;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Continue parsing packets belonging to the userid packet such as signatures
|
||||
* @param {Object} parent_node the parent object
|
||||
* @param {String} input input string to read the packet(s) from
|
||||
* @param {Integer} position start position for the parser
|
||||
* @param {Integer} len length of the packet(s) or remaining length of input
|
||||
* @return {Integer} length of nodes read
|
||||
*/
|
||||
this.read_nodes = function(parent_node, input, position, len) {
|
||||
if (parent_node.tagType == 6) { // public key
|
||||
this.parentNode = parent_node;
|
||||
var pos = position;
|
||||
var l = len;
|
||||
while (input.length != pos) {
|
||||
var result = openpgp_packet.read_packet(input, pos, l - (pos - position));
|
||||
if (result == null) {
|
||||
util.print_error('[user_id] parsing ends here @:' + pos + " l:" + l);
|
||||
break;
|
||||
} else {
|
||||
|
||||
pos += result.packetLength + result.headerLength;
|
||||
l = input.length - pos;
|
||||
switch (result.tagType) {
|
||||
case 2: // Signature Packet
|
||||
if (result.signatureType > 15
|
||||
&& result.signatureType < 20) { // certification
|
||||
// //
|
||||
// signature
|
||||
this.certificationSignatures[this.certificationSignatures.length] = result;
|
||||
break;
|
||||
} else if (result.signatureType == 48) {// certification revocation signature
|
||||
this.certificationRevocationSignatures[this.certificationRevocationSignatures.length] = result;
|
||||
break;
|
||||
} else if (result.signatureType == 24) { // omg. standalone signature
|
||||
this.certificationSignatures[this.certificationSignatures.length] = result;
|
||||
break;
|
||||
} else {
|
||||
util.print_debug("unknown sig t: "+result.signatureType+"@"+(pos - (result.packetLength + result.headerLength)));
|
||||
}
|
||||
default:
|
||||
this.data = input;
|
||||
this.position = position - parent_node.packetLength;
|
||||
this.len = pos - position -(result.headerLength + result.packetLength);
|
||||
return this.len;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.data = input;
|
||||
this.position = position - parent_node.packetLength;
|
||||
this.len = pos - position -(result.headerLength + result.packetLength);
|
||||
return this.len;
|
||||
} else if (parent_node.tagType == 5) { // secret Key
|
||||
this.parentNode = parent_node;
|
||||
var exit = false;
|
||||
var pos = position;
|
||||
while (input.length != pos) {
|
||||
var result = openpgp_packet.read_packet(input, pos, l - (pos - position));
|
||||
if (result == null) {
|
||||
util.print_error('parsing ends here @:' + pos + " l:" + l);
|
||||
break;
|
||||
} else {
|
||||
pos += result.packetLength + result.headerLength;
|
||||
l = input.length - pos;
|
||||
switch (result.tagType) {
|
||||
case 2: // Signature Packet certification signature
|
||||
if (result.signatureType > 15
|
||||
&& result.signatureType < 20)
|
||||
this.certificationSignatures[this.certificationSignatures.length] = result;
|
||||
// certification revocation signature
|
||||
else if (result.signatureType == 48)
|
||||
this.certificationRevocationSignatures[this.certificationRevocationSignatures.length] = result;
|
||||
default:
|
||||
this.data = input;
|
||||
this.position = position - parent_node.packetLength;
|
||||
this.len = pos - position -(result.headerLength + result.packetLength);
|
||||
return this.len;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
util.print_error("unknown parent node for a userId packet "+parent_node.tagType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* generates debug output (pretty print)
|
||||
* @return {String} String which gives some information about the user id packet
|
||||
*/
|
||||
this.toString = function() {
|
||||
var result = ' 5.11. User ID Packet (Tag 13)\n' + ' text ('
|
||||
+ this.text.length + '): "' + this.text.replace("<", "<")
|
||||
+ '"\n';
|
||||
result +="certification signatures:\n";
|
||||
for (var i = 0; i < this.certificationSignatures.length; i++) {
|
||||
result += " "+this.certificationSignatures[i].toString();
|
||||
}
|
||||
result +="certification revocation signatures:\n";
|
||||
for (var i = 0; i < this.certificationRevocationSignatures.length; i++) {
|
||||
result += " "+this.certificationRevocationSignatures[i].toString();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* lookup function to find certification revocation signatures
|
||||
* @param {String} keyId string containing the key id of the issuer of this signature
|
||||
* @return a CertificationRevocationSignature if found; otherwise null
|
||||
*/
|
||||
this.hasCertificationRevocationSignature = function(keyId) {
|
||||
for (var i = 0; i < this.certificationRevocationSignatures.length; i++) {
|
||||
if ((this.certificationRevocationSignatures[i].version == 3 &&
|
||||
this.certificationRevocationSignatures[i].keyId == keyId) ||
|
||||
(this.certificationRevocationSignatures[i].version == 4 &&
|
||||
this.certificationRevocationSignatures[i].issuerKeyId == keyId))
|
||||
return this.certificationRevocationSignatures[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies all certification signatures. This method does not consider possible revocation signatures.
|
||||
* @param {Object} publicKeyPacket the top level key material
|
||||
* @return {Integer[]} An array of integers corresponding to the array of certification signatures. The meaning of each integer is the following:
|
||||
* 0 = bad signature
|
||||
* 1 = signature expired
|
||||
* 2 = issuer key not available
|
||||
* 3 = revoked
|
||||
* 4 = signature valid
|
||||
* 5 = signature by key owner expired
|
||||
* 6 = signature by key owner revoked
|
||||
*/
|
||||
this.verifyCertificationSignatures = function(publicKeyPacket) {
|
||||
var bytes = this.get_text_bytes();
|
||||
result = new Array();
|
||||
for (var i = 0 ; i < this.certificationSignatures.length; i++) {
|
||||
// A certification signature (type 0x10 through 0x13) hashes the User
|
||||
// ID being bound to the key into the hash context after the above
|
||||
// data. A V3 certification hashes the contents of the User ID or
|
||||
// attribute packet packet, without any header. A V4 certification
|
||||
// hashes the constant 0xB4 for User ID certifications or the constant
|
||||
// 0xD1 for User Attribute certifications, followed by a four-octet
|
||||
// number giving the length of the User ID or User Attribute data, and
|
||||
// then the User ID or User Attribute data.
|
||||
|
||||
if (this.certificationSignatures[i].version == 4) {
|
||||
if (this.certificationSignatures[i].signatureExpirationTime != null &&
|
||||
this.certificationSignatures[i].signatureExpirationTime != null &&
|
||||
this.certificationSignatures[i].signatureExpirationTime != 0 &&
|
||||
!this.certificationSignatures[i].signatureNeverExpires &&
|
||||
new Date(this.certificationSignatures[i].creationTime.getTime() +(this.certificationSignatures[i].signatureExpirationTime*1000)) < new Date()) {
|
||||
if (this.certificationSignatures[i].issuerKeyId == publicKeyPacket.getKeyId())
|
||||
result[i] = 5;
|
||||
else
|
||||
result[i] = 1;
|
||||
continue;
|
||||
}
|
||||
if (this.certificationSignatures[i].issuerKeyId == null) {
|
||||
result[i] = 0;
|
||||
continue;
|
||||
}
|
||||
var issuerPublicKey = openpgp.keyring.getPublicKeysForKeyId(this.certificationSignatures[i].issuerKeyId);
|
||||
if (issuerPublicKey == null || issuerPublicKey.length == 0) {
|
||||
result[i] = 2;
|
||||
continue;
|
||||
}
|
||||
// TODO: try to verify all returned issuer public keys (key ids are not unique!)
|
||||
var issuerPublicKey = issuerPublicKey[0];
|
||||
var signingKey = issuerPublicKey.obj.getSigningKey();
|
||||
if (signingKey == null) {
|
||||
result[i] = 0;
|
||||
continue;
|
||||
}
|
||||
var revocation = this.hasCertificationRevocationSignature(this.certificationSignatures[i].issuerKeyId);
|
||||
if (revocation != null && revocation.creationTime >
|
||||
this.certificationSignatures[i].creationTime) {
|
||||
|
||||
var signaturedata = String.fromCharCode(0x99)+ publicKeyPacket.header.substring(1)+
|
||||
publicKeyPacket.data+String.fromCharCode(0xB4)+
|
||||
String.fromCharCode((bytes.length >> 24) & 0xFF)+
|
||||
String.fromCharCode((bytes.length >> 16) & 0xFF)+
|
||||
String.fromCharCode((bytes.length >> 8) & 0xFF)+
|
||||
String.fromCharCode((bytes.length) & 0xFF)+
|
||||
bytes;
|
||||
if (revocation.verify(signaturedata, signingKey)) {
|
||||
if (this.certificationSignatures[i].issuerKeyId == publicKeyPacket.getKeyId())
|
||||
result[i] = 6;
|
||||
else
|
||||
result[i] = 3;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
var signaturedata = String.fromCharCode(0x99)+ publicKeyPacket.header.substring(1)+
|
||||
publicKeyPacket.data+String.fromCharCode(0xB4)+
|
||||
String.fromCharCode((bytes.length >> 24) & 0xFF)+
|
||||
String.fromCharCode((bytes.length >> 16) & 0xFF)+
|
||||
String.fromCharCode((bytes.length >> 8) & 0xFF)+
|
||||
String.fromCharCode((bytes.length) & 0xFF)+
|
||||
bytes;
|
||||
if (this.certificationSignatures[i].verify(signaturedata, signingKey)) {
|
||||
result[i] = 4;
|
||||
} else
|
||||
result[i] = 0;
|
||||
} else if (this.certificationSignatures[i].version == 3) {
|
||||
if (this.certificationSignatures[i].keyId == null) {
|
||||
result[i] = 0;
|
||||
continue;
|
||||
}
|
||||
var issuerPublicKey = openpgp.keyring.getPublicKeysForKeyId(this.certificationSignatures[i].keyId);
|
||||
if (issuerPublicKey == null || issuerPublicKey.length == 0) {
|
||||
result[i] = 2;
|
||||
continue;
|
||||
}
|
||||
issuerPublicKey = issuerPublicKey[0];
|
||||
var signingKey = publicKey.obj.getSigningKey();
|
||||
if (signingKey == null) {
|
||||
result[i] = 0;
|
||||
continue;
|
||||
}
|
||||
var revocation = this.hasCertificationRevocationSignature(this.certificationSignatures[i].keyId);
|
||||
if (revocation != null && revocation.creationTime >
|
||||
this.certificationSignatures[i].creationTime) {
|
||||
var signaturedata = String.fromCharCode(0x99)+ this.publicKeyPacket.header.substring(1)+
|
||||
this.publicKeyPacket.data+bytes;
|
||||
if (revocation.verify(signaturedata, signingKey)) {
|
||||
if (revocation.keyId == publicKeyPacket.getKeyId())
|
||||
result[i] = 6;
|
||||
else
|
||||
result[i] = 3;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
var signaturedata = String.fromCharCode(0x99)+ publicKeyPacket.header.substring(1)+
|
||||
publicKeyPacket.data + bytes;
|
||||
if (this.certificationSignatures[i].verify(signaturedata, signingKey)) {
|
||||
result[i] = 4;
|
||||
} else
|
||||
result[i] = 0;
|
||||
} else {
|
||||
result[i] = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* verifies the signatures of the user id
|
||||
* @return 0 if the userid is valid; 1 = userid expired; 2 = userid revoked
|
||||
*/
|
||||
this.verify = function(publicKeyPacket) {
|
||||
var result = this.verifyCertificationSignatures(publicKeyPacket);
|
||||
if (result.indexOf(6) != -1)
|
||||
return 2;
|
||||
if (result.indexOf(5) != -1)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: implementation missing
|
||||
this.addCertification = function(publicKeyPacket, privateKeyPacket) {
|
||||
|
||||
}
|
||||
|
||||
// TODO: implementation missing
|
||||
this.revokeCertification = function(publicKeyPacket, privateKeyPacket) {
|
||||
|
||||
}
|
||||
}
|
|
@ -1,135 +0,0 @@
|
|||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
// Hint: We hold our MPIs as an array of octets in big endian format preceeding a two
|
||||
// octet scalar: MPI: [a,b,c,d,e,f]
|
||||
// - MPI size: (a << 8) | b
|
||||
// - MPI = c | d << 8 | e << ((MPI.length -2)*8) | f ((MPI.length -2)*8)
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @classdescImplementation of type MPI (RFC4880 3.2)
|
||||
* Multiprecision integers (also called MPIs) are unsigned integers used
|
||||
* to hold large integers such as the ones used in cryptographic
|
||||
* calculations.
|
||||
* An MPI consists of two pieces: a two-octet scalar that is the length
|
||||
* of the MPI in bits followed by a string of octets that contain the
|
||||
* actual integer.
|
||||
*/
|
||||
function openpgp_type_mpi() {
|
||||
this.MPI = null;
|
||||
this.mpiBitLength = null;
|
||||
this.mpiByteLength = null;
|
||||
this.data = null;
|
||||
/**
|
||||
* Parsing function for a mpi (RFC 4880 3.2).
|
||||
* @param {String} input Payload of mpi data
|
||||
* @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_type_mpi} Object representation
|
||||
*/
|
||||
function read(input, position, len) {
|
||||
var mypos = position;
|
||||
|
||||
this.mpiBitLength = (input.charCodeAt(mypos++) << 8) | input.charCodeAt(mypos++);
|
||||
|
||||
// Additional rules:
|
||||
//
|
||||
// The size of an MPI is ((MPI.length + 7) / 8) + 2 octets.
|
||||
//
|
||||
// The length field of an MPI describes the length starting from its
|
||||
// most significant non-zero bit. Thus, the MPI [00 02 01] is not
|
||||
// formed correctly. It should be [00 01 01].
|
||||
|
||||
// TODO: Verification of this size method! This size calculation as
|
||||
// specified above is not applicable in JavaScript
|
||||
this.mpiByteLength = (this.mpiBitLength - (this.mpiBitLength % 8)) / 8;
|
||||
if (this.mpiBitLength % 8 != 0)
|
||||
this.mpiByteLength++;
|
||||
|
||||
this.MPI = input.substring(mypos,mypos+this.mpiByteLength);
|
||||
this.data = input.substring(position, position+2+this.mpiByteLength);
|
||||
this.packetLength = this.mpiByteLength +2;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates debug output (pretty print)
|
||||
* @return {String} String which gives some information about the mpi
|
||||
*/
|
||||
function toString() {
|
||||
var r = " MPI("+this.mpiBitLength+"b/"+this.mpiByteLength+"B) : 0x";
|
||||
r+=util.hexstrdump(this.MPI);
|
||||
return r+'\n';
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the mpi to an BigInteger object
|
||||
* @return {BigInteger}
|
||||
*/
|
||||
function getBigInteger() {
|
||||
return new BigInteger(util.hexstrdump(this.MPI),16);
|
||||
}
|
||||
|
||||
|
||||
function getBits(num) {
|
||||
for (var i = 0; i < 9; i++)
|
||||
if (num >> i == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the length of the mpi in bytes
|
||||
* @return {Integer} Mpi byte length
|
||||
*/
|
||||
function getByteLength() {
|
||||
return this.mpiByteLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an mpi from the specified string
|
||||
* @param {String} data Data to read the mpi from
|
||||
* @return {openpgp_type_mpi}
|
||||
*/
|
||||
function create(data) {
|
||||
this.MPI = data;
|
||||
this.mpiBitLength = (data.length -1) *8 + getBits(data.charCodeAt(0));
|
||||
this.mpiByteLength = data.length;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the mpi object to a string as specified in RFC4880 3.2
|
||||
* @return {String} mpi Byte representation
|
||||
*/
|
||||
function toBin() {
|
||||
var result = String.fromCharCode((this.mpiBitLength >> 8) & 0xFF);
|
||||
result += String.fromCharCode(this.mpiBitLength & 0xFF);
|
||||
result += this.MPI;
|
||||
return result;
|
||||
}
|
||||
|
||||
this.read = read;
|
||||
this.toBigInteger = getBigInteger;
|
||||
this.toString = toString;
|
||||
this.create = create;
|
||||
this.toBin = toBin;
|
||||
this.getByteLength = getByteLength;
|
||||
}
|
||||
|
|
@ -1,141 +0,0 @@
|
|||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @classdesc Implementation of the String-to-key specifier (RFC4880 3.7)
|
||||
* String-to-key (S2K) specifiers are used to convert passphrase strings
|
||||
into symmetric-key encryption/decryption keys. They are used in two
|
||||
places, currently: to encrypt the secret part of private keys in the
|
||||
private keyring, and to convert passphrases to encryption keys for
|
||||
symmetrically encrypted messages.
|
||||
*/
|
||||
function openpgp_type_s2k() {
|
||||
/**
|
||||
* Parsing function for a string-to-key specifier (RFC 4880 3.7).
|
||||
* @param {String} input Payload of string-to-key specifier
|
||||
* @param {Integer} position Position to start reading from the input string
|
||||
* @return {openpgp_type_s2k} Object representation
|
||||
*/
|
||||
function read(input, position) {
|
||||
var mypos = position;
|
||||
this.type = input.charCodeAt(mypos++);
|
||||
switch (this.type) {
|
||||
case 0: // Simple S2K
|
||||
// Octet 1: hash algorithm
|
||||
this.hashAlgorithm = input.charCodeAt(mypos++);
|
||||
this.s2kLength = 1;
|
||||
break;
|
||||
|
||||
case 1: // Salted S2K
|
||||
// Octet 1: hash algorithm
|
||||
this.hashAlgorithm = input.charCodeAt(mypos++);
|
||||
|
||||
// Octets 2-9: 8-octet salt value
|
||||
this.saltValue = input.substring(mypos, mypos+8);
|
||||
mypos += 8;
|
||||
this.s2kLength = 9;
|
||||
break;
|
||||
|
||||
case 3: // Iterated and Salted S2K
|
||||
// Octet 1: hash algorithm
|
||||
this.hashAlgorithm = input.charCodeAt(mypos++);
|
||||
|
||||
// Octets 2-9: 8-octet salt value
|
||||
this.saltValue = input.substring(mypos, mypos+8);
|
||||
mypos += 8;
|
||||
|
||||
// Octet 10: count, a one-octet, coded value
|
||||
this.EXPBIAS = 6;
|
||||
var c = input.charCodeAt(mypos++);
|
||||
this.count = (16 + (c & 15)) << ((c >> 4) + this.EXPBIAS);
|
||||
this.s2kLength = 10;
|
||||
break;
|
||||
|
||||
case 101:
|
||||
if(input.substring(mypos+1, mypos+4) == "GNU") {
|
||||
this.hashAlgorithm = input.charCodeAt(mypos++);
|
||||
mypos += 3; // GNU
|
||||
var gnuExtType = 1000 + input.charCodeAt(mypos++);
|
||||
if(gnuExtType == 1001) {
|
||||
this.type = gnuExtType;
|
||||
this.s2kLength = 5;
|
||||
// GnuPG extension mode 1001 -- don't write secret key at all
|
||||
} else {
|
||||
util.print_error("unknown s2k gnu protection mode! "+this.type);
|
||||
}
|
||||
} else {
|
||||
util.print_error("unknown s2k type! "+this.type);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // Reserved value
|
||||
default:
|
||||
util.print_error("unknown s2k type! "+this.type);
|
||||
break;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* writes an s2k hash based on the inputs.
|
||||
* @return {String} Produced key of hashAlgorithm hash length
|
||||
*/
|
||||
function write(type, hash, passphrase, salt, c){
|
||||
this.type = type;
|
||||
if(this.type == 3){this.saltValue = salt;
|
||||
this.hashAlgorithm = hash;
|
||||
this.count = (16 + (c & 15)) << ((c >> 4) + 6);
|
||||
this.s2kLength = 10;
|
||||
}
|
||||
return this.produce_key(passphrase);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
function produce_key(passphrase, numBytes) {
|
||||
passphrase = util.encode_utf8(passphrase);
|
||||
if (this.type == 0) {
|
||||
return openpgp_crypto_hashData(this.hashAlgorithm,passphrase);
|
||||
} else if (this.type == 1) {
|
||||
return openpgp_crypto_hashData(this.hashAlgorithm,this.saltValue+passphrase);
|
||||
} else if (this.type == 3) {
|
||||
var isp = [];
|
||||
isp[0] = this.saltValue+passphrase;
|
||||
while (isp.length*(this.saltValue+passphrase).length < this.count)
|
||||
isp.push(this.saltValue+passphrase);
|
||||
isp = isp.join('');
|
||||
if (isp.length > this.count)
|
||||
isp = isp.substr(0, this.count);
|
||||
if(numBytes && (numBytes == 24 || numBytes == 32)){ //This if accounts for RFC 4880 3.7.1.1 -- If hash size is greater than block size, use leftmost bits. If blocksize larger than hash size, we need to rehash isp and prepend with 0.
|
||||
var key = openpgp_crypto_hashData(this.hashAlgorithm,isp);
|
||||
return key + openpgp_crypto_hashData(this.hashAlgorithm,String.fromCharCode(0)+isp);
|
||||
}
|
||||
return openpgp_crypto_hashData(this.hashAlgorithm,isp);
|
||||
} else return null;
|
||||
}
|
||||
|
||||
this.read = read;
|
||||
this.write = write;
|
||||
this.produce_key = produce_key;
|
||||
}
|
|
@ -1,155 +0,0 @@
|
|||
|
||||
unittests.register("TripleDES (EDE) cipher test with test vectors from http://csrc.nist.gov/publications/nistpubs/800-20/800-20.pdf", function() {
|
||||
var result = new Array();
|
||||
var key = util.bin2str([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]);
|
||||
var testvectors = [[[0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x95,0xF8,0xA5,0xE5,0xDD,0x31,0xD9,0x00]],
|
||||
[[0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0xDD,0x7F,0x12,0x1C,0xA5,0x01,0x56,0x19]],
|
||||
[[0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x2E,0x86,0x53,0x10,0x4F,0x38,0x34,0xEA]],
|
||||
[[0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x4B,0xD3,0x88,0xFF,0x6C,0xD8,0x1D,0x4F]],
|
||||
[[0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x20,0xB9,0xE7,0x67,0xB2,0xFB,0x14,0x56]],
|
||||
[[0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x55,0x57,0x93,0x80,0xD7,0x71,0x38,0xEF]],
|
||||
[[0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x6C,0xC5,0xDE,0xFA,0xAF,0x04,0x51,0x2F]],
|
||||
[[0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00],[0x0D,0x9F,0x27,0x9B,0xA5,0xD8,0x72,0x60]],
|
||||
[[0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00],[0xD9,0x03,0x1B,0x02,0x71,0xBD,0x5A,0x0A]],
|
||||
[[0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00],[0x42,0x42,0x50,0xB3,0x7C,0x3D,0xD9,0x51]],
|
||||
[[0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00],[0xB8,0x06,0x1B,0x7E,0xCD,0x9A,0x21,0xE5]],
|
||||
[[0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00],[0xF1,0x5D,0x0F,0x28,0x6B,0x65,0xBD,0x28]],
|
||||
[[0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00],[0xAD,0xD0,0xCC,0x8D,0x6E,0x5D,0xEB,0xA1]],
|
||||
[[0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00],[0xE6,0xD5,0xF8,0x27,0x52,0xAD,0x63,0xD1]],
|
||||
[[0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00],[0xEC,0xBF,0xE3,0xBD,0x3F,0x59,0x1A,0x5E]],
|
||||
[[0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00],[0xF3,0x56,0x83,0x43,0x79,0xD1,0x65,0xCD]],
|
||||
[[0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00],[0x2B,0x9F,0x98,0x2F,0x20,0x03,0x7F,0xA9]],
|
||||
[[0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00],[0x88,0x9D,0xE0,0x68,0xA1,0x6F,0x0B,0xE6]],
|
||||
[[0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00],[0xE1,0x9E,0x27,0x5D,0x84,0x6A,0x12,0x98]],
|
||||
[[0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00],[0x32,0x9A,0x8E,0xD5,0x23,0xD7,0x1A,0xEC]],
|
||||
[[0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00],[0xE7,0xFC,0xE2,0x25,0x57,0xD2,0x3C,0x97]],
|
||||
[[0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00],[0x12,0xA9,0xF5,0x81,0x7F,0xF2,0xD6,0x5D]],
|
||||
[[0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00],[0xA4,0x84,0xC3,0xAD,0x38,0xDC,0x9C,0x19]],
|
||||
[[0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00],[0xFB,0xE0,0x0A,0x8A,0x1E,0xF8,0xAD,0x72]],
|
||||
[[0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00],[0x75,0x0D,0x07,0x94,0x07,0x52,0x13,0x63]],
|
||||
[[0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00],[0x64,0xFE,0xED,0x9C,0x72,0x4C,0x2F,0xAF]],
|
||||
[[0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00],[0xF0,0x2B,0x26,0x3B,0x32,0x8E,0x2B,0x60]],
|
||||
[[0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00],[0x9D,0x64,0x55,0x5A,0x9A,0x10,0xB8,0x52]],
|
||||
[[0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00],[0xD1,0x06,0xFF,0x0B,0xED,0x52,0x55,0xD7]],
|
||||
[[0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00],[0xE1,0x65,0x2C,0x6B,0x13,0x8C,0x64,0xA5]],
|
||||
[[0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00],[0xE4,0x28,0x58,0x11,0x86,0xEC,0x8F,0x46]],
|
||||
[[0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00],[0xAE,0xB5,0xF5,0xED,0xE2,0x2D,0x1A,0x36]],
|
||||
[[0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00],[0xE9,0x43,0xD7,0x56,0x8A,0xEC,0x0C,0x5C]],
|
||||
[[0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00],[0xDF,0x98,0xC8,0x27,0x6F,0x54,0xB0,0x4B]],
|
||||
[[0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00],[0xB1,0x60,0xE4,0x68,0x0F,0x6C,0x69,0x6F]],
|
||||
[[0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00],[0xFA,0x07,0x52,0xB0,0x7D,0x9C,0x4A,0xB8]],
|
||||
[[0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00],[0xCA,0x3A,0x2B,0x03,0x6D,0xBC,0x85,0x02]],
|
||||
[[0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00],[0x5E,0x09,0x05,0x51,0x7B,0xB5,0x9B,0xCF]],
|
||||
[[0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00],[0x81,0x4E,0xEB,0x3B,0x91,0xD9,0x07,0x26]],
|
||||
[[0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00],[0x4D,0x49,0xDB,0x15,0x32,0x91,0x9C,0x9F]],
|
||||
[[0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00],[0x25,0xEB,0x5F,0xC3,0xF8,0xCF,0x06,0x21]],
|
||||
[[0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00],[0xAB,0x6A,0x20,0xC0,0x62,0x0D,0x1C,0x6F]],
|
||||
[[0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00],[0x79,0xE9,0x0D,0xBC,0x98,0xF9,0x2C,0xCA]],
|
||||
[[0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00],[0x86,0x6E,0xCE,0xDD,0x80,0x72,0xBB,0x0E]],
|
||||
[[0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00],[0x8B,0x54,0x53,0x6F,0x2F,0x3E,0x64,0xA8]],
|
||||
[[0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00],[0xEA,0x51,0xD3,0x97,0x55,0x95,0xB8,0x6B]],
|
||||
[[0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00],[0xCA,0xFF,0xC6,0xAC,0x45,0x42,0xDE,0x31]],
|
||||
[[0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00],[0x8D,0xD4,0x5A,0x2D,0xDF,0x90,0x79,0x6C]],
|
||||
[[0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00],[0x10,0x29,0xD5,0x5E,0x88,0x0E,0xC2,0xD0]],
|
||||
[[0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00],[0x5D,0x86,0xCB,0x23,0x63,0x9D,0xBE,0xA9]],
|
||||
[[0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00],[0x1D,0x1C,0xA8,0x53,0xAE,0x7C,0x0C,0x5F]],
|
||||
[[0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00],[0xCE,0x33,0x23,0x29,0x24,0x8F,0x32,0x28]],
|
||||
[[0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00],[0x84,0x05,0xD1,0xAB,0xE2,0x4F,0xB9,0x42]],
|
||||
[[0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00],[0xE6,0x43,0xD7,0x80,0x90,0xCA,0x42,0x07]],
|
||||
[[0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00],[0x48,0x22,0x1B,0x99,0x37,0x74,0x8A,0x23]],
|
||||
[[0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00],[0xDD,0x7C,0x0B,0xBD,0x61,0xFA,0xFD,0x54]],
|
||||
[[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80],[0x2F,0xBC,0x29,0x1A,0x57,0x0D,0xB5,0xC4]],
|
||||
[[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40],[0xE0,0x7C,0x30,0xD7,0xE4,0xE2,0x6E,0x12]],
|
||||
[[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20],[0x09,0x53,0xE2,0x25,0x8E,0x8E,0x90,0xA1]],
|
||||
[[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10],[0x5B,0x71,0x1B,0xC4,0xCE,0xEB,0xF2,0xEE]],
|
||||
[[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08],[0xCC,0x08,0x3F,0x1E,0x6D,0x9E,0x85,0xF6]],
|
||||
[[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04],[0xD2,0xFD,0x88,0x67,0xD5,0x0D,0x2D,0xFE]],
|
||||
[[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02],[0x06,0xE7,0xEA,0x22,0xCE,0x92,0x70,0x8F]],
|
||||
[[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01],[0x16,0x6B,0x40,0xB4,0x4A,0xBA,0x4B,0xD6]]];
|
||||
|
||||
var res = true;
|
||||
var j = 0;
|
||||
for (var i = 0; i < testvectors.length; i++) {
|
||||
var deseded = desede(testvectors[i][0], key);
|
||||
var res2 = (util.bin2str(deseded) == util.bin2str(testvectors[i][1]));
|
||||
res &= res2;
|
||||
if (!res2) {
|
||||
result[j] = new test_result("Testing vector with block "+
|
||||
util.hexidump(testvectors[i][0])+
|
||||
" and key "+util.hexstrdump(key)+
|
||||
" should be "+util.hexidump(testvectors[i][1])+" != "+util.hexidump(deseded),
|
||||
false);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
if (res) {
|
||||
result[j] = new test_result("All " + testvectors.length + " 3DES EDE test vectors completed", true);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
|
||||
unittests.register("DES encrypt/decrypt padding tests", function() {
|
||||
var result = new Array();
|
||||
var key = util.bin2str([0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF]);
|
||||
var testvectors = new Array();
|
||||
testvectors[0] = [[[0x01],[0x24,0xC7,0x4A,0x9A,0x79,0x75,0x4B,0xC7]],
|
||||
[[0x02,0x03],[0xA7,0x7A,0x9A,0x59,0x8A,0x86,0x85,0xC5]],
|
||||
[[0x03,0x04,0x05],[0x01,0xCF,0xEB,0x6A,0x74,0x60,0xF5,0x02]],
|
||||
[[0x04,0x05,0x06,0x07],[0xA8,0xF0,0x3D,0x59,0xBA,0x6B,0x0E,0x76]],
|
||||
[[0x05,0x06,0x07,0x08,0x09],[0x86,0x40,0x33,0x61,0x3F,0x55,0x73,0x49]],
|
||||
[[0x06,0x07,0x08,0x09,0x0A,0x0B],[0x13,0x21,0x3E,0x0E,0xCE,0x2C,0x94,0x01]],
|
||||
[[0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D],[0x30,0x49,0x97,0xC1,0xDA,0xD5,0x59,0xA5]],
|
||||
[[0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F],[0x83,0x25,0x79,0x06,0x54,0xA4,0x44,0xD9]]];
|
||||
testvectors[1] = [[[0x01],[0xF2,0xAB,0x1C,0x9E,0x70,0x7D,0xCC,0x92]],
|
||||
[[0x02,0x03],[0x6B,0x4C,0x67,0x24,0x9F,0xB7,0x4D,0xAC]],
|
||||
[[0x03,0x04,0x05],[0x68,0x95,0xAB,0xA8,0xEA,0x53,0x13,0x23]],
|
||||
[[0x04,0x05,0x06,0x07],[0xC8,0xDE,0x60,0x8F,0xF6,0x09,0x90,0xB5]],
|
||||
[[0x05,0x06,0x07,0x08,0x09],[0x19,0x13,0x50,0x20,0x70,0x40,0x2E,0x09]],
|
||||
[[0x06,0x07,0x08,0x09,0x0A,0x0B],[0xA8,0x23,0x40,0xC6,0x17,0xA6,0x31,0x4A]],
|
||||
[[0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D],[0x36,0x62,0xF2,0x99,0x68,0xD4,0xBF,0x7C]],
|
||||
[[0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F],[0x83,0x25,0x79,0x06,0x54,0xA4,0x44,0xD9,0x08,0x6F,0x9A,0x1D,0x74,0xC9,0x4D,0x4E]]];
|
||||
testvectors[2] = [[[0x01],[0x83,0x68,0xE4,0x9C,0x84,0xCC,0xCB,0xF0]],
|
||||
[[0x02,0x03],[0xBB,0xA8,0x0B,0x66,0x1B,0x62,0xC4,0xC8]],
|
||||
[[0x03,0x04,0x05],[0x9A,0xD7,0x5A,0x24,0xFD,0x3F,0xBF,0x22]],
|
||||
[[0x04,0x05,0x06,0x07],[0x14,0x4E,0x68,0x6D,0x2E,0xC1,0xB7,0x52]],
|
||||
[[0x05,0x06,0x07,0x08,0x09],[0x12,0x0A,0x51,0x08,0xF9,0xA3,0x03,0x74]],
|
||||
[[0x06,0x07,0x08,0x09,0x0A,0x0B],[0xB2,0x07,0xD1,0x05,0xF6,0x67,0xAF,0xBA]],
|
||||
[[0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D],[0xCA,0x59,0x61,0x3A,0x83,0x23,0x26,0xDD]],
|
||||
[[0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F],[0x83,0x25,0x79,0x06,0x54,0xA4,0x44,0xD9]]];
|
||||
|
||||
var keys = des_createKeys(key);
|
||||
|
||||
var res = true;
|
||||
var j = 0;
|
||||
|
||||
for (var padding = 0; padding < 3; padding++) {
|
||||
var thisVectorSet = testvectors[padding];
|
||||
|
||||
for (var i = 0; i < thisVectorSet.length; i++) {
|
||||
var encrypted = des(keys, util.bin2str(thisVectorSet[i][0]), true, 0, null, padding);
|
||||
var decrypted = des(keys, encrypted, false, 0, null, padding);
|
||||
|
||||
var res2 = (encrypted == util.bin2str(thisVectorSet[i][1]));
|
||||
var res3 = (decrypted == util.bin2str(thisVectorSet[i][0]));
|
||||
res &= res2;
|
||||
res &= res3;
|
||||
if (!res2 || !res3) {
|
||||
result[j] = new test_result(
|
||||
"Testing vector with block [" +
|
||||
util.hexidump(thisVectorSet[i][0]) +
|
||||
"] and key [" + util.hexstrdump(key) +
|
||||
"] and padding [" + padding +
|
||||
"] should be " + util.hexidump(thisVectorSet[i][1]) + " - Actually [ENC:" + util.hexdump(encrypted) + ", DEC:" + util.hexdump(decrypted) + "]",
|
||||
false);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (res) {
|
||||
result[j] = new test_result("All DES test vectors completed", true);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JavaScript Unit Tests</title>
|
||||
<link rel="stylesheet" href="lib/mocha.css" />
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="mocha"></div>
|
||||
|
||||
<script src="lib/chai.js"></script>
|
||||
<script src="lib/sinon.js"></script>
|
||||
<script src="lib/mocha.js"></script>
|
||||
|
||||
<script data-main="main.js" src="lib/require.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1,29 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
// config require.js
|
||||
require.config({
|
||||
baseUrl: './',
|
||||
paths: {
|
||||
openpgp: '../../resources/openpgp',
|
||||
jquery: '../../resources/jquery.min'
|
||||
},
|
||||
shim: {
|
||||
openpgp: {
|
||||
exports: 'window'
|
||||
},
|
||||
jquery: {
|
||||
exports: 'window'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// start mocha tests
|
||||
mocha.setup('bdd');
|
||||
require(
|
||||
[
|
||||
'pgp-test'
|
||||
], function() {
|
||||
// require modules loaded -> run tests
|
||||
mocha.run();
|
||||
}
|
||||
);
|
|
@ -1,253 +0,0 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var PGP = require('pgp'),
|
||||
expect = chai.expect;
|
||||
|
||||
describe('PGP Crypto Api unit tests', function() {
|
||||
var pgp,
|
||||
user = 'test@t-online.de',
|
||||
passphrase = 'asdf',
|
||||
keySize = 512,
|
||||
keyId = 'F6F60E9B42CDFF4C',
|
||||
pubkey = '-----BEGIN PGP PUBLIC KEY BLOCK-----\n' +
|
||||
'Version: OpenPGP.js v.1.20131011\n' +
|
||||
'Comment: http://openpgpjs.org\n' +
|
||||
'\n' +
|
||||
'xk0EUlhMvAEB/2MZtCUOAYvyLFjDp3OBMGn3Ev8FwjzyPbIF0JUw+L7y2XR5\n' +
|
||||
'RVGvbK88unV3cU/1tOYdNsXI6pSp/Ztjyv7vbBUAEQEAAc0pV2hpdGVvdXQg\n' +
|
||||
'VXNlciA8d2hpdGVvdXQudGVzdEB0LW9ubGluZS5kZT7CXAQQAQgAEAUCUlhM\n' +
|
||||
'vQkQ9vYOm0LN/0wAAAW4Af9C+kYW1AvNWmivdtr0M0iYCUjM9DNOQH1fcvXq\n' +
|
||||
'IiN602mWrkd8jcEzLsW5IUNzVPLhrFIuKyBDTpLnC07Loce1\n' +
|
||||
'=6XMW\n' +
|
||||
'-----END PGP PUBLIC KEY BLOCK-----',
|
||||
privkey = '-----BEGIN PGP PRIVATE KEY BLOCK-----\n' +
|
||||
'Version: OpenPGP.js v.1.20131011\n' +
|
||||
'Comment: http://openpgpjs.org\n' +
|
||||
'\n' +
|
||||
'xcBeBFJYTLwBAf9jGbQlDgGL8ixYw6dzgTBp9xL/BcI88j2yBdCVMPi+8tl0\n' +
|
||||
'eUVRr2yvPLp1d3FP9bTmHTbFyOqUqf2bY8r+72wVABEBAAH+AwMIhNB4ivtv\n' +
|
||||
'Y2xg6VeMcjjHxZayESHACV+nQx5Tx6ev6xzIF1Qh72fNPDppLhFSFOuTTMsU\n' +
|
||||
'kTN4c+BVYt29spH+cA1jcDAxQ2ULrNAXo+hheOqhpedTs8aCbcLFkJAS16hk\n' +
|
||||
'YSk4OnJgp/z24rVju1SHRSFbgundPzmNgXeX9e8IkviGhhQ11Wc5YwVkx03t\n' +
|
||||
'Z3MdDMF0jyhopbPIoBdyJB0dhvBh98w3JmwpYh9wjUA9MBHD1tvHpRmSZ3BM\n' +
|
||||
'UCmATn2ZLWBRWiYqFbgDnL1GM80pV2hpdGVvdXQgVXNlciA8d2hpdGVvdXQu\n' +
|
||||
'dGVzdEB0LW9ubGluZS5kZT7CXAQQAQgAEAUCUlhMvQkQ9vYOm0LN/0wAAAW4\n' +
|
||||
'Af9C+kYW1AvNWmivdtr0M0iYCUjM9DNOQH1fcvXqIiN602mWrkd8jcEzLsW5\n' +
|
||||
'IUNzVPLhrFIuKyBDTpLnC07Loce1\n' +
|
||||
'=ULta\n' +
|
||||
'-----END PGP PRIVATE KEY BLOCK-----';
|
||||
|
||||
beforeEach(function() {
|
||||
pgp = new PGP();
|
||||
});
|
||||
|
||||
afterEach(function() {});
|
||||
|
||||
describe('Generate key pair', function() {
|
||||
it('should fail', function(done) {
|
||||
pgp.generateKeys({
|
||||
emailAddress: 'test@t-onlinede',
|
||||
keySize: keySize,
|
||||
passphrase: passphrase
|
||||
}, function(err, keys) {
|
||||
expect(err).to.exist;
|
||||
expect(keys).to.not.exist;
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('should fail', function(done) {
|
||||
pgp.generateKeys({
|
||||
emailAddress: 'testt-online.de',
|
||||
keySize: keySize,
|
||||
passphrase: passphrase
|
||||
}, function(err, keys) {
|
||||
expect(err).to.exist;
|
||||
expect(keys).to.not.exist;
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('should work', function(done) {
|
||||
pgp.generateKeys({
|
||||
emailAddress: user,
|
||||
keySize: keySize,
|
||||
passphrase: passphrase
|
||||
}, function(err, keys) {
|
||||
expect(err).to.not.exist;
|
||||
expect(keys.keyId).to.exist;
|
||||
expect(keys.privateKeyArmored).to.exist;
|
||||
expect(keys.publicKeyArmored).to.exist;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Import/Export key pair', function() {
|
||||
it('should fail', function(done) {
|
||||
pgp.importKeys({
|
||||
passphrase: 'asd',
|
||||
privateKeyArmored: privkey,
|
||||
publicKeyArmored: pubkey
|
||||
}, function(err) {
|
||||
expect(err).to.exist;
|
||||
|
||||
pgp.exportKeys(function(err, keys) {
|
||||
expect(err).to.exist;
|
||||
expect(keys).to.not.exist;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
it('should work', function(done) {
|
||||
pgp.importKeys({
|
||||
passphrase: passphrase,
|
||||
privateKeyArmored: privkey,
|
||||
publicKeyArmored: pubkey
|
||||
}, function(err) {
|
||||
expect(err).to.not.exist;
|
||||
|
||||
pgp.exportKeys(function(err, keys) {
|
||||
expect(err).to.not.exist;
|
||||
expect(keys.keyId).to.equal(keyId);
|
||||
expect(keys.privateKeyArmored).to.equal(privkey);
|
||||
expect(keys.publicKeyArmored).to.equal(pubkey);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Encryption', function() {
|
||||
var message = 'asdfs\n\nThursday, Nov 21, 2013 7:38 PM asdf@example.com wrote:\n' +
|
||||
'> asdf\n' +
|
||||
'> \n' +
|
||||
'> Thursday, Nov 21, 2013 7:32 PM asdf@example.com wrote:\n' +
|
||||
'> > secret 3',
|
||||
ciphertext;
|
||||
|
||||
beforeEach(function(done) {
|
||||
pgp.importKeys({
|
||||
passphrase: passphrase,
|
||||
privateKeyArmored: privkey,
|
||||
publicKeyArmored: pubkey
|
||||
}, function(err) {
|
||||
expect(err).to.not.exist;
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Encrypt and Sign', function() {
|
||||
it('should work', function(done) {
|
||||
pgp.encrypt(message, [pubkey], function(err, ct) {
|
||||
expect(err).to.not.exist;
|
||||
expect(ct).to.exist;
|
||||
ciphertext = ct;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Decrypt and Verify', function() {
|
||||
it('should work', function(done) {
|
||||
pgp.decrypt(ciphertext, pubkey, function(err, pt) {
|
||||
expect(err).to.not.exist;
|
||||
expect(pt.text).to.equal(message.replace(/\r/g,'').replace(/\n/g,"\r\n"));
|
||||
expect(pt.validSignatures[0]).to.be.true;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Verify clearsign from gpg', function() {
|
||||
var v3_clearsign_msg = '-----BEGIN PGP SIGNED MESSAGE-----\r\n' +
|
||||
'Hash: SHA1\r\n' +
|
||||
'\r\n' +
|
||||
'This is a test message.\r\n' +
|
||||
'\r\n' +
|
||||
'This paragraph is separated form the next by a line of dashes.\r\n' +
|
||||
'\r\n' +
|
||||
'- --------------------------------------------------------------------------\r\n' +
|
||||
'\r\n' +
|
||||
'The next paragraph has a number of blank lines between this one and it.\r\n' +
|
||||
'\r\n' +
|
||||
'\r\n' +
|
||||
'\r\n' +
|
||||
'\r\n' +
|
||||
'\r\n' +
|
||||
'\r\n' +
|
||||
'This is the last paragraph.\r\n' +
|
||||
'\r\n' +
|
||||
'- --\r\n' +
|
||||
'\r\n' +
|
||||
'Joe Test\r\n' +
|
||||
'-----BEGIN PGP SIGNATURE-----\r\n' +
|
||||
'Version: GnuPG v1.4.15 (GNU/Linux)\r\n' +
|
||||
'\r\n' +
|
||||
'iQBVAwUBUp/7GPb2DptCzf9MAQKviQH6A6Pqa63kxWI+atMiaSXz5uifgsBoiOof\r\n' +
|
||||
'E3/oVTIGyGTgB7KnwZiFkDMFrUNREJVSQGt6+4nxje8gARcuYpMnWw==\r\n' +
|
||||
'=lOCC\r\n' +
|
||||
'-----END PGP SIGNATURE-----\r\n';
|
||||
var v4_clearsign_msg = '-----BEGIN PGP SIGNED MESSAGE-----\r\n' +
|
||||
'Hash: SHA1\r\n' +
|
||||
'\r\n' +
|
||||
'This is a test message.\r\n' +
|
||||
'\r\n' +
|
||||
'This paragraph is separated form the next by a line of dashes.\r\n' +
|
||||
'\r\n' +
|
||||
'- --------------------------------------------------------------------------\r\n' +
|
||||
'\r\n' +
|
||||
'The next paragraph has a number of blank lines between this one and it.\r\n' +
|
||||
'\r\n' +
|
||||
'\r\n' +
|
||||
'\r\n' +
|
||||
'\r\n' +
|
||||
'\r\n' +
|
||||
'\r\n' +
|
||||
'This is the last paragraph.\r\n' +
|
||||
'\r\n' +
|
||||
'- --\r\n' +
|
||||
'\r\n' +
|
||||
'Joe Test\r\n' +
|
||||
'-----BEGIN PGP SIGNATURE-----\r\n' +
|
||||
'Version: GnuPG v1.4.15 (GNU/Linux)\r\n' +
|
||||
'\r\n' +
|
||||
'iFwEAQECAAYFAlKf5LcACgkQ9vYOm0LN/0ybVwH8CItdDh4kWKVcyUx3Q3hWZnWd\r\n' +
|
||||
'zP9CUbIa9uToIPABjV3GOTDM3ZgiP0/SE6Al5vG8hlx+/u2piVojoLovk/4LnA==\r\n' +
|
||||
'=i6ew\r\n' +
|
||||
'-----END PGP SIGNATURE-----\r\n';
|
||||
|
||||
beforeEach(function(done) {
|
||||
pgp.importKeys({
|
||||
passphrase: passphrase,
|
||||
privateKeyArmored: privkey,
|
||||
publicKeyArmored: pubkey
|
||||
}, function(err) {
|
||||
expect(err).to.not.exist;
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Verify V3 signature', function() {
|
||||
it('should work', function(done) {
|
||||
pgp.verify(v3_clearsign_msg, pubkey, function(err, pt) {
|
||||
expect(err).to.not.exist;
|
||||
expect(pt).to.be.true;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Verify V4 signature', function() {
|
||||
it('should work', function(done) {
|
||||
pgp.verify(v4_clearsign_msg, pubkey, function(err, pt) {
|
||||
expect(err).to.not.exist;
|
||||
expect(pt).to.be.true;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,191 +0,0 @@
|
|||
/**
|
||||
* High level crypto api that handles all calls to OpenPGP.js
|
||||
*/
|
||||
function showMessages(str) {
|
||||
}
|
||||
|
||||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var openpgp = require('openpgp').openpgp,
|
||||
util = require('openpgp').util,
|
||||
jquery = require('jquery').jquery;
|
||||
|
||||
var PGP = function() {
|
||||
openpgp.init();
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate a key pair for the user
|
||||
*/
|
||||
PGP.prototype.generateKeys = function(options, callback) {
|
||||
var keys, userId;
|
||||
|
||||
if (!util.emailRegEx.test(options.emailAddress) || !options.keySize || typeof options.passphrase !== 'string') {
|
||||
callback({
|
||||
errMsg: 'Crypto init failed. Not all options set!'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// generate keypair (keytype 1=RSA)
|
||||
try {
|
||||
userId = 'Whiteout User <' + options.emailAddress + '>';
|
||||
keys = openpgp.generate_key_pair(1, options.keySize, userId, options.passphrase);
|
||||
} catch (e) {
|
||||
callback({
|
||||
errMsg: 'Keygeneration failed!',
|
||||
err: e
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
keyId: util.hexstrdump(keys.privateKey.getKeyId()).toUpperCase(),
|
||||
privateKeyArmored: keys.privateKeyArmored,
|
||||
publicKeyArmored: keys.publicKeyArmored
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Import the user's key pair
|
||||
*/
|
||||
PGP.prototype.importKeys = function(options, callback) {
|
||||
var publicKey, privateKey;
|
||||
|
||||
// check passphrase
|
||||
if (typeof options.passphrase !== 'string' || !options.privateKeyArmored || !options.publicKeyArmored) {
|
||||
callback({
|
||||
errMsg: 'Importing keys failed. Not all options set!'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// clear any keypair already in the keychain
|
||||
openpgp.keyring.init();
|
||||
// unlock and import private key
|
||||
if (!openpgp.keyring.importPrivateKey(options.privateKeyArmored, options.passphrase)) {
|
||||
openpgp.keyring.init();
|
||||
callback({
|
||||
errMsg: 'Incorrect passphrase!'
|
||||
});
|
||||
return;
|
||||
}
|
||||
// import public key
|
||||
openpgp.keyring.importPublicKey(options.publicKeyArmored);
|
||||
|
||||
// check if keys have the same id
|
||||
privateKey = openpgp.keyring.exportPrivateKey(0);
|
||||
publicKey = openpgp.keyring.getPublicKeysForKeyId(privateKey.keyId)[0];
|
||||
if (!privateKey || !privateKey.armored || !publicKey || !publicKey.armored || privateKey.keyId !== publicKey.keyId) {
|
||||
// reset keyring
|
||||
openpgp.keyring.init();
|
||||
callback({
|
||||
errMsg: 'Key IDs dont match!'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
callback();
|
||||
};
|
||||
|
||||
/**
|
||||
* Export the user's key pair
|
||||
*/
|
||||
PGP.prototype.exportKeys = function(callback) {
|
||||
var publicKey, privateKey;
|
||||
|
||||
privateKey = openpgp.keyring.exportPrivateKey(0);
|
||||
if (privateKey && privateKey.keyId) {
|
||||
publicKey = openpgp.keyring.getPublicKeysForKeyId(privateKey.keyId)[0];
|
||||
}
|
||||
|
||||
if (!privateKey || !privateKey.keyId || !privateKey.armored || !publicKey || !publicKey.armored) {
|
||||
callback({
|
||||
errMsg: 'Could not export keys!'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
keyId: util.hexstrdump(privateKey.keyId).toUpperCase(),
|
||||
privateKeyArmored: privateKey.armored,
|
||||
publicKeyArmored: publicKey.armored
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Encrypt and sign a pgp message for a list of receivers
|
||||
*/
|
||||
PGP.prototype.encrypt = function(plaintext, receiverKeys, callback) {
|
||||
var ct, i,
|
||||
privateKey = openpgp.keyring.exportPrivateKey(0).obj;
|
||||
|
||||
for (i = 0; i < receiverKeys.length; i++) {
|
||||
receiverKeys[i] = openpgp.read_publicKey(receiverKeys[i])[0];
|
||||
}
|
||||
|
||||
ct = openpgp.write_signed_and_encrypted_message(privateKey, receiverKeys, plaintext);
|
||||
|
||||
callback(null, ct);
|
||||
};
|
||||
|
||||
/**
|
||||
* Decrypt and verify a pgp message for a single sender
|
||||
*/
|
||||
PGP.prototype.decrypt = function(ciphertext, senderKey, callback) {
|
||||
var privateKey = openpgp.keyring.exportPrivateKey(0).obj;
|
||||
var publicKey = openpgp.read_publicKey(senderKey)[0];
|
||||
var pubKeys = [ { armored: senderKey, obj: publicKey, keyId: publicKey.getKeyId() } ];
|
||||
|
||||
var msg = openpgp.read_message(ciphertext)[0];
|
||||
var keymat = null;
|
||||
var sesskey = null;
|
||||
|
||||
// Find the private (sub)key for the session key of the message
|
||||
for (var i = 0; i < msg.sessionKeys.length; i++) {
|
||||
if (privateKey.privateKeyPacket.publicKey.getKeyId() === msg.sessionKeys[i].keyId.bytes) {
|
||||
keymat = {
|
||||
key: privateKey,
|
||||
keymaterial: privateKey.privateKeyPacket
|
||||
};
|
||||
sesskey = msg.sessionKeys[i];
|
||||
break;
|
||||
}
|
||||
for (var j = 0; j < privateKey.subKeys.length; j++) {
|
||||
if (privateKey.subKeys[j].publicKey.getKeyId() === msg.sessionKeys[i].keyId.bytes) {
|
||||
keymat = {
|
||||
key: privateKey,
|
||||
keymaterial: privateKey.subKeys[j]
|
||||
};
|
||||
sesskey = msg.sessionKeys[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (keymat !== null) {
|
||||
var decrypted = msg.decryptAndVerifySignature(keymat, sesskey, pubKeys);
|
||||
callback(null, decrypted);
|
||||
|
||||
} else {
|
||||
callback({
|
||||
errMsg: 'No private key found!'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Verify a clearsign message for a single sender
|
||||
*/
|
||||
PGP.prototype.verify = function(message, senderKey, callback) {
|
||||
var publicKey = openpgp.read_publicKey(senderKey)[0];
|
||||
var pubKeys = [ { armored: senderKey, obj: publicKey, keyId: publicKey.getKeyId() } ];
|
||||
|
||||
var msg = openpgp.read_message(message)[0];
|
||||
|
||||
var verified = msg.verifySignature(pubKeys);
|
||||
callback(null, verified);
|
||||
};
|
||||
|
||||
return PGP;
|
||||
});
|
Loading…
Reference in New Issue
Block a user