A ton of changes regarding browserify support. Non functional as of now.
This commit is contained in:
parent
f421dc0d72
commit
18236ac097
2
Makefile
2
Makefile
|
@ -31,7 +31,7 @@ lint:
|
||||||
@./scripts/lint.sh
|
@./scripts/lint.sh
|
||||||
|
|
||||||
bundle:
|
bundle:
|
||||||
@browserify -d -r ./src/openpgp.js:openpgp > ./resources/openpgp.js
|
@browserify -d -r ./src:openpgp > ./resources/openpgp.js
|
||||||
minify:
|
minify:
|
||||||
@echo See http://code.google.com/closure/compiler/
|
@echo See http://code.google.com/closure/compiler/
|
||||||
@./scripts/minimize.sh
|
@./scripts/minimize.sh
|
||||||
|
|
7234
resources/openpgp.js
7234
resources/openpgp.js
File diff suppressed because one or more lines are too long
|
@ -1,589 +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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Basic JavaScript BN library - subset useful for RSA encryption.
|
|
||||||
|
|
||||||
// Bits per digit
|
|
||||||
var dbits;
|
|
||||||
|
|
||||||
// JavaScript engine analysis
|
|
||||||
var canary = 0xdeadbeefcafe;
|
|
||||||
var j_lm = ((canary&0xffffff)==0xefcafe);
|
|
||||||
|
|
||||||
// (public) Constructor
|
|
||||||
function BigInteger(a,b,c) {
|
|
||||||
if(a != null)
|
|
||||||
if("number" == typeof a) this.fromNumber(a,b,c);
|
|
||||||
else if(b == null && "string" != typeof a) this.fromString(a,256);
|
|
||||||
else this.fromString(a,b);
|
|
||||||
}
|
|
||||||
|
|
||||||
// return new, unset BigInteger
|
|
||||||
function nbi() { return new BigInteger(null); }
|
|
||||||
|
|
||||||
// am: Compute w_j += (x*this_i), propagate carries,
|
|
||||||
// c is initial carry, returns final carry.
|
|
||||||
// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
|
|
||||||
// We need to select the fastest one that works in this environment.
|
|
||||||
|
|
||||||
// am1: use a single mult and divide to get the high bits,
|
|
||||||
// max digit bits should be 26 because
|
|
||||||
// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
|
|
||||||
function am1(i,x,w,j,c,n) {
|
|
||||||
while(--n >= 0) {
|
|
||||||
var v = x*this[i++]+w[j]+c;
|
|
||||||
c = Math.floor(v/0x4000000);
|
|
||||||
w[j++] = v&0x3ffffff;
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
// am2 avoids a big mult-and-extract completely.
|
|
||||||
// Max digit bits should be <= 30 because we do bitwise ops
|
|
||||||
// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
|
|
||||||
function am2(i,x,w,j,c,n) {
|
|
||||||
var xl = x&0x7fff, xh = x>>15;
|
|
||||||
while(--n >= 0) {
|
|
||||||
var l = this[i]&0x7fff;
|
|
||||||
var h = this[i++]>>15;
|
|
||||||
var m = xh*l+h*xl;
|
|
||||||
l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff);
|
|
||||||
c = (l>>>30)+(m>>>15)+xh*h+(c>>>30);
|
|
||||||
w[j++] = l&0x3fffffff;
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
// Alternately, set max digit bits to 28 since some
|
|
||||||
// browsers slow down when dealing with 32-bit numbers.
|
|
||||||
function am3(i,x,w,j,c,n) {
|
|
||||||
var xl = x&0x3fff, xh = x>>14;
|
|
||||||
while(--n >= 0) {
|
|
||||||
var l = this[i]&0x3fff;
|
|
||||||
var h = this[i++]>>14;
|
|
||||||
var m = xh*l+h*xl;
|
|
||||||
l = xl*l+((m&0x3fff)<<14)+w[j]+c;
|
|
||||||
c = (l>>28)+(m>>14)+xh*h;
|
|
||||||
w[j++] = l&0xfffffff;
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
|
|
||||||
BigInteger.prototype.am = am2;
|
|
||||||
dbits = 30;
|
|
||||||
}
|
|
||||||
else if(j_lm && (navigator.appName != "Netscape")) {
|
|
||||||
BigInteger.prototype.am = am1;
|
|
||||||
dbits = 26;
|
|
||||||
}
|
|
||||||
else { // Mozilla/Netscape seems to prefer am3
|
|
||||||
BigInteger.prototype.am = am3;
|
|
||||||
dbits = 28;
|
|
||||||
}
|
|
||||||
|
|
||||||
BigInteger.prototype.DB = dbits;
|
|
||||||
BigInteger.prototype.DM = ((1<<dbits)-1);
|
|
||||||
BigInteger.prototype.DV = (1<<dbits);
|
|
||||||
|
|
||||||
var BI_FP = 52;
|
|
||||||
BigInteger.prototype.FV = Math.pow(2,BI_FP);
|
|
||||||
BigInteger.prototype.F1 = BI_FP-dbits;
|
|
||||||
BigInteger.prototype.F2 = 2*dbits-BI_FP;
|
|
||||||
|
|
||||||
// Digit conversions
|
|
||||||
var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
||||||
var BI_RC = new Array();
|
|
||||||
var rr,vv;
|
|
||||||
rr = "0".charCodeAt(0);
|
|
||||||
for(vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
|
|
||||||
rr = "a".charCodeAt(0);
|
|
||||||
for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
|
|
||||||
rr = "A".charCodeAt(0);
|
|
||||||
for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
|
|
||||||
|
|
||||||
function int2char(n) { return BI_RM.charAt(n); }
|
|
||||||
function intAt(s,i) {
|
|
||||||
var c = BI_RC[s.charCodeAt(i)];
|
|
||||||
return (c==null)?-1:c;
|
|
||||||
}
|
|
||||||
|
|
||||||
// (protected) copy this to r
|
|
||||||
function bnpCopyTo(r) {
|
|
||||||
for(var i = this.t-1; i >= 0; --i) r[i] = this[i];
|
|
||||||
r.t = this.t;
|
|
||||||
r.s = this.s;
|
|
||||||
}
|
|
||||||
|
|
||||||
// (protected) set from integer value x, -DV <= x < DV
|
|
||||||
function bnpFromInt(x) {
|
|
||||||
this.t = 1;
|
|
||||||
this.s = (x<0)?-1:0;
|
|
||||||
if(x > 0) this[0] = x;
|
|
||||||
else if(x < -1) this[0] = x+DV;
|
|
||||||
else this.t = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return bigint initialized to value
|
|
||||||
function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
|
|
||||||
|
|
||||||
// (protected) set from string and radix
|
|
||||||
function bnpFromString(s,b) {
|
|
||||||
var k;
|
|
||||||
if(b == 16) k = 4;
|
|
||||||
else if(b == 8) k = 3;
|
|
||||||
else if(b == 256) k = 8; // byte array
|
|
||||||
else if(b == 2) k = 1;
|
|
||||||
else if(b == 32) k = 5;
|
|
||||||
else if(b == 4) k = 2;
|
|
||||||
else { this.fromRadix(s,b); return; }
|
|
||||||
this.t = 0;
|
|
||||||
this.s = 0;
|
|
||||||
var i = s.length, mi = false, sh = 0;
|
|
||||||
while(--i >= 0) {
|
|
||||||
var x = (k==8)?s[i]&0xff:intAt(s,i);
|
|
||||||
if(x < 0) {
|
|
||||||
if(s.charAt(i) == "-") mi = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
mi = false;
|
|
||||||
if(sh == 0)
|
|
||||||
this[this.t++] = x;
|
|
||||||
else if(sh+k > this.DB) {
|
|
||||||
this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<<sh;
|
|
||||||
this[this.t++] = (x>>(this.DB-sh));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
this[this.t-1] |= x<<sh;
|
|
||||||
sh += k;
|
|
||||||
if(sh >= this.DB) sh -= this.DB;
|
|
||||||
}
|
|
||||||
if(k == 8 && (s[0]&0x80) != 0) {
|
|
||||||
this.s = -1;
|
|
||||||
if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh;
|
|
||||||
}
|
|
||||||
this.clamp();
|
|
||||||
if(mi) BigInteger.ZERO.subTo(this,this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// (protected) clamp off excess high words
|
|
||||||
function bnpClamp() {
|
|
||||||
var c = this.s&this.DM;
|
|
||||||
while(this.t > 0 && this[this.t-1] == c) --this.t;
|
|
||||||
}
|
|
||||||
|
|
||||||
// (public) return string representation in given radix
|
|
||||||
function bnToString(b) {
|
|
||||||
if(this.s < 0) return "-"+this.negate().toString(b);
|
|
||||||
var k;
|
|
||||||
if(b == 16) k = 4;
|
|
||||||
else if(b == 8) k = 3;
|
|
||||||
else if(b == 2) k = 1;
|
|
||||||
else if(b == 32) k = 5;
|
|
||||||
else if(b == 4) k = 2;
|
|
||||||
else return this.toRadix(b);
|
|
||||||
var km = (1<<k)-1, d, m = false, r = "", i = this.t;
|
|
||||||
var p = this.DB-(i*this.DB)%k;
|
|
||||||
if(i-- > 0) {
|
|
||||||
if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); }
|
|
||||||
while(i >= 0) {
|
|
||||||
if(p < k) {
|
|
||||||
d = (this[i]&((1<<p)-1))<<(k-p);
|
|
||||||
d |= this[--i]>>(p+=this.DB-k);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
d = (this[i]>>(p-=k))&km;
|
|
||||||
if(p <= 0) { p += this.DB; --i; }
|
|
||||||
}
|
|
||||||
if(d > 0) m = true;
|
|
||||||
if(m) r += int2char(d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return m?r:"0";
|
|
||||||
}
|
|
||||||
|
|
||||||
// (public) -this
|
|
||||||
function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }
|
|
||||||
|
|
||||||
// (public) |this|
|
|
||||||
function bnAbs() { return (this.s<0)?this.negate():this; }
|
|
||||||
|
|
||||||
// (public) return + if this > a, - if this < a, 0 if equal
|
|
||||||
function bnCompareTo(a) {
|
|
||||||
var r = this.s-a.s;
|
|
||||||
if(r != 0) return r;
|
|
||||||
var i = this.t;
|
|
||||||
r = i-a.t;
|
|
||||||
if(r != 0) return r;
|
|
||||||
while(--i >= 0) if((r=this[i]-a[i]) != 0) return r;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns bit length of the integer x
|
|
||||||
function nbits(x) {
|
|
||||||
var r = 1, t;
|
|
||||||
if((t=x>>>16) != 0) { x = t; r += 16; }
|
|
||||||
if((t=x>>8) != 0) { x = t; r += 8; }
|
|
||||||
if((t=x>>4) != 0) { x = t; r += 4; }
|
|
||||||
if((t=x>>2) != 0) { x = t; r += 2; }
|
|
||||||
if((t=x>>1) != 0) { x = t; r += 1; }
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
// (public) return the number of bits in "this"
|
|
||||||
function bnBitLength() {
|
|
||||||
if(this.t <= 0) return 0;
|
|
||||||
return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM));
|
|
||||||
}
|
|
||||||
|
|
||||||
// (protected) r = this << n*DB
|
|
||||||
function bnpDLShiftTo(n,r) {
|
|
||||||
var i;
|
|
||||||
for(i = this.t-1; i >= 0; --i) r[i+n] = this[i];
|
|
||||||
for(i = n-1; i >= 0; --i) r[i] = 0;
|
|
||||||
r.t = this.t+n;
|
|
||||||
r.s = this.s;
|
|
||||||
}
|
|
||||||
|
|
||||||
// (protected) r = this >> n*DB
|
|
||||||
function bnpDRShiftTo(n,r) {
|
|
||||||
for(var i = n; i < this.t; ++i) r[i-n] = this[i];
|
|
||||||
r.t = Math.max(this.t-n,0);
|
|
||||||
r.s = this.s;
|
|
||||||
}
|
|
||||||
|
|
||||||
// (protected) r = this << n
|
|
||||||
function bnpLShiftTo(n,r) {
|
|
||||||
var bs = n%this.DB;
|
|
||||||
var cbs = this.DB-bs;
|
|
||||||
var bm = (1<<cbs)-1;
|
|
||||||
var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i;
|
|
||||||
for(i = this.t-1; i >= 0; --i) {
|
|
||||||
r[i+ds+1] = (this[i]>>cbs)|c;
|
|
||||||
c = (this[i]&bm)<<bs;
|
|
||||||
}
|
|
||||||
for(i = ds-1; i >= 0; --i) r[i] = 0;
|
|
||||||
r[ds] = c;
|
|
||||||
r.t = this.t+ds+1;
|
|
||||||
r.s = this.s;
|
|
||||||
r.clamp();
|
|
||||||
}
|
|
||||||
|
|
||||||
// (protected) r = this >> n
|
|
||||||
function bnpRShiftTo(n,r) {
|
|
||||||
r.s = this.s;
|
|
||||||
var ds = Math.floor(n/this.DB);
|
|
||||||
if(ds >= this.t) { r.t = 0; return; }
|
|
||||||
var bs = n%this.DB;
|
|
||||||
var cbs = this.DB-bs;
|
|
||||||
var bm = (1<<bs)-1;
|
|
||||||
r[0] = this[ds]>>bs;
|
|
||||||
for(var i = ds+1; i < this.t; ++i) {
|
|
||||||
r[i-ds-1] |= (this[i]&bm)<<cbs;
|
|
||||||
r[i-ds] = this[i]>>bs;
|
|
||||||
}
|
|
||||||
if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs;
|
|
||||||
r.t = this.t-ds;
|
|
||||||
r.clamp();
|
|
||||||
}
|
|
||||||
|
|
||||||
// (protected) r = this - a
|
|
||||||
function bnpSubTo(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 < -1) r[i++] = this.DV+c;
|
|
||||||
else if(c > 0) r[i++] = c;
|
|
||||||
r.t = i;
|
|
||||||
r.clamp();
|
|
||||||
}
|
|
||||||
|
|
||||||
// (protected) r = this * a, r != this,a (HAC 14.12)
|
|
||||||
// "this" should be the larger one if appropriate.
|
|
||||||
function bnpMultiplyTo(a,r) {
|
|
||||||
var x = this.abs(), y = a.abs();
|
|
||||||
var i = x.t;
|
|
||||||
r.t = i+y.t;
|
|
||||||
while(--i >= 0) r[i] = 0;
|
|
||||||
for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t);
|
|
||||||
r.s = 0;
|
|
||||||
r.clamp();
|
|
||||||
if(this.s != a.s) BigInteger.ZERO.subTo(r,r);
|
|
||||||
}
|
|
||||||
|
|
||||||
// (protected) r = this^2, r != this (HAC 14.16)
|
|
||||||
function bnpSquareTo(r) {
|
|
||||||
var x = this.abs();
|
|
||||||
var i = r.t = 2*x.t;
|
|
||||||
while(--i >= 0) r[i] = 0;
|
|
||||||
for(i = 0; i < x.t-1; ++i) {
|
|
||||||
var c = x.am(i,x[i],r,2*i,0,1);
|
|
||||||
if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) {
|
|
||||||
r[i+x.t] -= x.DV;
|
|
||||||
r[i+x.t+1] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1);
|
|
||||||
r.s = 0;
|
|
||||||
r.clamp();
|
|
||||||
}
|
|
||||||
|
|
||||||
// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
|
|
||||||
// r != q, this != m. q or r may be null.
|
|
||||||
function bnpDivRemTo(m,q,r) {
|
|
||||||
var pm = m.abs();
|
|
||||||
if(pm.t <= 0) return;
|
|
||||||
var pt = this.abs();
|
|
||||||
if(pt.t < pm.t) {
|
|
||||||
if(q != null) q.fromInt(0);
|
|
||||||
if(r != null) this.copyTo(r);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(r == null) r = nbi();
|
|
||||||
var y = nbi(), ts = this.s, ms = m.s;
|
|
||||||
var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus
|
|
||||||
if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); }
|
|
||||||
else { pm.copyTo(y); pt.copyTo(r); }
|
|
||||||
var ys = y.t;
|
|
||||||
var y0 = y[ys-1];
|
|
||||||
if(y0 == 0) return;
|
|
||||||
var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0);
|
|
||||||
var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
|
|
||||||
var i = r.t, j = i-ys, t = (q==null)?nbi():q;
|
|
||||||
y.dlShiftTo(j,t);
|
|
||||||
if(r.compareTo(t) >= 0) {
|
|
||||||
r[r.t++] = 1;
|
|
||||||
r.subTo(t,r);
|
|
||||||
}
|
|
||||||
BigInteger.ONE.dlShiftTo(ys,t);
|
|
||||||
t.subTo(y,y); // "negative" y so we can replace sub with am later
|
|
||||||
while(y.t < ys) y[y.t++] = 0;
|
|
||||||
while(--j >= 0) {
|
|
||||||
// Estimate quotient digit
|
|
||||||
var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);
|
|
||||||
if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out
|
|
||||||
y.dlShiftTo(j,t);
|
|
||||||
r.subTo(t,r);
|
|
||||||
while(r[i] < --qd) r.subTo(t,r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(q != null) {
|
|
||||||
r.drShiftTo(ys,q);
|
|
||||||
if(ts != ms) BigInteger.ZERO.subTo(q,q);
|
|
||||||
}
|
|
||||||
r.t = ys;
|
|
||||||
r.clamp();
|
|
||||||
if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder
|
|
||||||
if(ts < 0) BigInteger.ZERO.subTo(r,r);
|
|
||||||
}
|
|
||||||
|
|
||||||
// (public) this mod a
|
|
||||||
function bnMod(a) {
|
|
||||||
var r = nbi();
|
|
||||||
this.abs().divRemTo(a,null,r);
|
|
||||||
if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Modular reduction using "classic" algorithm
|
|
||||||
function Classic(m) { this.m = m; }
|
|
||||||
function cConvert(x) {
|
|
||||||
if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
|
|
||||||
else return x;
|
|
||||||
}
|
|
||||||
function cRevert(x) { return x; }
|
|
||||||
function cReduce(x) { x.divRemTo(this.m,null,x); }
|
|
||||||
function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
|
|
||||||
function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
|
|
||||||
|
|
||||||
Classic.prototype.convert = cConvert;
|
|
||||||
Classic.prototype.revert = cRevert;
|
|
||||||
Classic.prototype.reduce = cReduce;
|
|
||||||
Classic.prototype.mulTo = cMulTo;
|
|
||||||
Classic.prototype.sqrTo = cSqrTo;
|
|
||||||
|
|
||||||
// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
|
|
||||||
// justification:
|
|
||||||
// xy == 1 (mod m)
|
|
||||||
// xy = 1+km
|
|
||||||
// xy(2-xy) = (1+km)(1-km)
|
|
||||||
// x[y(2-xy)] = 1-k^2m^2
|
|
||||||
// x[y(2-xy)] == 1 (mod m^2)
|
|
||||||
// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
|
|
||||||
// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
|
|
||||||
// JS multiply "overflows" differently from C/C++, so care is needed here.
|
|
||||||
function bnpInvDigit() {
|
|
||||||
if(this.t < 1) return 0;
|
|
||||||
var x = this[0];
|
|
||||||
if((x&1) == 0) return 0;
|
|
||||||
var y = x&3; // y == 1/x mod 2^2
|
|
||||||
y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4
|
|
||||||
y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8
|
|
||||||
y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16
|
|
||||||
// last step - calculate inverse mod DV directly;
|
|
||||||
// assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
|
|
||||||
y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits
|
|
||||||
// we really want the negative inverse, and -DV < y < DV
|
|
||||||
return (y>0)?this.DV-y:-y;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Montgomery reduction
|
|
||||||
function Montgomery(m) {
|
|
||||||
this.m = m;
|
|
||||||
this.mp = m.invDigit();
|
|
||||||
this.mpl = this.mp&0x7fff;
|
|
||||||
this.mph = this.mp>>15;
|
|
||||||
this.um = (1<<(m.DB-15))-1;
|
|
||||||
this.mt2 = 2*m.t;
|
|
||||||
}
|
|
||||||
|
|
||||||
// xR mod m
|
|
||||||
function montConvert(x) {
|
|
||||||
var r = nbi();
|
|
||||||
x.abs().dlShiftTo(this.m.t,r);
|
|
||||||
r.divRemTo(this.m,null,r);
|
|
||||||
if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
// x/R mod m
|
|
||||||
function montRevert(x) {
|
|
||||||
var r = nbi();
|
|
||||||
x.copyTo(r);
|
|
||||||
this.reduce(r);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
// x = x/R mod m (HAC 14.32)
|
|
||||||
function montReduce(x) {
|
|
||||||
while(x.t <= this.mt2) // pad x so am has enough room later
|
|
||||||
x[x.t++] = 0;
|
|
||||||
for(var i = 0; i < this.m.t; ++i) {
|
|
||||||
// faster way of calculating u0 = x[i]*mp mod DV
|
|
||||||
var j = x[i]&0x7fff;
|
|
||||||
var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM;
|
|
||||||
// use am to combine the multiply-shift-add into one call
|
|
||||||
j = i+this.m.t;
|
|
||||||
x[j] += this.m.am(0,u0,x,i,0,this.m.t);
|
|
||||||
// propagate carry
|
|
||||||
while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; }
|
|
||||||
}
|
|
||||||
x.clamp();
|
|
||||||
x.drShiftTo(this.m.t,x);
|
|
||||||
if(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
|
|
||||||
}
|
|
||||||
|
|
||||||
// r = "x^2/R mod m"; x != r
|
|
||||||
function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
|
|
||||||
|
|
||||||
// r = "xy/R mod m"; x,y != r
|
|
||||||
function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
|
|
||||||
|
|
||||||
Montgomery.prototype.convert = montConvert;
|
|
||||||
Montgomery.prototype.revert = montRevert;
|
|
||||||
Montgomery.prototype.reduce = montReduce;
|
|
||||||
Montgomery.prototype.mulTo = montMulTo;
|
|
||||||
Montgomery.prototype.sqrTo = montSqrTo;
|
|
||||||
|
|
||||||
// (protected) true iff this is even
|
|
||||||
function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; }
|
|
||||||
|
|
||||||
// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
|
|
||||||
function bnpExp(e,z) {
|
|
||||||
if(e > 0xffffffff || e < 1) return BigInteger.ONE;
|
|
||||||
var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1;
|
|
||||||
g.copyTo(r);
|
|
||||||
while(--i >= 0) {
|
|
||||||
z.sqrTo(r,r2);
|
|
||||||
if((e&(1<<i)) > 0) z.mulTo(r2,g,r);
|
|
||||||
else { var t = r; r = r2; r2 = t; }
|
|
||||||
}
|
|
||||||
return z.revert(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
// (public) this^e % m, 0 <= e < 2^32
|
|
||||||
function bnModPowInt(e,m) {
|
|
||||||
var z;
|
|
||||||
if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
|
|
||||||
return this.exp(e,z);
|
|
||||||
}
|
|
||||||
|
|
||||||
// protected
|
|
||||||
BigInteger.prototype.copyTo = bnpCopyTo;
|
|
||||||
BigInteger.prototype.fromInt = bnpFromInt;
|
|
||||||
BigInteger.prototype.fromString = bnpFromString;
|
|
||||||
BigInteger.prototype.clamp = bnpClamp;
|
|
||||||
BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
|
|
||||||
BigInteger.prototype.drShiftTo = bnpDRShiftTo;
|
|
||||||
BigInteger.prototype.lShiftTo = bnpLShiftTo;
|
|
||||||
BigInteger.prototype.rShiftTo = bnpRShiftTo;
|
|
||||||
BigInteger.prototype.subTo = bnpSubTo;
|
|
||||||
BigInteger.prototype.multiplyTo = bnpMultiplyTo;
|
|
||||||
BigInteger.prototype.squareTo = bnpSquareTo;
|
|
||||||
BigInteger.prototype.divRemTo = bnpDivRemTo;
|
|
||||||
BigInteger.prototype.invDigit = bnpInvDigit;
|
|
||||||
BigInteger.prototype.isEven = bnpIsEven;
|
|
||||||
BigInteger.prototype.exp = bnpExp;
|
|
||||||
|
|
||||||
// public
|
|
||||||
BigInteger.prototype.toString = bnToString;
|
|
||||||
BigInteger.prototype.negate = bnNegate;
|
|
||||||
BigInteger.prototype.abs = bnAbs;
|
|
||||||
BigInteger.prototype.compareTo = bnCompareTo;
|
|
||||||
BigInteger.prototype.bitLength = bnBitLength;
|
|
||||||
BigInteger.prototype.mod = bnMod;
|
|
||||||
BigInteger.prototype.modPowInt = bnModPowInt;
|
|
||||||
|
|
||||||
// "constants"
|
|
||||||
BigInteger.ZERO = nbv(0);
|
|
||||||
BigInteger.ONE = nbv(1);
|
|
||||||
|
|
294
src/crypto/cfb.js
Normal file
294
src/crypto/cfb.js
Normal file
|
@ -0,0 +1,294 @@
|
||||||
|
// Modified by Recurity Labs GmbH
|
||||||
|
|
||||||
|
// modified version of http://www.hanewin.net/encrypt/PGdecode.js:
|
||||||
|
|
||||||
|
/* OpenPGP encryption using RSA/AES
|
||||||
|
* Copyright 2005-2006 Herbert Hanewinkel, www.haneWIN.de
|
||||||
|
* version 2.0, check www.haneWIN.de for the latest version
|
||||||
|
|
||||||
|
* This software is provided as-is, without express or implied warranty.
|
||||||
|
* Permission to use, copy, modify, distribute or sell this software, with or
|
||||||
|
* without fee, for any purpose and by any individual or organization, is hereby
|
||||||
|
* granted, provided that the above copyright notice and this paragraph appear
|
||||||
|
* in all copies. Distribution as a part of an application or binary must
|
||||||
|
* include the above copyright notice in the documentation and/or other
|
||||||
|
* materials provided with the application or distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var util = require('../util');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of bytes, that is integers with values from 0 to 255
|
||||||
|
* @typedef {(Array|Uint8Array)} openpgp_byte_array
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block cipher function
|
||||||
|
* @callback openpgp_cipher_block_fn
|
||||||
|
* @param {openpgp_byte_array} block A block to perform operations on
|
||||||
|
* @param {openpgp_byte_array} key to use in encryption/decryption
|
||||||
|
* @return {openpgp_byte_array} Encrypted/decrypted block
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------------------------
|
||||||
|
/**
|
||||||
|
* This function encrypts a given with the specified prefixrandom
|
||||||
|
* using the specified blockcipher to encrypt a message
|
||||||
|
* @param {String} prefixrandom random bytes of block_size length provided
|
||||||
|
* as a string to be used in prefixing the data
|
||||||
|
* @param {openpgp_cipher_block_fn} blockcipherfn the algorithm encrypt function to encrypt
|
||||||
|
* data in one block_size encryption.
|
||||||
|
* @param {Integer} block_size the block size in bytes of the algorithm used
|
||||||
|
* @param {String} plaintext data to be encrypted provided as a string
|
||||||
|
* @param {openpgp_byte_array} key key to be used to encrypt the data. This will be passed to the
|
||||||
|
* blockcipherfn
|
||||||
|
* @param {Boolean} resync a boolean value specifying if a resync of the
|
||||||
|
* IV should be used or not. The encrypteddatapacket uses the
|
||||||
|
* "old" style with a resync. Encryption within an
|
||||||
|
* encryptedintegrityprotecteddata packet is not resyncing the IV.
|
||||||
|
* @return {String} a string with the encrypted data
|
||||||
|
*/
|
||||||
|
encrypt: function (prefixrandom, blockcipherencryptfn, plaintext, block_size, key, resync) {
|
||||||
|
var FR = new Array(block_size);
|
||||||
|
var FRE = new Array(block_size);
|
||||||
|
|
||||||
|
prefixrandom = prefixrandom + prefixrandom.charAt(block_size-2) +prefixrandom.charAt(block_size-1);
|
||||||
|
util.print_debug("prefixrandom:"+util.hexstrdump(prefixrandom));
|
||||||
|
var ciphertext = "";
|
||||||
|
// 1. The feedback register (FR) is set to the IV, which is all zeros.
|
||||||
|
for (var i = 0; i < block_size; i++) FR[i] = 0;
|
||||||
|
|
||||||
|
// 2. FR is encrypted to produce FRE (FR Encrypted). This is the
|
||||||
|
// encryption of an all-zero value.
|
||||||
|
FRE = blockcipherencryptfn(FR, key);
|
||||||
|
// 3. FRE is xored with the first BS octets of random data prefixed to
|
||||||
|
// the plaintext to produce C[1] through C[BS], the first BS octets
|
||||||
|
// of ciphertext.
|
||||||
|
for (var i = 0; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ prefixrandom.charCodeAt(i));
|
||||||
|
|
||||||
|
// 4. FR is loaded with C[1] through C[BS].
|
||||||
|
for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i);
|
||||||
|
|
||||||
|
// 5. FR is encrypted to produce FRE, the encryption of the first BS
|
||||||
|
// octets of ciphertext.
|
||||||
|
FRE = blockcipherencryptfn(FR, key);
|
||||||
|
|
||||||
|
// 6. The left two octets of FRE get xored with the next two octets of
|
||||||
|
// data that were prefixed to the plaintext. This produces C[BS+1]
|
||||||
|
// and C[BS+2], the next two octets of ciphertext.
|
||||||
|
ciphertext += String.fromCharCode(FRE[0] ^ prefixrandom.charCodeAt(block_size));
|
||||||
|
ciphertext += String.fromCharCode(FRE[1] ^ prefixrandom.charCodeAt(block_size+1));
|
||||||
|
|
||||||
|
if (resync) {
|
||||||
|
// 7. (The resync step) FR is loaded with C3-C10.
|
||||||
|
for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i+2);
|
||||||
|
} else {
|
||||||
|
for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i);
|
||||||
|
}
|
||||||
|
// 8. FR is encrypted to produce FRE.
|
||||||
|
FRE = blockcipherencryptfn(FR, key);
|
||||||
|
|
||||||
|
if (resync) {
|
||||||
|
// 9. FRE is xored with the first 8 octets of the given plaintext, now
|
||||||
|
// that we have finished encrypting the 10 octets of prefixed data.
|
||||||
|
// This produces C11-C18, the next 8 octets of ciphertext.
|
||||||
|
for (var i = 0; i < block_size; i++)
|
||||||
|
ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(i));
|
||||||
|
for(n=block_size+2; n < plaintext.length; n+=block_size) {
|
||||||
|
// 10. FR is loaded with C11-C18
|
||||||
|
for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(n+i);
|
||||||
|
|
||||||
|
// 11. FR is encrypted to produce FRE.
|
||||||
|
FRE = blockcipherencryptfn(FR, key);
|
||||||
|
|
||||||
|
// 12. FRE is xored with the next 8 octets of plaintext, to produce the
|
||||||
|
// next 8 octets of ciphertext. These are loaded into FR and the
|
||||||
|
// process is repeated until the plaintext is used up.
|
||||||
|
for (var i = 0; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt((n-2)+i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
plaintext = " "+plaintext;
|
||||||
|
// 9. FRE is xored with the first 8 octets of the given plaintext, now
|
||||||
|
// that we have finished encrypting the 10 octets of prefixed data.
|
||||||
|
// This produces C11-C18, the next 8 octets of ciphertext.
|
||||||
|
for (var i = 2; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(i));
|
||||||
|
var tempCiphertext = ciphertext.substring(0,2*block_size).split('');
|
||||||
|
var tempCiphertextString = ciphertext.substring(block_size);
|
||||||
|
for(n=block_size; n<plaintext.length; n+=block_size) {
|
||||||
|
// 10. FR is loaded with C11-C18
|
||||||
|
for (var i = 0; i < block_size; i++) FR[i] = tempCiphertextString.charCodeAt(i);
|
||||||
|
tempCiphertextString='';
|
||||||
|
|
||||||
|
// 11. FR is encrypted to produce FRE.
|
||||||
|
FRE = blockcipherencryptfn(FR, key);
|
||||||
|
|
||||||
|
// 12. FRE is xored with the next 8 octets of plaintext, to produce the
|
||||||
|
// next 8 octets of ciphertext. These are loaded into FR and the
|
||||||
|
// process is repeated until the plaintext is used up.
|
||||||
|
for (var i = 0; i < block_size; i++){ tempCiphertext.push(String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(n+i)));
|
||||||
|
tempCiphertextString += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(n+i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ciphertext = tempCiphertext.join('');
|
||||||
|
|
||||||
|
}
|
||||||
|
return ciphertext;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypts the prefixed data for the Modification Detection Code (MDC) computation
|
||||||
|
* @param {openpgp_block_cipher_fn} blockcipherencryptfn Cipher function to use
|
||||||
|
* @param {Integer} block_size Blocksize of the algorithm
|
||||||
|
* @param {openpgp_byte_array} key The key for encryption
|
||||||
|
* @param {String} ciphertext The encrypted data
|
||||||
|
* @return {String} plaintext Data of D(ciphertext) with blocksize length +2
|
||||||
|
*/
|
||||||
|
mdc: function (blockcipherencryptfn, block_size, key, ciphertext) {
|
||||||
|
var iblock = new Array(block_size);
|
||||||
|
var ablock = new Array(block_size);
|
||||||
|
var i;
|
||||||
|
|
||||||
|
// initialisation vector
|
||||||
|
for(i=0; i < block_size; i++) iblock[i] = 0;
|
||||||
|
|
||||||
|
iblock = blockcipherencryptfn(iblock, key);
|
||||||
|
for(i = 0; i < block_size; i++)
|
||||||
|
{
|
||||||
|
ablock[i] = ciphertext.charCodeAt(i);
|
||||||
|
iblock[i] ^= ablock[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
ablock = blockcipherencryptfn(ablock, key);
|
||||||
|
|
||||||
|
return util.bin2str(iblock)+
|
||||||
|
String.fromCharCode(ablock[0]^ciphertext.charCodeAt(block_size))+
|
||||||
|
String.fromCharCode(ablock[1]^ciphertext.charCodeAt(block_size+1));
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* This function decrypts a given plaintext using the specified
|
||||||
|
* blockcipher to decrypt a message
|
||||||
|
* @param {openpgp_cipher_block_fn} blockcipherfn The algorithm _encrypt_ function to encrypt
|
||||||
|
* data in one block_size encryption.
|
||||||
|
* @param {Integer} block_size the block size in bytes of the algorithm used
|
||||||
|
* @param {String} plaintext ciphertext to be decrypted provided as a string
|
||||||
|
* @param {openpgp_byte_array} key key to be used to decrypt the ciphertext. This will be passed to the
|
||||||
|
* blockcipherfn
|
||||||
|
* @param {Boolean} resync a boolean value specifying if a resync of the
|
||||||
|
* IV should be used or not. The encrypteddatapacket uses the
|
||||||
|
* "old" style with a resync. Decryption within an
|
||||||
|
* encryptedintegrityprotecteddata packet is not resyncing the IV.
|
||||||
|
* @return {String} a string with the plaintext data
|
||||||
|
*/
|
||||||
|
|
||||||
|
decrypt: function (blockcipherencryptfn, block_size, key, ciphertext, resync)
|
||||||
|
{
|
||||||
|
util.print_debug("resync:"+resync);
|
||||||
|
var iblock = new Array(block_size);
|
||||||
|
var ablock = new Array(block_size);
|
||||||
|
var i, n = '';
|
||||||
|
var text = [];
|
||||||
|
|
||||||
|
// initialisation vector
|
||||||
|
for(i=0; i < block_size; i++) iblock[i] = 0;
|
||||||
|
|
||||||
|
iblock = blockcipherencryptfn(iblock, key);
|
||||||
|
for(i = 0; i < block_size; i++)
|
||||||
|
{
|
||||||
|
ablock[i] = ciphertext.charCodeAt(i);
|
||||||
|
iblock[i] ^= ablock[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
ablock = blockcipherencryptfn(ablock, key);
|
||||||
|
|
||||||
|
util.print_debug("openpgp_cfb_decrypt:\niblock:"+util.hexidump(iblock)+"\nablock:"+util.hexidump(ablock)+"\n");
|
||||||
|
util.print_debug((ablock[0]^ciphertext.charCodeAt(block_size)).toString(16)+(ablock[1]^ciphertext.charCodeAt(block_size+1)).toString(16));
|
||||||
|
|
||||||
|
// test check octets
|
||||||
|
if(iblock[block_size-2]!=(ablock[0]^ciphertext.charCodeAt(block_size))
|
||||||
|
|| iblock[block_size-1]!=(ablock[1]^ciphertext.charCodeAt(block_size+1)))
|
||||||
|
{
|
||||||
|
util.print_eror("error duding decryption. Symmectric encrypted data not valid.");
|
||||||
|
return text.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RFC4880: Tag 18 and Resync:
|
||||||
|
* [...] Unlike the Symmetrically Encrypted Data Packet, no
|
||||||
|
* special CFB resynchronization is done after encrypting this prefix
|
||||||
|
* data. See "OpenPGP CFB Mode" below for more details.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (resync) {
|
||||||
|
for(i=0; i<block_size; i++) iblock[i] = ciphertext.charCodeAt(i+2);
|
||||||
|
for(n=block_size+2; n<ciphertext.length; n+=block_size)
|
||||||
|
{
|
||||||
|
ablock = blockcipherencryptfn(iblock, key);
|
||||||
|
|
||||||
|
for(i = 0; i<block_size && i+n < ciphertext.length; i++)
|
||||||
|
{
|
||||||
|
iblock[i] = ciphertext.charCodeAt(n+i);
|
||||||
|
text.push(String.fromCharCode(ablock[i]^iblock[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(i=0; i<block_size; i++) iblock[i] = ciphertext.charCodeAt(i);
|
||||||
|
for(n=block_size; n<ciphertext.length; n+=block_size)
|
||||||
|
{
|
||||||
|
ablock = blockcipherencryptfn(iblock, key);
|
||||||
|
for(i = 0; i<block_size && i+n < ciphertext.length; i++)
|
||||||
|
{
|
||||||
|
iblock[i] = ciphertext.charCodeAt(n+i);
|
||||||
|
text.push(String.fromCharCode(ablock[i]^iblock[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return text.join('');
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
normalEncrypt: function(blockcipherencryptfn, block_size, key, plaintext, iv) {
|
||||||
|
var blocki ="";
|
||||||
|
var blockc = "";
|
||||||
|
var pos = 0;
|
||||||
|
var cyphertext = [];
|
||||||
|
var tempBlock = [];
|
||||||
|
blockc = iv.substring(0,block_size);
|
||||||
|
while (plaintext.length > block_size*pos) {
|
||||||
|
var encblock = blockcipherencryptfn(blockc, key);
|
||||||
|
blocki = plaintext.substring((pos*block_size),(pos*block_size)+block_size);
|
||||||
|
for (var i=0; i < blocki.length; i++)
|
||||||
|
tempBlock.push(String.fromCharCode(blocki.charCodeAt(i) ^ encblock[i]));
|
||||||
|
blockc = tempBlock.join('');
|
||||||
|
tempBlock = [];
|
||||||
|
cyphertext.push(blockc);
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
return cyphertext.join('');
|
||||||
|
},
|
||||||
|
|
||||||
|
normalDecrypt: function(blockcipherencryptfn, block_size, key, ciphertext, iv) {
|
||||||
|
var blockp ="";
|
||||||
|
var pos = 0;
|
||||||
|
var plaintext = [];
|
||||||
|
var offset = 0;
|
||||||
|
if (iv == null)
|
||||||
|
for (var i = 0; i < block_size; i++) blockp += String.fromCharCode(0);
|
||||||
|
else
|
||||||
|
blockp = iv.substring(0,block_size);
|
||||||
|
while (ciphertext.length > (block_size*pos)) {
|
||||||
|
var decblock = blockcipherencryptfn(blockp, key);
|
||||||
|
blockp = ciphertext.substring((pos*(block_size))+offset,(pos*(block_size))+(block_size)+offset);
|
||||||
|
for (var i=0; i < blockp.length; i++) {
|
||||||
|
plaintext.push(String.fromCharCode(blockp.charCodeAt(i) ^ decblock[i]));
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return plaintext.join('');
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,7 +12,7 @@
|
||||||
* materials provided with the application or distribution.
|
* materials provided with the application or distribution.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var util = require('../../util/util.js');
|
var util = require('../../util');
|
||||||
|
|
||||||
// The round constants used in subkey expansion
|
// The round constants used in subkey expansion
|
||||||
var Rcon = [
|
var Rcon = [
|
||||||
|
@ -486,6 +486,6 @@ function AESencrypt(block, ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
AESencrypt: AESencrypt,
|
encrypt: AESencrypt,
|
||||||
keyExpansion: keyExpansion
|
keyExpansion: keyExpansion
|
||||||
}
|
}
|
|
@ -385,7 +385,7 @@ Blowfish.prototype.init = function ( key ) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var util = require('../../util/util.js');
|
var util = require('../../util');
|
||||||
|
|
||||||
// added by Recurity Labs
|
// added by Recurity Labs
|
||||||
function BFencrypt(block,key) {
|
function BFencrypt(block,key) {
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
// CAST5 constructor
|
// CAST5 constructor
|
||||||
|
|
||||||
var util = require('../../util/util.js');
|
var util = require('../../util');
|
||||||
|
|
||||||
function cast5_encrypt(block, key) {
|
function cast5_encrypt(block, key) {
|
||||||
var cast5 = new openpgp_symenc_cast5();
|
var cast5 = new openpgp_symenc_cast5();
|
|
@ -21,7 +21,7 @@
|
||||||
//des
|
//des
|
||||||
//this takes the key, the message, and whether to encrypt or decrypt
|
//this takes the key, the message, and whether to encrypt or decrypt
|
||||||
|
|
||||||
var util = require('../../util/util.js');
|
var util = require('../../util');
|
||||||
|
|
||||||
// added by Recurity Labs
|
// added by Recurity Labs
|
||||||
function desede(block,key) {
|
function desede(block,key) {
|
9
src/crypto/cipher/index.js
Normal file
9
src/crypto/cipher/index.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
aes: require('./aes.js'),
|
||||||
|
des: require('./des.js'),
|
||||||
|
cast5: require('./cast5.js'),
|
||||||
|
twofish: require('./twofish.js'),
|
||||||
|
blowfish: require('./blowfish.js')
|
||||||
|
}
|
||||||
|
|
5
src/crypto/cipher/package.json
Normal file
5
src/crypto/cipher/package.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"name": "openpgp-crypto-cipher",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"main": "./index.js"
|
||||||
|
}
|
|
@ -18,7 +18,7 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var util = require('../../util/util.js');
|
var util = require('../../util');
|
||||||
|
|
||||||
// added by Recurity Labs
|
// added by Recurity Labs
|
||||||
function TFencrypt(block, key) {
|
function TFencrypt(block, key) {
|
|
@ -17,6 +17,11 @@
|
||||||
|
|
||||||
// The GPG4Browsers crypto interface
|
// The GPG4Browsers crypto interface
|
||||||
|
|
||||||
|
var random = require('./random.js'),
|
||||||
|
publicKey= require('./public_key'),
|
||||||
|
type_mpi = require('../type/mpi.js');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
/**
|
/**
|
||||||
* Encrypts data using the specified public key multiprecision integers
|
* Encrypts data using the specified public key multiprecision integers
|
||||||
* and the specified algorithm.
|
* and the specified algorithm.
|
||||||
|
@ -26,19 +31,19 @@
|
||||||
* @return {openpgp_type_mpi[]} if RSA an openpgp_type_mpi;
|
* @return {openpgp_type_mpi[]} if RSA an openpgp_type_mpi;
|
||||||
* if elgamal encryption an array of two openpgp_type_mpi is returned; otherwise null
|
* if elgamal encryption an array of two openpgp_type_mpi is returned; otherwise null
|
||||||
*/
|
*/
|
||||||
function openpgp_crypto_asymetricEncrypt(algo, publicMPIs, data) {
|
publicKeyEncrypt: function(algo, publicMPIs, data) {
|
||||||
var result = (function() {
|
var result = (function() {
|
||||||
switch(algo) {
|
switch(algo) {
|
||||||
case 1: // RSA (Encrypt or Sign) [HAC]
|
case 1: // RSA (Encrypt or Sign) [HAC]
|
||||||
case 2: // RSA Encrypt-Only [HAC]
|
case 2: // RSA Encrypt-Only [HAC]
|
||||||
case 3: // RSA Sign-Only [HAC]
|
case 3: // RSA Sign-Only [HAC]
|
||||||
var rsa = new RSA();
|
var rsa = new publicKey.rsa();
|
||||||
var n = publicMPIs[0].toBigInteger();
|
var n = publicMPIs[0].toBigInteger();
|
||||||
var e = publicMPIs[1].toBigInteger();
|
var e = publicMPIs[1].toBigInteger();
|
||||||
var m = data.toBigInteger();
|
var m = data.toBigInteger();
|
||||||
return [rsa.encrypt(m,e,n)];
|
return [rsa.encrypt(m,e,n)];
|
||||||
case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
|
case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
|
||||||
var elgamal = new Elgamal();
|
var elgamal = new publicKey.elgamal();
|
||||||
var p = publicMPIs[0].toBigInteger();
|
var p = publicMPIs[0].toBigInteger();
|
||||||
var g = publicMPIs[1].toBigInteger();
|
var g = publicMPIs[1].toBigInteger();
|
||||||
var y = publicMPIs[2].toBigInteger();
|
var y = publicMPIs[2].toBigInteger();
|
||||||
|
@ -50,11 +55,11 @@ function openpgp_crypto_asymetricEncrypt(algo, publicMPIs, data) {
|
||||||
})();
|
})();
|
||||||
|
|
||||||
return result.map(function(bn) {
|
return result.map(function(bn) {
|
||||||
var mpi = new openpgp_type_mpi();
|
var mpi = new type_mpi();
|
||||||
mpi.fromBigInteger(bn);
|
mpi.fromBigInteger(bn);
|
||||||
return mpi;
|
return mpi;
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrypts data using the specified public key multiprecision integers of the private key,
|
* Decrypts data using the specified public key multiprecision integers of the private key,
|
||||||
|
@ -68,13 +73,13 @@ function openpgp_crypto_asymetricEncrypt(algo, publicMPIs, data) {
|
||||||
* @return {openpgp_type_mpi} returns a big integer containing the decrypted data; otherwise null
|
* @return {openpgp_type_mpi} returns a big integer containing the decrypted data; otherwise null
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function openpgp_crypto_asymetricDecrypt(algo, keyIntegers, dataIntegers) {
|
publicKeyDecrypt: function (algo, keyIntegers, dataIntegers) {
|
||||||
var bn = (function() {
|
var bn = (function() {
|
||||||
switch(algo) {
|
switch(algo) {
|
||||||
case 1: // RSA (Encrypt or Sign) [HAC]
|
case 1: // RSA (Encrypt or Sign) [HAC]
|
||||||
case 2: // RSA Encrypt-Only [HAC]
|
case 2: // RSA Encrypt-Only [HAC]
|
||||||
case 3: // RSA Sign-Only [HAC]
|
case 3: // RSA Sign-Only [HAC]
|
||||||
var rsa = new RSA();
|
var rsa = new publicKey.rsa();
|
||||||
// 0 and 1 are the public key.
|
// 0 and 1 are the public key.
|
||||||
var d = keyIntegers[2].toBigInteger();
|
var d = keyIntegers[2].toBigInteger();
|
||||||
var p = keyIntegers[3].toBigInteger();
|
var p = keyIntegers[3].toBigInteger();
|
||||||
|
@ -83,7 +88,7 @@ function openpgp_crypto_asymetricDecrypt(algo, keyIntegers, dataIntegers) {
|
||||||
var m = dataIntegers[0].toBigInteger();
|
var m = dataIntegers[0].toBigInteger();
|
||||||
return rsa.decrypt(m, d, p, q, u);
|
return rsa.decrypt(m, d, p, q, u);
|
||||||
case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
|
case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
|
||||||
var elgamal = new Elgamal();
|
var elgamal = new publicKey.elgamal();
|
||||||
var x = keyIntegers[3].toBigInteger();
|
var x = keyIntegers[3].toBigInteger();
|
||||||
var c1 = dataIntegers[0].toBigInteger();
|
var c1 = dataIntegers[0].toBigInteger();
|
||||||
var c2 = dataIntegers[1].toBigInteger();
|
var c2 = dataIntegers[1].toBigInteger();
|
||||||
|
@ -94,16 +99,16 @@ function openpgp_crypto_asymetricDecrypt(algo, keyIntegers, dataIntegers) {
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var result = new openpgp_type_mpi();
|
var result = new type_mpi();
|
||||||
result.fromBigInteger(bn);
|
result.fromBigInteger(bn);
|
||||||
return result;
|
return result;
|
||||||
}
|
},
|
||||||
|
|
||||||
/** Returns the number of integers comprising the private key of an algorithm
|
/** Returns the number of integers comprising the private key of an algorithm
|
||||||
* @param {openpgp.publickey} algo The public key algorithm
|
* @param {openpgp.publickey} algo The public key algorithm
|
||||||
* @return {Integer} The number of integers.
|
* @return {Integer} The number of integers.
|
||||||
*/
|
*/
|
||||||
function openpgp_crypto_getPrivateMpiCount(algo) {
|
getPrivateMpiCount: function(algo) {
|
||||||
if (algo > 0 && algo < 4) {
|
if (algo > 0 && algo < 4) {
|
||||||
// Algorithm-Specific Fields for RSA secret keys:
|
// Algorithm-Specific Fields for RSA secret keys:
|
||||||
// - multiprecision integer (MPI) of RSA secret exponent d.
|
// - multiprecision integer (MPI) of RSA secret exponent d.
|
||||||
|
@ -121,9 +126,9 @@ function openpgp_crypto_getPrivateMpiCount(algo) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else return 0;
|
else return 0;
|
||||||
}
|
},
|
||||||
|
|
||||||
function openpgp_crypto_getPublicMpiCount(algorithm) {
|
getPublicMpiCount: function(algorithm) {
|
||||||
// - A series of multiprecision integers comprising the key material:
|
// - A series of multiprecision integers comprising the key material:
|
||||||
// Algorithm-Specific Fields for RSA public keys:
|
// Algorithm-Specific Fields for RSA public keys:
|
||||||
// - a multiprecision integer (MPI) of RSA public modulus n;
|
// - a multiprecision integer (MPI) of RSA public modulus n;
|
||||||
|
@ -147,7 +152,7 @@ function openpgp_crypto_getPublicMpiCount(algorithm) {
|
||||||
return 4;
|
return 4;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
};
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -156,21 +161,21 @@ function openpgp_crypto_getPublicMpiCount(algorithm) {
|
||||||
* @return {String} Random bytes with length equal to the block
|
* @return {String} Random bytes with length equal to the block
|
||||||
* size of the cipher
|
* size of the cipher
|
||||||
*/
|
*/
|
||||||
function openpgp_crypto_getPrefixRandom(algo) {
|
getPrefixRandom: function(algo) {
|
||||||
switch(algo) {
|
switch(algo) {
|
||||||
case 2:
|
case 2:
|
||||||
case 3:
|
case 3:
|
||||||
case 4:
|
case 4:
|
||||||
return openpgp_crypto_getRandomBytes(8);
|
return random.getRandomBytes(8);
|
||||||
case 7:
|
case 7:
|
||||||
case 8:
|
case 8:
|
||||||
case 9:
|
case 9:
|
||||||
case 10:
|
case 10:
|
||||||
return openpgp_crypto_getRandomBytes(16);
|
return random.getRandomBytes(16);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* retrieve the MDC prefixed bytes by decrypting them
|
* retrieve the MDC prefixed bytes by decrypting them
|
||||||
|
@ -179,8 +184,7 @@ function openpgp_crypto_getPrefixRandom(algo) {
|
||||||
* @param {String} data Encrypted data where the prefix is decrypted from
|
* @param {String} data Encrypted data where the prefix is decrypted from
|
||||||
* @return {String} Plain text data of the prefixed data
|
* @return {String} Plain text data of the prefixed data
|
||||||
*/
|
*/
|
||||||
function openpgp_crypto_MDCSystemBytes(algo, key, data) {
|
MDCSystemBytes: function(algo, key, data) {
|
||||||
util.print_debug_hexstr_dump("openpgp_crypto_symmetricDecrypt:\nencrypteddata:",data);
|
|
||||||
switch(algo) {
|
switch(algo) {
|
||||||
case 0: // Plaintext or unencrypted data
|
case 0: // Plaintext or unencrypted data
|
||||||
return data;
|
return data;
|
||||||
|
@ -197,27 +201,26 @@ function openpgp_crypto_MDCSystemBytes(algo, key, data) {
|
||||||
case 10:
|
case 10:
|
||||||
return openpgp_cfb_mdc(TFencrypt, 16, key, data);
|
return openpgp_cfb_mdc(TFencrypt, 16, key, data);
|
||||||
case 1: // IDEA [IDEA]
|
case 1: // IDEA [IDEA]
|
||||||
util.print_error(""+ (algo == 1 ? "IDEA Algorithm not implemented" : "Twofish Algorithm not implemented"));
|
throw new Error('IDEA Algorithm not implemented');
|
||||||
return null;
|
|
||||||
default:
|
default:
|
||||||
|
throw new Error('Invalid algorithm.');
|
||||||
}
|
}
|
||||||
return null;
|
},
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Generating a session key for the specified symmetric algorithm
|
* Generating a session key for the specified symmetric algorithm
|
||||||
* @param {Integer} algo Algorithm to use (see RFC4880 9.2)
|
* @param {Integer} algo Algorithm to use (see RFC4880 9.2)
|
||||||
* @return {String} Random bytes as a string to be used as a key
|
* @return {String} Random bytes as a string to be used as a key
|
||||||
*/
|
*/
|
||||||
function openpgp_crypto_generateSessionKey(algo) {
|
generateSessionKey: function(algo) {
|
||||||
return openpgp_crypto_getRandomBytes(openpgp_crypto_getKeyLength(algo));
|
return random.getRandomBytes(this.getKeyLength(algo));
|
||||||
}
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the key length by symmetric algorithm id.
|
* Get the key length by symmetric algorithm id.
|
||||||
* @param {Integer} algo Algorithm to use (see RFC4880 9.2)
|
* @param {Integer} algo Algorithm to use (see RFC4880 9.2)
|
||||||
* @return {String} Random bytes as a string to be used as a key
|
* @return {String} Random bytes as a string to be used as a key
|
||||||
*/
|
*/
|
||||||
function openpgp_crypto_getKeyLength(algo) {
|
getKeyLength: function(algo) {
|
||||||
switch (algo) {
|
switch (algo) {
|
||||||
case 2: // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
|
case 2: // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
|
||||||
case 8: // AES with 192-bit key
|
case 8: // AES with 192-bit key
|
||||||
|
@ -231,14 +234,14 @@ function openpgp_crypto_getKeyLength(algo) {
|
||||||
return 32;
|
return 32;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the block length of the specified symmetric encryption algorithm
|
* Returns the block length of the specified symmetric encryption algorithm
|
||||||
* @param {openpgp.symmetric} algo Symmetric algorithm idenhifier
|
* @param {openpgp.symmetric} algo Symmetric algorithm idenhifier
|
||||||
* @return {Integer} The number of bytes in a single block encrypted by the algorithm
|
* @return {Integer} The number of bytes in a single block encrypted by the algorithm
|
||||||
*/
|
*/
|
||||||
function openpgp_crypto_getBlockLength(algo) {
|
getBlockLength: function(algo) {
|
||||||
switch (algo) {
|
switch (algo) {
|
||||||
case 1: // - IDEA [IDEA]
|
case 1: // - IDEA [IDEA]
|
||||||
case 2: // - TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
|
case 2: // - TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
|
||||||
|
@ -254,214 +257,19 @@ function openpgp_crypto_getBlockLength(algo) {
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @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;
|
|
||||||
}
|
|
||||||
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 {openpgp_type_mpi[]}
|
|
||||||
*/
|
|
||||||
function openpgp_crypto_signData(hash_algo, algo, keyIntegers, data) {
|
|
||||||
|
|
||||||
switch(algo) {
|
|
||||||
case 1: // RSA (Encrypt or Sign) [HAC]
|
|
||||||
case 2: // RSA Encrypt-Only [HAC]
|
|
||||||
case 3: // RSA Sign-Only [HAC]
|
|
||||||
var rsa = new RSA();
|
|
||||||
var d = keyIntegers[2].toBigInteger();
|
|
||||||
var n = keyIntegers[0].toBigInteger();
|
|
||||||
var m = openpgp_encoding_emsa_pkcs1_encode(hash_algo,
|
|
||||||
data, keyIntegers[0].byteLength());
|
|
||||||
|
|
||||||
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:"+keyIntegers[1].getByteLength());
|
|
||||||
var p = keyIntegers[0].toBigInteger();
|
|
||||||
var q = keyIntegers[1].toBigInteger();
|
|
||||||
var g = keyIntegers[2].toBigInteger();
|
|
||||||
var y = keyIntegers[3].toBigInteger();
|
|
||||||
var x = keyIntegers[4].toBigInteger();
|
|
||||||
var m = data;
|
|
||||||
var result = dsa.sign(hash_algo,m, g, p, q, x);
|
|
||||||
util.print_debug("signing using DSA\n result:"+util.hexstrdump(result[0])+"|"+util.hexstrdump(result[1]));
|
|
||||||
return result[0].toString() + result[1].toString();
|
|
||||||
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
|
* Create a secure random big integer of bits length
|
||||||
* @param {Integer} bits Bit length of the MPI to create
|
* @param {Integer} bits Bit length of the MPI to create
|
||||||
* @return {BigInteger} Resulting big integer
|
* @return {BigInteger} Resulting big integer
|
||||||
*/
|
*/
|
||||||
function openpgp_crypto_getRandomBigInteger(bits) {
|
getRandomBigInteger: function(bits) {
|
||||||
if (bits < 0)
|
if (bits < 0)
|
||||||
return null;
|
return null;
|
||||||
var numBytes = Math.floor((bits+7)/8);
|
var numBytes = Math.floor((bits+7)/8);
|
||||||
|
|
||||||
var randomBits = openpgp_crypto_getRandomBytes(numBytes);
|
var randomBits = random.getRandomBytes(numBytes);
|
||||||
if (bits % 8 > 0) {
|
if (bits % 8 > 0) {
|
||||||
|
|
||||||
randomBits = String.fromCharCode(
|
randomBits = String.fromCharCode(
|
||||||
|
@ -470,9 +278,9 @@ function openpgp_crypto_getRandomBigInteger(bits) {
|
||||||
randomBits.substring(1);
|
randomBits.substring(1);
|
||||||
}
|
}
|
||||||
return new openpgp_type_mpi().create(randomBits).toBigInteger();
|
return new openpgp_type_mpi().create(randomBits).toBigInteger();
|
||||||
}
|
},
|
||||||
|
|
||||||
function openpgp_crypto_getRandomBigIntegerInRange(min, max) {
|
getRandomBigIntegerInRange: function(min, max) {
|
||||||
if (max.compareTo(min) <= 0)
|
if (max.compareTo(min) <= 0)
|
||||||
return;
|
return;
|
||||||
var range = max.subtract(min);
|
var range = max.subtract(min);
|
||||||
|
@ -481,18 +289,18 @@ function openpgp_crypto_getRandomBigIntegerInRange(min, max) {
|
||||||
r = openpgp_crypto_getRandomBigInteger(range.bitLength());
|
r = openpgp_crypto_getRandomBigInteger(range.bitLength());
|
||||||
}
|
}
|
||||||
return min.add(r);
|
return min.add(r);
|
||||||
}
|
},
|
||||||
|
|
||||||
|
|
||||||
//This is a test method to ensure that encryption/decryption with a given 1024bit RSAKey object functions as intended
|
//This is a test method to ensure that encryption/decryption with a given 1024bit RSAKey object functions as intended
|
||||||
function openpgp_crypto_testRSA(key){
|
testRSA: function(key){
|
||||||
debugger;
|
debugger;
|
||||||
var rsa = new RSA();
|
var rsa = new RSA();
|
||||||
var mpi = new openpgp_type_mpi();
|
var mpi = new openpgp_type_mpi();
|
||||||
mpi.create(openpgp_encoding_eme_pkcs1_encode('ABABABAB', 128));
|
mpi.create(openpgp_encoding_eme_pkcs1_encode('ABABABAB', 128));
|
||||||
var msg = rsa.encrypt(mpi.toBigInteger(),key.ee,key.n);
|
var msg = rsa.encrypt(mpi.toBigInteger(),key.ee,key.n);
|
||||||
var result = rsa.decrypt(msg, key.d, key.p, key.q, key.u);
|
var result = rsa.decrypt(msg, key.d, key.p, key.q, key.u);
|
||||||
}
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} openpgp_keypair
|
* @typedef {Object} openpgp_keypair
|
||||||
|
@ -507,7 +315,7 @@ function openpgp_crypto_testRSA(key){
|
||||||
* @param {Integer} numBits Number of bits to make the key to be generated
|
* @param {Integer} numBits Number of bits to make the key to be generated
|
||||||
* @return {openpgp_keypair}
|
* @return {openpgp_keypair}
|
||||||
*/
|
*/
|
||||||
function openpgp_crypto_generateKeyPair(keyType, numBits, passphrase, s2kHash, symmetricEncryptionAlgorithm){
|
generateKeyPair: function(keyType, numBits, passphrase, s2kHash, symmetricEncryptionAlgorithm){
|
||||||
var privKeyPacket;
|
var privKeyPacket;
|
||||||
var publicKeyPacket;
|
var publicKeyPacket;
|
||||||
var d = new Date();
|
var d = new Date();
|
||||||
|
@ -525,3 +333,5 @@ function openpgp_crypto_generateKeyPair(keyType, numBits, passphrase, s2kHash, s
|
||||||
}
|
}
|
||||||
return {privateKey: privKeyPacket, publicKey: publicKeyPacket};
|
return {privateKey: privKeyPacket, publicKey: publicKeyPacket};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
66
src/crypto/hash/index.js
Normal file
66
src/crypto/hash/index.js
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
|
||||||
|
var sha = require('./sha.js');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
md5: require('./md5.js'),
|
||||||
|
sha1: sha.sha1,
|
||||||
|
sha256: sha.sha256,
|
||||||
|
sha224: sha.sha224,
|
||||||
|
sha384: sha.sha384,
|
||||||
|
sha512: sha.sha512,
|
||||||
|
ripemd: require('./ripe-md.js'),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
digest: function(algo, data) {
|
||||||
|
switch(algo) {
|
||||||
|
case 1: // - MD5 [HAC]
|
||||||
|
return this.md5(data);
|
||||||
|
case 2: // - SHA-1 [FIPS180]
|
||||||
|
return this.sha1(data);
|
||||||
|
case 3: // - RIPE-MD/160 [HAC]
|
||||||
|
return this.ripemd(data);
|
||||||
|
case 8: // - SHA256 [FIPS180]
|
||||||
|
return this.sha256(data);
|
||||||
|
case 9: // - SHA384 [FIPS180]
|
||||||
|
return this.sha384(data);
|
||||||
|
case 10:// - SHA512 [FIPS180]
|
||||||
|
return this.sha512(data);
|
||||||
|
case 11:// - SHA224 [FIPS180]
|
||||||
|
return this.sha224(data);
|
||||||
|
default:
|
||||||
|
throw new Error('Invalid hash function.');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
getHashByteLength: function(algo) {
|
||||||
|
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;
|
||||||
|
default:
|
||||||
|
throw new Error('Invalid hash algorithm.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
5
src/crypto/hash/package.json
Normal file
5
src/crypto/hash/package.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"name": "openpgp-crypto-hash",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"main": "./index.js"
|
||||||
|
}
|
|
@ -1,16 +1,16 @@
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
cipher: {
|
cipher: require('./cipher'),
|
||||||
aes: require('./symmetric/aes.js'),
|
hash: require('./hash'),
|
||||||
des: require('./symmetric/dessrc.js'),
|
cfb: require('./cfb.js'),
|
||||||
cast5: require('./symmetric/cast5.js'),
|
publicKey: require('./public_key'),
|
||||||
twofish: require('./symmetric/twofish.js'),
|
signature: require('./signature.js'),
|
||||||
blowfish: require('./symmetric/blowfish.js')
|
|
||||||
},
|
|
||||||
hash: {
|
|
||||||
md5: require('./hash/md5.js'),
|
|
||||||
sha: require('./hash/sha.js'),
|
|
||||||
ripemd: require('./hash/ripe-md.js')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var crypto = require('./crypto.js');
|
||||||
|
|
||||||
|
for(var i in crypto)
|
||||||
|
module.exports[i] = crypto[i];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,289 +0,0 @@
|
||||||
// Modified by Recurity Labs GmbH
|
|
||||||
|
|
||||||
// modified version of http://www.hanewin.net/encrypt/PGdecode.js:
|
|
||||||
|
|
||||||
/* OpenPGP encryption using RSA/AES
|
|
||||||
* Copyright 2005-2006 Herbert Hanewinkel, www.haneWIN.de
|
|
||||||
* version 2.0, check www.haneWIN.de for the latest version
|
|
||||||
|
|
||||||
* This software is provided as-is, without express or implied warranty.
|
|
||||||
* Permission to use, copy, modify, distribute or sell this software, with or
|
|
||||||
* without fee, for any purpose and by any individual or organization, is hereby
|
|
||||||
* granted, provided that the above copyright notice and this paragraph appear
|
|
||||||
* in all copies. Distribution as a part of an application or binary must
|
|
||||||
* include the above copyright notice in the documentation and/or other
|
|
||||||
* materials provided with the application or distribution.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An array of bytes, that is integers with values from 0 to 255
|
|
||||||
* @typedef {(Array|Uint8Array)} openpgp_byte_array
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Block cipher function
|
|
||||||
* @callback openpgp_cipher_block_fn
|
|
||||||
* @param {openpgp_byte_array} block A block to perform operations on
|
|
||||||
* @param {openpgp_byte_array} key to use in encryption/decryption
|
|
||||||
* @return {openpgp_byte_array} Encrypted/decrypted block
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
// --------------------------------------
|
|
||||||
/**
|
|
||||||
* This function encrypts a given with the specified prefixrandom
|
|
||||||
* using the specified blockcipher to encrypt a message
|
|
||||||
* @param {String} prefixrandom random bytes of block_size length provided
|
|
||||||
* as a string to be used in prefixing the data
|
|
||||||
* @param {openpgp_cipher_block_fn} blockcipherfn the algorithm encrypt function to encrypt
|
|
||||||
* data in one block_size encryption.
|
|
||||||
* @param {Integer} block_size the block size in bytes of the algorithm used
|
|
||||||
* @param {String} plaintext data to be encrypted provided as a string
|
|
||||||
* @param {openpgp_byte_array} key key to be used to encrypt the data. This will be passed to the
|
|
||||||
* blockcipherfn
|
|
||||||
* @param {Boolean} resync a boolean value specifying if a resync of the
|
|
||||||
* IV should be used or not. The encrypteddatapacket uses the
|
|
||||||
* "old" style with a resync. Encryption within an
|
|
||||||
* encryptedintegrityprotecteddata packet is not resyncing the IV.
|
|
||||||
* @return {String} a string with the encrypted data
|
|
||||||
*/
|
|
||||||
function openpgp_cfb_encrypt(prefixrandom, blockcipherencryptfn, plaintext, block_size, key, resync) {
|
|
||||||
var FR = new Array(block_size);
|
|
||||||
var FRE = new Array(block_size);
|
|
||||||
|
|
||||||
prefixrandom = prefixrandom + prefixrandom.charAt(block_size-2) +prefixrandom.charAt(block_size-1);
|
|
||||||
util.print_debug("prefixrandom:"+util.hexstrdump(prefixrandom));
|
|
||||||
var ciphertext = "";
|
|
||||||
// 1. The feedback register (FR) is set to the IV, which is all zeros.
|
|
||||||
for (var i = 0; i < block_size; i++) FR[i] = 0;
|
|
||||||
|
|
||||||
// 2. FR is encrypted to produce FRE (FR Encrypted). This is the
|
|
||||||
// encryption of an all-zero value.
|
|
||||||
FRE = blockcipherencryptfn(FR, key);
|
|
||||||
// 3. FRE is xored with the first BS octets of random data prefixed to
|
|
||||||
// the plaintext to produce C[1] through C[BS], the first BS octets
|
|
||||||
// of ciphertext.
|
|
||||||
for (var i = 0; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ prefixrandom.charCodeAt(i));
|
|
||||||
|
|
||||||
// 4. FR is loaded with C[1] through C[BS].
|
|
||||||
for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i);
|
|
||||||
|
|
||||||
// 5. FR is encrypted to produce FRE, the encryption of the first BS
|
|
||||||
// octets of ciphertext.
|
|
||||||
FRE = blockcipherencryptfn(FR, key);
|
|
||||||
|
|
||||||
// 6. The left two octets of FRE get xored with the next two octets of
|
|
||||||
// data that were prefixed to the plaintext. This produces C[BS+1]
|
|
||||||
// and C[BS+2], the next two octets of ciphertext.
|
|
||||||
ciphertext += String.fromCharCode(FRE[0] ^ prefixrandom.charCodeAt(block_size));
|
|
||||||
ciphertext += String.fromCharCode(FRE[1] ^ prefixrandom.charCodeAt(block_size+1));
|
|
||||||
|
|
||||||
if (resync) {
|
|
||||||
// 7. (The resync step) FR is loaded with C3-C10.
|
|
||||||
for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i+2);
|
|
||||||
} else {
|
|
||||||
for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i);
|
|
||||||
}
|
|
||||||
// 8. FR is encrypted to produce FRE.
|
|
||||||
FRE = blockcipherencryptfn(FR, key);
|
|
||||||
|
|
||||||
if (resync) {
|
|
||||||
// 9. FRE is xored with the first 8 octets of the given plaintext, now
|
|
||||||
// that we have finished encrypting the 10 octets of prefixed data.
|
|
||||||
// This produces C11-C18, the next 8 octets of ciphertext.
|
|
||||||
for (var i = 0; i < block_size; i++)
|
|
||||||
ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(i));
|
|
||||||
for(n=block_size+2; n < plaintext.length; n+=block_size) {
|
|
||||||
// 10. FR is loaded with C11-C18
|
|
||||||
for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(n+i);
|
|
||||||
|
|
||||||
// 11. FR is encrypted to produce FRE.
|
|
||||||
FRE = blockcipherencryptfn(FR, key);
|
|
||||||
|
|
||||||
// 12. FRE is xored with the next 8 octets of plaintext, to produce the
|
|
||||||
// next 8 octets of ciphertext. These are loaded into FR and the
|
|
||||||
// process is repeated until the plaintext is used up.
|
|
||||||
for (var i = 0; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt((n-2)+i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
plaintext = " "+plaintext;
|
|
||||||
// 9. FRE is xored with the first 8 octets of the given plaintext, now
|
|
||||||
// that we have finished encrypting the 10 octets of prefixed data.
|
|
||||||
// This produces C11-C18, the next 8 octets of ciphertext.
|
|
||||||
for (var i = 2; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(i));
|
|
||||||
var tempCiphertext = ciphertext.substring(0,2*block_size).split('');
|
|
||||||
var tempCiphertextString = ciphertext.substring(block_size);
|
|
||||||
for(n=block_size; n<plaintext.length; n+=block_size) {
|
|
||||||
// 10. FR is loaded with C11-C18
|
|
||||||
for (var i = 0; i < block_size; i++) FR[i] = tempCiphertextString.charCodeAt(i);
|
|
||||||
tempCiphertextString='';
|
|
||||||
|
|
||||||
// 11. FR is encrypted to produce FRE.
|
|
||||||
FRE = blockcipherencryptfn(FR, key);
|
|
||||||
|
|
||||||
// 12. FRE is xored with the next 8 octets of plaintext, to produce the
|
|
||||||
// next 8 octets of ciphertext. These are loaded into FR and the
|
|
||||||
// process is repeated until the plaintext is used up.
|
|
||||||
for (var i = 0; i < block_size; i++){ tempCiphertext.push(String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(n+i)));
|
|
||||||
tempCiphertextString += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(n+i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ciphertext = tempCiphertext.join('');
|
|
||||||
|
|
||||||
}
|
|
||||||
return ciphertext;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decrypts the prefixed data for the Modification Detection Code (MDC) computation
|
|
||||||
* @param {openpgp_block_cipher_fn} blockcipherencryptfn Cipher function to use
|
|
||||||
* @param {Integer} block_size Blocksize of the algorithm
|
|
||||||
* @param {openpgp_byte_array} key The key for encryption
|
|
||||||
* @param {String} ciphertext The encrypted data
|
|
||||||
* @return {String} plaintext Data of D(ciphertext) with blocksize length +2
|
|
||||||
*/
|
|
||||||
function openpgp_cfb_mdc(blockcipherencryptfn, block_size, key, ciphertext) {
|
|
||||||
var iblock = new Array(block_size);
|
|
||||||
var ablock = new Array(block_size);
|
|
||||||
var i;
|
|
||||||
|
|
||||||
// initialisation vector
|
|
||||||
for(i=0; i < block_size; i++) iblock[i] = 0;
|
|
||||||
|
|
||||||
iblock = blockcipherencryptfn(iblock, key);
|
|
||||||
for(i = 0; i < block_size; i++)
|
|
||||||
{
|
|
||||||
ablock[i] = ciphertext.charCodeAt(i);
|
|
||||||
iblock[i] ^= ablock[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
ablock = blockcipherencryptfn(ablock, key);
|
|
||||||
|
|
||||||
return util.bin2str(iblock)+
|
|
||||||
String.fromCharCode(ablock[0]^ciphertext.charCodeAt(block_size))+
|
|
||||||
String.fromCharCode(ablock[1]^ciphertext.charCodeAt(block_size+1));
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This function decrypts a given plaintext using the specified
|
|
||||||
* blockcipher to decrypt a message
|
|
||||||
* @param {openpgp_cipher_block_fn} blockcipherfn The algorithm _encrypt_ function to encrypt
|
|
||||||
* data in one block_size encryption.
|
|
||||||
* @param {Integer} block_size the block size in bytes of the algorithm used
|
|
||||||
* @param {String} plaintext ciphertext to be decrypted provided as a string
|
|
||||||
* @param {openpgp_byte_array} key key to be used to decrypt the ciphertext. This will be passed to the
|
|
||||||
* blockcipherfn
|
|
||||||
* @param {Boolean} resync a boolean value specifying if a resync of the
|
|
||||||
* IV should be used or not. The encrypteddatapacket uses the
|
|
||||||
* "old" style with a resync. Decryption within an
|
|
||||||
* encryptedintegrityprotecteddata packet is not resyncing the IV.
|
|
||||||
* @return {String} a string with the plaintext data
|
|
||||||
*/
|
|
||||||
|
|
||||||
function openpgp_cfb_decrypt(blockcipherencryptfn, block_size, key, ciphertext, resync)
|
|
||||||
{
|
|
||||||
util.print_debug("resync:"+resync);
|
|
||||||
var iblock = new Array(block_size);
|
|
||||||
var ablock = new Array(block_size);
|
|
||||||
var i, n = '';
|
|
||||||
var text = [];
|
|
||||||
|
|
||||||
// initialisation vector
|
|
||||||
for(i=0; i < block_size; i++) iblock[i] = 0;
|
|
||||||
|
|
||||||
iblock = blockcipherencryptfn(iblock, key);
|
|
||||||
for(i = 0; i < block_size; i++)
|
|
||||||
{
|
|
||||||
ablock[i] = ciphertext.charCodeAt(i);
|
|
||||||
iblock[i] ^= ablock[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
ablock = blockcipherencryptfn(ablock, key);
|
|
||||||
|
|
||||||
util.print_debug("openpgp_cfb_decrypt:\niblock:"+util.hexidump(iblock)+"\nablock:"+util.hexidump(ablock)+"\n");
|
|
||||||
util.print_debug((ablock[0]^ciphertext.charCodeAt(block_size)).toString(16)+(ablock[1]^ciphertext.charCodeAt(block_size+1)).toString(16));
|
|
||||||
|
|
||||||
// test check octets
|
|
||||||
if(iblock[block_size-2]!=(ablock[0]^ciphertext.charCodeAt(block_size))
|
|
||||||
|| iblock[block_size-1]!=(ablock[1]^ciphertext.charCodeAt(block_size+1)))
|
|
||||||
{
|
|
||||||
util.print_eror("error duding decryption. Symmectric encrypted data not valid.");
|
|
||||||
return text.join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* RFC4880: Tag 18 and Resync:
|
|
||||||
* [...] Unlike the Symmetrically Encrypted Data Packet, no
|
|
||||||
* special CFB resynchronization is done after encrypting this prefix
|
|
||||||
* data. See "OpenPGP CFB Mode" below for more details.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (resync) {
|
|
||||||
for(i=0; i<block_size; i++) iblock[i] = ciphertext.charCodeAt(i+2);
|
|
||||||
for(n=block_size+2; n<ciphertext.length; n+=block_size)
|
|
||||||
{
|
|
||||||
ablock = blockcipherencryptfn(iblock, key);
|
|
||||||
|
|
||||||
for(i = 0; i<block_size && i+n < ciphertext.length; i++)
|
|
||||||
{
|
|
||||||
iblock[i] = ciphertext.charCodeAt(n+i);
|
|
||||||
text.push(String.fromCharCode(ablock[i]^iblock[i]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for(i=0; i<block_size; i++) iblock[i] = ciphertext.charCodeAt(i);
|
|
||||||
for(n=block_size; n<ciphertext.length; n+=block_size)
|
|
||||||
{
|
|
||||||
ablock = blockcipherencryptfn(iblock, key);
|
|
||||||
for(i = 0; i<block_size && i+n < ciphertext.length; i++)
|
|
||||||
{
|
|
||||||
iblock[i] = ciphertext.charCodeAt(n+i);
|
|
||||||
text.push(String.fromCharCode(ablock[i]^iblock[i]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return text.join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function normal_cfb_encrypt(blockcipherencryptfn, block_size, key, plaintext, iv) {
|
|
||||||
var blocki ="";
|
|
||||||
var blockc = "";
|
|
||||||
var pos = 0;
|
|
||||||
var cyphertext = [];
|
|
||||||
var tempBlock = [];
|
|
||||||
blockc = iv.substring(0,block_size);
|
|
||||||
while (plaintext.length > block_size*pos) {
|
|
||||||
var encblock = blockcipherencryptfn(blockc, key);
|
|
||||||
blocki = plaintext.substring((pos*block_size),(pos*block_size)+block_size);
|
|
||||||
for (var i=0; i < blocki.length; i++)
|
|
||||||
tempBlock.push(String.fromCharCode(blocki.charCodeAt(i) ^ encblock[i]));
|
|
||||||
blockc = tempBlock.join('');
|
|
||||||
tempBlock = [];
|
|
||||||
cyphertext.push(blockc);
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
return cyphertext.join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
function normal_cfb_decrypt(blockcipherencryptfn, block_size, key, ciphertext, iv) {
|
|
||||||
var blockp ="";
|
|
||||||
var pos = 0;
|
|
||||||
var plaintext = [];
|
|
||||||
var offset = 0;
|
|
||||||
if (iv == null)
|
|
||||||
for (var i = 0; i < block_size; i++) blockp += String.fromCharCode(0);
|
|
||||||
else
|
|
||||||
blockp = iv.substring(0,block_size);
|
|
||||||
while (ciphertext.length > (block_size*pos)) {
|
|
||||||
var decblock = blockcipherencryptfn(blockp, key);
|
|
||||||
blockp = ciphertext.substring((pos*(block_size))+offset,(pos*(block_size))+(block_size)+offset);
|
|
||||||
for (var i=0; i < blockp.length; i++) {
|
|
||||||
plaintext.push(String.fromCharCode(blockp.charCodeAt(i) ^ decblock[i]));
|
|
||||||
}
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return plaintext.join('');
|
|
||||||
}
|
|
125
src/crypto/pkcs1.js
Normal file
125
src/crypto/pkcs1.js
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ASN1 object identifiers for hashes (See RFC4880 5.2.2)
|
||||||
|
*/
|
||||||
|
hash_headers = new Array();
|
||||||
|
hash_headers[1] = [0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x04,0x10];
|
||||||
|
hash_headers[3] = [0x30,0x21,0x30,0x09,0x06,0x05,0x2B,0x24,0x03,0x02,0x01,0x05,0x00,0x04,0x14];
|
||||||
|
hash_headers[2] = [0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14];
|
||||||
|
hash_headers[8] = [0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20];
|
||||||
|
hash_headers[9] = [0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04,0x30];
|
||||||
|
hash_headers[10] = [0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,0x40];
|
||||||
|
hash_headers[11] = [0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x04,0x05,0x00,0x04,0x1C];
|
||||||
|
|
||||||
|
|
||||||
|
var crypto = require('./crypto.js'),
|
||||||
|
random = require('./random.js'),
|
||||||
|
util = require('../util'),
|
||||||
|
BigInteger = require('./public_key/jsbn.js'),
|
||||||
|
hash = require('./hash');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
eme: {
|
||||||
|
/**
|
||||||
|
* create a EME-PKCS1-v1_5 padding (See RFC4880 13.1.1)
|
||||||
|
* @param {String} message message to be padded
|
||||||
|
* @param {Integer} length Length to the resulting message
|
||||||
|
* @return {String} EME-PKCS1 padded message
|
||||||
|
*/
|
||||||
|
encode: function(message, length) {
|
||||||
|
if (message.length > length-11)
|
||||||
|
return -1;
|
||||||
|
var result = "";
|
||||||
|
result += String.fromCharCode(0);
|
||||||
|
result += String.fromCharCode(2);
|
||||||
|
for (var i = 0; i < length - message.length - 3; i++) {
|
||||||
|
result += String.fromCharCode(random.getPseudoRandom(1,255));
|
||||||
|
}
|
||||||
|
result += String.fromCharCode(0);
|
||||||
|
result += message;
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* decodes a EME-PKCS1-v1_5 padding (See RFC4880 13.1.2)
|
||||||
|
* @param {String} message EME-PKCS1 padded message
|
||||||
|
* @return {String} decoded message
|
||||||
|
*/
|
||||||
|
decode: function(message, len) {
|
||||||
|
if (message.length < len)
|
||||||
|
message = String.fromCharCode(0)+message;
|
||||||
|
if (message.length < 12 || message.charCodeAt(0) != 0 || message.charCodeAt(1) != 2)
|
||||||
|
return -1;
|
||||||
|
var i = 2;
|
||||||
|
while (message.charCodeAt(i) != 0 && message.length > i)
|
||||||
|
i++;
|
||||||
|
return message.substring(i+1, message.length);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
emsa: {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create a EMSA-PKCS1-v1_5 padding (See RFC4880 13.1.3)
|
||||||
|
* @param {Integer} algo Hash algorithm type used
|
||||||
|
* @param {String} data Data to be hashed
|
||||||
|
* @param {Integer} keylength Key size of the public mpi in bytes
|
||||||
|
* @returns {String} Hashcode with pkcs1padding as string
|
||||||
|
*/
|
||||||
|
encode: function(algo, data, keylength) {
|
||||||
|
var data2 = "";
|
||||||
|
data2 += String.fromCharCode(0x00);
|
||||||
|
data2 += String.fromCharCode(0x01);
|
||||||
|
for (var i = 0; i < (keylength - hash_headers[algo].length - 3 -
|
||||||
|
hash.getHashByteLength(algo)); i++)
|
||||||
|
|
||||||
|
data2 += String.fromCharCode(0xff);
|
||||||
|
|
||||||
|
data2 += String.fromCharCode(0x00);
|
||||||
|
|
||||||
|
for (var i = 0; i < hash_headers[algo].length; i++)
|
||||||
|
data2 += String.fromCharCode(hash_headers[algo][i]);
|
||||||
|
|
||||||
|
data2 += hash.digest(algo, data);
|
||||||
|
return new BigInteger(util.hexstrdump(data2),16);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* extract the hash out of an EMSA-PKCS1-v1.5 padding (See RFC4880 13.1.3)
|
||||||
|
* @param {String} data Hash in pkcs1 encoding
|
||||||
|
* @returns {String} The hash as string
|
||||||
|
*/
|
||||||
|
decode: function(algo, data) {
|
||||||
|
var i = 0;
|
||||||
|
if (data.charCodeAt(0) == 0) i++;
|
||||||
|
else if (data.charCodeAt(0) != 1) return -1;
|
||||||
|
else i++;
|
||||||
|
|
||||||
|
while (data.charCodeAt(i) == 0xFF) i++;
|
||||||
|
if (data.charCodeAt(i++) != 0) return -1;
|
||||||
|
var j = 0;
|
||||||
|
for (j = 0; j < hash_headers[algo].length && j+i < data.length; j++) {
|
||||||
|
if (data.charCodeAt(j+i) != hash_headers[algo][j]) return -1;
|
||||||
|
}
|
||||||
|
i+= j;
|
||||||
|
if (data.substring(i).length < hash.getHashByteLength(algo)) return -1;
|
||||||
|
return data.substring(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -149,3 +149,5 @@ function DSA() {
|
||||||
this.verify = verify;
|
this.verify = verify;
|
||||||
// this.generate = generateKey;
|
// this.generate = generateKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports = DSA;
|
|
@ -17,6 +17,9 @@
|
||||||
//
|
//
|
||||||
// ElGamal implementation
|
// ElGamal implementation
|
||||||
|
|
||||||
|
var BigInteger = require('./jsbn.js'),
|
||||||
|
util = require('../../util');
|
||||||
|
|
||||||
function Elgamal() {
|
function Elgamal() {
|
||||||
|
|
||||||
function encrypt(m,g,p,y) {
|
function encrypt(m,g,p,y) {
|
||||||
|
@ -46,3 +49,5 @@ function Elgamal() {
|
||||||
this.encrypt = encrypt;
|
this.encrypt = encrypt;
|
||||||
this.decrypt = decrypt;
|
this.decrypt = decrypt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports = Elgamal;
|
7
src/crypto/public_key/index.js
Normal file
7
src/crypto/public_key/index.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
rsa: require('./rsa.js'),
|
||||||
|
elgamal: require('./elgamal.js'),
|
||||||
|
dsa: require('./dsa.js')
|
||||||
|
}
|
||||||
|
|
|
@ -30,6 +30,620 @@
|
||||||
* All redistributions must retain an intact copy of this copyright notice
|
* All redistributions must retain an intact copy of this copyright notice
|
||||||
* and disclaimer.
|
* and disclaimer.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
var util = require('../../util');
|
||||||
|
|
||||||
|
// Basic JavaScript BN library - subset useful for RSA encryption.
|
||||||
|
|
||||||
|
// Bits per digit
|
||||||
|
var dbits;
|
||||||
|
|
||||||
|
// JavaScript engine analysis
|
||||||
|
var canary = 0xdeadbeefcafe;
|
||||||
|
var j_lm = ((canary&0xffffff)==0xefcafe);
|
||||||
|
|
||||||
|
// (public) Constructor
|
||||||
|
function BigInteger(a,b,c) {
|
||||||
|
if(a != null)
|
||||||
|
if("number" == typeof a) this.fromNumber(a,b,c);
|
||||||
|
else if(b == null && "string" != typeof a) this.fromString(a,256);
|
||||||
|
else this.fromString(a,b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return new, unset BigInteger
|
||||||
|
function nbi() { return new BigInteger(null); }
|
||||||
|
|
||||||
|
// am: Compute w_j += (x*this_i), propagate carries,
|
||||||
|
// c is initial carry, returns final carry.
|
||||||
|
// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
|
||||||
|
// We need to select the fastest one that works in this environment.
|
||||||
|
|
||||||
|
// am1: use a single mult and divide to get the high bits,
|
||||||
|
// max digit bits should be 26 because
|
||||||
|
// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
|
||||||
|
function am1(i,x,w,j,c,n) {
|
||||||
|
while(--n >= 0) {
|
||||||
|
var v = x*this[i++]+w[j]+c;
|
||||||
|
c = Math.floor(v/0x4000000);
|
||||||
|
w[j++] = v&0x3ffffff;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
// am2 avoids a big mult-and-extract completely.
|
||||||
|
// Max digit bits should be <= 30 because we do bitwise ops
|
||||||
|
// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
|
||||||
|
function am2(i,x,w,j,c,n) {
|
||||||
|
var xl = x&0x7fff, xh = x>>15;
|
||||||
|
while(--n >= 0) {
|
||||||
|
var l = this[i]&0x7fff;
|
||||||
|
var h = this[i++]>>15;
|
||||||
|
var m = xh*l+h*xl;
|
||||||
|
l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff);
|
||||||
|
c = (l>>>30)+(m>>>15)+xh*h+(c>>>30);
|
||||||
|
w[j++] = l&0x3fffffff;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
// Alternately, set max digit bits to 28 since some
|
||||||
|
// browsers slow down when dealing with 32-bit numbers.
|
||||||
|
function am3(i,x,w,j,c,n) {
|
||||||
|
var xl = x&0x3fff, xh = x>>14;
|
||||||
|
while(--n >= 0) {
|
||||||
|
var l = this[i]&0x3fff;
|
||||||
|
var h = this[i++]>>14;
|
||||||
|
var m = xh*l+h*xl;
|
||||||
|
l = xl*l+((m&0x3fff)<<14)+w[j]+c;
|
||||||
|
c = (l>>28)+(m>>14)+xh*h;
|
||||||
|
w[j++] = l&0xfffffff;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
|
||||||
|
BigInteger.prototype.am = am2;
|
||||||
|
dbits = 30;
|
||||||
|
}
|
||||||
|
else if(j_lm && (navigator.appName != "Netscape")) {
|
||||||
|
BigInteger.prototype.am = am1;
|
||||||
|
dbits = 26;
|
||||||
|
}
|
||||||
|
else { // Mozilla/Netscape seems to prefer am3
|
||||||
|
BigInteger.prototype.am = am3;
|
||||||
|
dbits = 28;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger.prototype.DB = dbits;
|
||||||
|
BigInteger.prototype.DM = ((1<<dbits)-1);
|
||||||
|
BigInteger.prototype.DV = (1<<dbits);
|
||||||
|
|
||||||
|
var BI_FP = 52;
|
||||||
|
BigInteger.prototype.FV = Math.pow(2,BI_FP);
|
||||||
|
BigInteger.prototype.F1 = BI_FP-dbits;
|
||||||
|
BigInteger.prototype.F2 = 2*dbits-BI_FP;
|
||||||
|
|
||||||
|
// Digit conversions
|
||||||
|
var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||||
|
var BI_RC = new Array();
|
||||||
|
var rr,vv;
|
||||||
|
rr = "0".charCodeAt(0);
|
||||||
|
for(vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
|
||||||
|
rr = "a".charCodeAt(0);
|
||||||
|
for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
|
||||||
|
rr = "A".charCodeAt(0);
|
||||||
|
for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
|
||||||
|
|
||||||
|
function int2char(n) { return BI_RM.charAt(n); }
|
||||||
|
function intAt(s,i) {
|
||||||
|
var c = BI_RC[s.charCodeAt(i)];
|
||||||
|
return (c==null)?-1:c;
|
||||||
|
}
|
||||||
|
|
||||||
|
// (protected) copy this to r
|
||||||
|
function bnpCopyTo(r) {
|
||||||
|
for(var i = this.t-1; i >= 0; --i) r[i] = this[i];
|
||||||
|
r.t = this.t;
|
||||||
|
r.s = this.s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// (protected) set from integer value x, -DV <= x < DV
|
||||||
|
function bnpFromInt(x) {
|
||||||
|
this.t = 1;
|
||||||
|
this.s = (x<0)?-1:0;
|
||||||
|
if(x > 0) this[0] = x;
|
||||||
|
else if(x < -1) this[0] = x+DV;
|
||||||
|
else this.t = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return bigint initialized to value
|
||||||
|
function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
|
||||||
|
|
||||||
|
// (protected) set from string and radix
|
||||||
|
function bnpFromString(s,b) {
|
||||||
|
var k;
|
||||||
|
if(b == 16) k = 4;
|
||||||
|
else if(b == 8) k = 3;
|
||||||
|
else if(b == 256) k = 8; // byte array
|
||||||
|
else if(b == 2) k = 1;
|
||||||
|
else if(b == 32) k = 5;
|
||||||
|
else if(b == 4) k = 2;
|
||||||
|
else { this.fromRadix(s,b); return; }
|
||||||
|
this.t = 0;
|
||||||
|
this.s = 0;
|
||||||
|
var i = s.length, mi = false, sh = 0;
|
||||||
|
while(--i >= 0) {
|
||||||
|
var x = (k==8)?s[i]&0xff:intAt(s,i);
|
||||||
|
if(x < 0) {
|
||||||
|
if(s.charAt(i) == "-") mi = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
mi = false;
|
||||||
|
if(sh == 0)
|
||||||
|
this[this.t++] = x;
|
||||||
|
else if(sh+k > this.DB) {
|
||||||
|
this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<<sh;
|
||||||
|
this[this.t++] = (x>>(this.DB-sh));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
this[this.t-1] |= x<<sh;
|
||||||
|
sh += k;
|
||||||
|
if(sh >= this.DB) sh -= this.DB;
|
||||||
|
}
|
||||||
|
if(k == 8 && (s[0]&0x80) != 0) {
|
||||||
|
this.s = -1;
|
||||||
|
if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh;
|
||||||
|
}
|
||||||
|
this.clamp();
|
||||||
|
if(mi) BigInteger.ZERO.subTo(this,this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (protected) clamp off excess high words
|
||||||
|
function bnpClamp() {
|
||||||
|
var c = this.s&this.DM;
|
||||||
|
while(this.t > 0 && this[this.t-1] == c) --this.t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// (public) return string representation in given radix
|
||||||
|
function bnToString(b) {
|
||||||
|
if(this.s < 0) return "-"+this.negate().toString(b);
|
||||||
|
var k;
|
||||||
|
if(b == 16) k = 4;
|
||||||
|
else if(b == 8) k = 3;
|
||||||
|
else if(b == 2) k = 1;
|
||||||
|
else if(b == 32) k = 5;
|
||||||
|
else if(b == 4) k = 2;
|
||||||
|
else return this.toRadix(b);
|
||||||
|
var km = (1<<k)-1, d, m = false, r = "", i = this.t;
|
||||||
|
var p = this.DB-(i*this.DB)%k;
|
||||||
|
if(i-- > 0) {
|
||||||
|
if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); }
|
||||||
|
while(i >= 0) {
|
||||||
|
if(p < k) {
|
||||||
|
d = (this[i]&((1<<p)-1))<<(k-p);
|
||||||
|
d |= this[--i]>>(p+=this.DB-k);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
d = (this[i]>>(p-=k))&km;
|
||||||
|
if(p <= 0) { p += this.DB; --i; }
|
||||||
|
}
|
||||||
|
if(d > 0) m = true;
|
||||||
|
if(m) r += int2char(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m?r:"0";
|
||||||
|
}
|
||||||
|
|
||||||
|
// (public) -this
|
||||||
|
function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }
|
||||||
|
|
||||||
|
// (public) |this|
|
||||||
|
function bnAbs() { return (this.s<0)?this.negate():this; }
|
||||||
|
|
||||||
|
// (public) return + if this > a, - if this < a, 0 if equal
|
||||||
|
function bnCompareTo(a) {
|
||||||
|
var r = this.s-a.s;
|
||||||
|
if(r != 0) return r;
|
||||||
|
var i = this.t;
|
||||||
|
r = i-a.t;
|
||||||
|
if(r != 0) return r;
|
||||||
|
while(--i >= 0) if((r=this[i]-a[i]) != 0) return r;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns bit length of the integer x
|
||||||
|
function nbits(x) {
|
||||||
|
var r = 1, t;
|
||||||
|
if((t=x>>>16) != 0) { x = t; r += 16; }
|
||||||
|
if((t=x>>8) != 0) { x = t; r += 8; }
|
||||||
|
if((t=x>>4) != 0) { x = t; r += 4; }
|
||||||
|
if((t=x>>2) != 0) { x = t; r += 2; }
|
||||||
|
if((t=x>>1) != 0) { x = t; r += 1; }
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// (public) return the number of bits in "this"
|
||||||
|
function bnBitLength() {
|
||||||
|
if(this.t <= 0) return 0;
|
||||||
|
return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM));
|
||||||
|
}
|
||||||
|
|
||||||
|
// (protected) r = this << n*DB
|
||||||
|
function bnpDLShiftTo(n,r) {
|
||||||
|
var i;
|
||||||
|
for(i = this.t-1; i >= 0; --i) r[i+n] = this[i];
|
||||||
|
for(i = n-1; i >= 0; --i) r[i] = 0;
|
||||||
|
r.t = this.t+n;
|
||||||
|
r.s = this.s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// (protected) r = this >> n*DB
|
||||||
|
function bnpDRShiftTo(n,r) {
|
||||||
|
for(var i = n; i < this.t; ++i) r[i-n] = this[i];
|
||||||
|
r.t = Math.max(this.t-n,0);
|
||||||
|
r.s = this.s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// (protected) r = this << n
|
||||||
|
function bnpLShiftTo(n,r) {
|
||||||
|
var bs = n%this.DB;
|
||||||
|
var cbs = this.DB-bs;
|
||||||
|
var bm = (1<<cbs)-1;
|
||||||
|
var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i;
|
||||||
|
for(i = this.t-1; i >= 0; --i) {
|
||||||
|
r[i+ds+1] = (this[i]>>cbs)|c;
|
||||||
|
c = (this[i]&bm)<<bs;
|
||||||
|
}
|
||||||
|
for(i = ds-1; i >= 0; --i) r[i] = 0;
|
||||||
|
r[ds] = c;
|
||||||
|
r.t = this.t+ds+1;
|
||||||
|
r.s = this.s;
|
||||||
|
r.clamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
// (protected) r = this >> n
|
||||||
|
function bnpRShiftTo(n,r) {
|
||||||
|
r.s = this.s;
|
||||||
|
var ds = Math.floor(n/this.DB);
|
||||||
|
if(ds >= this.t) { r.t = 0; return; }
|
||||||
|
var bs = n%this.DB;
|
||||||
|
var cbs = this.DB-bs;
|
||||||
|
var bm = (1<<bs)-1;
|
||||||
|
r[0] = this[ds]>>bs;
|
||||||
|
for(var i = ds+1; i < this.t; ++i) {
|
||||||
|
r[i-ds-1] |= (this[i]&bm)<<cbs;
|
||||||
|
r[i-ds] = this[i]>>bs;
|
||||||
|
}
|
||||||
|
if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs;
|
||||||
|
r.t = this.t-ds;
|
||||||
|
r.clamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
// (protected) r = this - a
|
||||||
|
function bnpSubTo(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 < -1) r[i++] = this.DV+c;
|
||||||
|
else if(c > 0) r[i++] = c;
|
||||||
|
r.t = i;
|
||||||
|
r.clamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
// (protected) r = this * a, r != this,a (HAC 14.12)
|
||||||
|
// "this" should be the larger one if appropriate.
|
||||||
|
function bnpMultiplyTo(a,r) {
|
||||||
|
var x = this.abs(), y = a.abs();
|
||||||
|
var i = x.t;
|
||||||
|
r.t = i+y.t;
|
||||||
|
while(--i >= 0) r[i] = 0;
|
||||||
|
for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t);
|
||||||
|
r.s = 0;
|
||||||
|
r.clamp();
|
||||||
|
if(this.s != a.s) BigInteger.ZERO.subTo(r,r);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (protected) r = this^2, r != this (HAC 14.16)
|
||||||
|
function bnpSquareTo(r) {
|
||||||
|
var x = this.abs();
|
||||||
|
var i = r.t = 2*x.t;
|
||||||
|
while(--i >= 0) r[i] = 0;
|
||||||
|
for(i = 0; i < x.t-1; ++i) {
|
||||||
|
var c = x.am(i,x[i],r,2*i,0,1);
|
||||||
|
if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) {
|
||||||
|
r[i+x.t] -= x.DV;
|
||||||
|
r[i+x.t+1] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1);
|
||||||
|
r.s = 0;
|
||||||
|
r.clamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
|
||||||
|
// r != q, this != m. q or r may be null.
|
||||||
|
function bnpDivRemTo(m,q,r) {
|
||||||
|
var pm = m.abs();
|
||||||
|
if(pm.t <= 0) return;
|
||||||
|
var pt = this.abs();
|
||||||
|
if(pt.t < pm.t) {
|
||||||
|
if(q != null) q.fromInt(0);
|
||||||
|
if(r != null) this.copyTo(r);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(r == null) r = nbi();
|
||||||
|
var y = nbi(), ts = this.s, ms = m.s;
|
||||||
|
var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus
|
||||||
|
if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); }
|
||||||
|
else { pm.copyTo(y); pt.copyTo(r); }
|
||||||
|
var ys = y.t;
|
||||||
|
var y0 = y[ys-1];
|
||||||
|
if(y0 == 0) return;
|
||||||
|
var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0);
|
||||||
|
var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
|
||||||
|
var i = r.t, j = i-ys, t = (q==null)?nbi():q;
|
||||||
|
y.dlShiftTo(j,t);
|
||||||
|
if(r.compareTo(t) >= 0) {
|
||||||
|
r[r.t++] = 1;
|
||||||
|
r.subTo(t,r);
|
||||||
|
}
|
||||||
|
BigInteger.ONE.dlShiftTo(ys,t);
|
||||||
|
t.subTo(y,y); // "negative" y so we can replace sub with am later
|
||||||
|
while(y.t < ys) y[y.t++] = 0;
|
||||||
|
while(--j >= 0) {
|
||||||
|
// Estimate quotient digit
|
||||||
|
var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);
|
||||||
|
if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out
|
||||||
|
y.dlShiftTo(j,t);
|
||||||
|
r.subTo(t,r);
|
||||||
|
while(r[i] < --qd) r.subTo(t,r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(q != null) {
|
||||||
|
r.drShiftTo(ys,q);
|
||||||
|
if(ts != ms) BigInteger.ZERO.subTo(q,q);
|
||||||
|
}
|
||||||
|
r.t = ys;
|
||||||
|
r.clamp();
|
||||||
|
if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder
|
||||||
|
if(ts < 0) BigInteger.ZERO.subTo(r,r);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (public) this mod a
|
||||||
|
function bnMod(a) {
|
||||||
|
var r = nbi();
|
||||||
|
this.abs().divRemTo(a,null,r);
|
||||||
|
if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modular reduction using "classic" algorithm
|
||||||
|
function Classic(m) { this.m = m; }
|
||||||
|
function cConvert(x) {
|
||||||
|
if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
|
||||||
|
else return x;
|
||||||
|
}
|
||||||
|
function cRevert(x) { return x; }
|
||||||
|
function cReduce(x) { x.divRemTo(this.m,null,x); }
|
||||||
|
function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
|
||||||
|
function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
|
||||||
|
|
||||||
|
Classic.prototype.convert = cConvert;
|
||||||
|
Classic.prototype.revert = cRevert;
|
||||||
|
Classic.prototype.reduce = cReduce;
|
||||||
|
Classic.prototype.mulTo = cMulTo;
|
||||||
|
Classic.prototype.sqrTo = cSqrTo;
|
||||||
|
|
||||||
|
// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
|
||||||
|
// justification:
|
||||||
|
// xy == 1 (mod m)
|
||||||
|
// xy = 1+km
|
||||||
|
// xy(2-xy) = (1+km)(1-km)
|
||||||
|
// x[y(2-xy)] = 1-k^2m^2
|
||||||
|
// x[y(2-xy)] == 1 (mod m^2)
|
||||||
|
// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
|
||||||
|
// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
|
||||||
|
// JS multiply "overflows" differently from C/C++, so care is needed here.
|
||||||
|
function bnpInvDigit() {
|
||||||
|
if(this.t < 1) return 0;
|
||||||
|
var x = this[0];
|
||||||
|
if((x&1) == 0) return 0;
|
||||||
|
var y = x&3; // y == 1/x mod 2^2
|
||||||
|
y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4
|
||||||
|
y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8
|
||||||
|
y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16
|
||||||
|
// last step - calculate inverse mod DV directly;
|
||||||
|
// assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
|
||||||
|
y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits
|
||||||
|
// we really want the negative inverse, and -DV < y < DV
|
||||||
|
return (y>0)?this.DV-y:-y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Montgomery reduction
|
||||||
|
function Montgomery(m) {
|
||||||
|
this.m = m;
|
||||||
|
this.mp = m.invDigit();
|
||||||
|
this.mpl = this.mp&0x7fff;
|
||||||
|
this.mph = this.mp>>15;
|
||||||
|
this.um = (1<<(m.DB-15))-1;
|
||||||
|
this.mt2 = 2*m.t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// xR mod m
|
||||||
|
function montConvert(x) {
|
||||||
|
var r = nbi();
|
||||||
|
x.abs().dlShiftTo(this.m.t,r);
|
||||||
|
r.divRemTo(this.m,null,r);
|
||||||
|
if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// x/R mod m
|
||||||
|
function montRevert(x) {
|
||||||
|
var r = nbi();
|
||||||
|
x.copyTo(r);
|
||||||
|
this.reduce(r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// x = x/R mod m (HAC 14.32)
|
||||||
|
function montReduce(x) {
|
||||||
|
while(x.t <= this.mt2) // pad x so am has enough room later
|
||||||
|
x[x.t++] = 0;
|
||||||
|
for(var i = 0; i < this.m.t; ++i) {
|
||||||
|
// faster way of calculating u0 = x[i]*mp mod DV
|
||||||
|
var j = x[i]&0x7fff;
|
||||||
|
var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM;
|
||||||
|
// use am to combine the multiply-shift-add into one call
|
||||||
|
j = i+this.m.t;
|
||||||
|
x[j] += this.m.am(0,u0,x,i,0,this.m.t);
|
||||||
|
// propagate carry
|
||||||
|
while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; }
|
||||||
|
}
|
||||||
|
x.clamp();
|
||||||
|
x.drShiftTo(this.m.t,x);
|
||||||
|
if(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// r = "x^2/R mod m"; x != r
|
||||||
|
function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
|
||||||
|
|
||||||
|
// r = "xy/R mod m"; x,y != r
|
||||||
|
function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
|
||||||
|
|
||||||
|
Montgomery.prototype.convert = montConvert;
|
||||||
|
Montgomery.prototype.revert = montRevert;
|
||||||
|
Montgomery.prototype.reduce = montReduce;
|
||||||
|
Montgomery.prototype.mulTo = montMulTo;
|
||||||
|
Montgomery.prototype.sqrTo = montSqrTo;
|
||||||
|
|
||||||
|
// (protected) true iff this is even
|
||||||
|
function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; }
|
||||||
|
|
||||||
|
// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
|
||||||
|
function bnpExp(e,z) {
|
||||||
|
if(e > 0xffffffff || e < 1) return BigInteger.ONE;
|
||||||
|
var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1;
|
||||||
|
g.copyTo(r);
|
||||||
|
while(--i >= 0) {
|
||||||
|
z.sqrTo(r,r2);
|
||||||
|
if((e&(1<<i)) > 0) z.mulTo(r2,g,r);
|
||||||
|
else { var t = r; r = r2; r2 = t; }
|
||||||
|
}
|
||||||
|
return z.revert(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (public) this^e % m, 0 <= e < 2^32
|
||||||
|
function bnModPowInt(e,m) {
|
||||||
|
var z;
|
||||||
|
if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
|
||||||
|
return this.exp(e,z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// protected
|
||||||
|
BigInteger.prototype.copyTo = bnpCopyTo;
|
||||||
|
BigInteger.prototype.fromInt = bnpFromInt;
|
||||||
|
BigInteger.prototype.fromString = bnpFromString;
|
||||||
|
BigInteger.prototype.clamp = bnpClamp;
|
||||||
|
BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
|
||||||
|
BigInteger.prototype.drShiftTo = bnpDRShiftTo;
|
||||||
|
BigInteger.prototype.lShiftTo = bnpLShiftTo;
|
||||||
|
BigInteger.prototype.rShiftTo = bnpRShiftTo;
|
||||||
|
BigInteger.prototype.subTo = bnpSubTo;
|
||||||
|
BigInteger.prototype.multiplyTo = bnpMultiplyTo;
|
||||||
|
BigInteger.prototype.squareTo = bnpSquareTo;
|
||||||
|
BigInteger.prototype.divRemTo = bnpDivRemTo;
|
||||||
|
BigInteger.prototype.invDigit = bnpInvDigit;
|
||||||
|
BigInteger.prototype.isEven = bnpIsEven;
|
||||||
|
BigInteger.prototype.exp = bnpExp;
|
||||||
|
|
||||||
|
// public
|
||||||
|
BigInteger.prototype.toString = bnToString;
|
||||||
|
BigInteger.prototype.negate = bnNegate;
|
||||||
|
BigInteger.prototype.abs = bnAbs;
|
||||||
|
BigInteger.prototype.compareTo = bnCompareTo;
|
||||||
|
BigInteger.prototype.bitLength = bnBitLength;
|
||||||
|
BigInteger.prototype.mod = bnMod;
|
||||||
|
BigInteger.prototype.modPowInt = bnModPowInt;
|
||||||
|
|
||||||
|
// "constants"
|
||||||
|
BigInteger.ZERO = nbv(0);
|
||||||
|
BigInteger.ONE = nbv(1);
|
||||||
|
|
||||||
|
module.exports = BigInteger;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2003-2005 Tom Wu (tjw@cs.Stanford.EDU)
|
||||||
|
* All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Modified by Recurity Labs GmbH
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
|
||||||
|
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
|
||||||
|
* INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
|
||||||
|
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
|
||||||
|
* THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
|
||||||
|
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
* In addition, the following condition applies:
|
||||||
|
*
|
||||||
|
* All redistributions must retain an intact copy of this copyright notice
|
||||||
|
* and disclaimer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
// Extended JavaScript BN functions, required for RSA private ops.
|
// Extended JavaScript BN functions, required for RSA private ops.
|
||||||
|
|
||||||
// Version 1.1: new BigInteger("0", 10) returns "proper" zero
|
// Version 1.1: new BigInteger("0", 10) returns "proper" zero
|
||||||
|
@ -659,6 +1273,8 @@ function bnpMillerRabin(t) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var BigInteger = require('./jsbn.js');
|
||||||
|
|
||||||
// protected
|
// protected
|
||||||
BigInteger.prototype.chunkSize = bnpChunkSize;
|
BigInteger.prototype.chunkSize = bnpChunkSize;
|
||||||
BigInteger.prototype.toRadix = bnpToRadix;
|
BigInteger.prototype.toRadix = bnpToRadix;
|
||||||
|
@ -712,3 +1328,5 @@ BigInteger.prototype.toMPI = bnToMPI;
|
||||||
|
|
||||||
// JSBN-specific extension
|
// JSBN-specific extension
|
||||||
BigInteger.prototype.square = bnSquare;
|
BigInteger.prototype.square = bnSquare;
|
||||||
|
|
||||||
|
|
5
src/crypto/public_key/package.json
Normal file
5
src/crypto/public_key/package.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"name": "openpgp-crypto-public-key",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"main": "./index.js"
|
||||||
|
}
|
|
@ -17,10 +17,13 @@
|
||||||
//
|
//
|
||||||
// RSA implementation
|
// RSA implementation
|
||||||
|
|
||||||
|
var BigInteger = require('./jsbn.js'),
|
||||||
|
random = require('../random.js');
|
||||||
|
|
||||||
function SecureRandom(){
|
function SecureRandom(){
|
||||||
function nextBytes(byteArray){
|
function nextBytes(byteArray){
|
||||||
for(var n = 0; n < byteArray.length;n++){
|
for(var n = 0; n < byteArray.length;n++){
|
||||||
byteArray[n] = openpgp_crypto_getSecureRandomOctet();
|
byteArray[n] = random.getSecureRandomOctet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.nextBytes = nextBytes;
|
this.nextBytes = nextBytes;
|
||||||
|
@ -133,3 +136,5 @@ function RSA() {
|
||||||
this.generate = generate;
|
this.generate = generate;
|
||||||
this.keyObject = keyObject;
|
this.keyObject = keyObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports = RSA;
|
64
src/crypto/random.js
Normal file
64
src/crypto/random.js
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* Retrieve secure random byte string of the specified length
|
||||||
|
* @param {Integer} length Length in bytes to generate
|
||||||
|
* @return {String} Random byte string
|
||||||
|
*/
|
||||||
|
getRandomBytes: function(length) {
|
||||||
|
var result = '';
|
||||||
|
for (var i = 0; i < length; i++) {
|
||||||
|
result += String.fromCharCode(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
|
||||||
|
*/
|
||||||
|
getPseudoRandom: function(from, to) {
|
||||||
|
return Math.round(Math.random()*(to-from))+from;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a secure random number in the specified range
|
||||||
|
* @param {Integer} from Min of the random number
|
||||||
|
* @param {Integer} to Max of the random number (max 32bit)
|
||||||
|
* @return {Integer} A secure random number
|
||||||
|
*/
|
||||||
|
getSecureRandom: function(from, to) {
|
||||||
|
var buf = new Uint32Array(1);
|
||||||
|
window.crypto.getRandomValues(buf);
|
||||||
|
var bits = ((to-from)).toString(2).length;
|
||||||
|
while ((buf[0] & (Math.pow(2, bits) -1)) > (to-from))
|
||||||
|
window.crypto.getRandomValues(buf);
|
||||||
|
return from+(Math.abs(buf[0] & (Math.pow(2, bits) -1)));
|
||||||
|
},
|
||||||
|
|
||||||
|
getSecureRandomOctet: function() {
|
||||||
|
var buf = new Uint32Array(1);
|
||||||
|
window.crypto.getRandomValues(buf);
|
||||||
|
return buf[0] & 0xFF;
|
||||||
|
}
|
||||||
|
}
|
96
src/crypto/signature.js
Normal file
96
src/crypto/signature.js
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
|
||||||
|
var publicKey = require('./public_key'),
|
||||||
|
pkcs1 = require('./pkcs1.js'),
|
||||||
|
hashModule = require('./hash');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Integer} algo public Key algorithm
|
||||||
|
* @param {Integer} hash_algo Hash algorithm
|
||||||
|
* @param {openpgp_type_mpi[]} msg_MPIs Signature multiprecision integers
|
||||||
|
* @param {openpgp_type_mpi[]} publickey_MPIs Public key multiprecision integers
|
||||||
|
* @param {String} data Data on where the signature was computed on.
|
||||||
|
* @return {Boolean} true if signature (sig_data was equal to data over hash)
|
||||||
|
*/
|
||||||
|
verify: function(algo, hash_algo, msg_MPIs, publickey_MPIs, data) {
|
||||||
|
var calc_hash = hashModule.digest(hash_algo, data);
|
||||||
|
|
||||||
|
switch(algo) {
|
||||||
|
case 1: // RSA (Encrypt or Sign) [HAC]
|
||||||
|
case 2: // RSA Encrypt-Only [HAC]
|
||||||
|
case 3: // RSA Sign-Only [HAC]
|
||||||
|
var rsa = new publicKey.rsa();
|
||||||
|
var n = publickey_MPIs[0].toBigInteger();
|
||||||
|
var e = publickey_MPIs[1].toBigInteger();
|
||||||
|
var x = msg_MPIs[0].toBigInteger();
|
||||||
|
var dopublic = rsa.verify(x,e,n);
|
||||||
|
var hash = pkcs1.emsa.decode(hash_algo,dopublic.toMPI().substring(2));
|
||||||
|
if (hash == -1) {
|
||||||
|
throw new Error('PKCS1 padding in message or key incorrect. Aborting...');
|
||||||
|
}
|
||||||
|
return hash == calc_hash;
|
||||||
|
|
||||||
|
case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
|
||||||
|
throw new Error("signing with Elgamal is not defined in the OpenPGP standard.");
|
||||||
|
case 17: // DSA (Digital Signature Algorithm) [FIPS186] [HAC]
|
||||||
|
var dsa = new publicKey.dsa();
|
||||||
|
var s1 = msg_MPIs[0].toBigInteger();
|
||||||
|
var s2 = msg_MPIs[1].toBigInteger();
|
||||||
|
var p = publickey_MPIs[0].toBigInteger();
|
||||||
|
var q = publickey_MPIs[1].toBigInteger();
|
||||||
|
var g = publickey_MPIs[2].toBigInteger();
|
||||||
|
var y = publickey_MPIs[3].toBigInteger();
|
||||||
|
var m = data;
|
||||||
|
var dopublic = dsa.verify(hash_algo,s1,s2,m,p,q,g,y);
|
||||||
|
return dopublic.compareTo(s1) == 0;
|
||||||
|
default:
|
||||||
|
throw new Error('Invalid signature algorithm.');
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a signature on data using the specified algorithm
|
||||||
|
* @param {Integer} hash_algo hash Algorithm to use (See RFC4880 9.4)
|
||||||
|
* @param {Integer} algo Asymmetric cipher algorithm to use (See RFC4880 9.1)
|
||||||
|
* @param {openpgp_type_mpi[]} publicMPIs Public key multiprecision integers
|
||||||
|
* of the private key
|
||||||
|
* @param {openpgp_type_mpi[]} secretMPIs Private key multiprecision
|
||||||
|
* integers which is used to sign the data
|
||||||
|
* @param {String} data Data to be signed
|
||||||
|
* @return {openpgp_type_mpi[]}
|
||||||
|
*/
|
||||||
|
sign: function(hash_algo, algo, keyIntegers, data) {
|
||||||
|
|
||||||
|
switch(algo) {
|
||||||
|
case 1: // RSA (Encrypt or Sign) [HAC]
|
||||||
|
case 2: // RSA Encrypt-Only [HAC]
|
||||||
|
case 3: // RSA Sign-Only [HAC]
|
||||||
|
var rsa = new publicKey.rsa();
|
||||||
|
var d = keyIntegers[2].toBigInteger();
|
||||||
|
var n = keyIntegers[0].toBigInteger();
|
||||||
|
var m = pkcs1.emsa.encode(hash_algo,
|
||||||
|
data, keyIntegers[0].byteLength());
|
||||||
|
|
||||||
|
return rsa.sign(m, d, n).toMPI();
|
||||||
|
|
||||||
|
case 17: // DSA (Digital Signature Algorithm) [FIPS186] [HAC]
|
||||||
|
var dsa = new publicKey.dsa();
|
||||||
|
|
||||||
|
var p = keyIntegers[0].toBigInteger();
|
||||||
|
var q = keyIntegers[1].toBigInteger();
|
||||||
|
var g = keyIntegers[2].toBigInteger();
|
||||||
|
var y = keyIntegers[3].toBigInteger();
|
||||||
|
var x = keyIntegers[4].toBigInteger();
|
||||||
|
var m = data;
|
||||||
|
var result = dsa.sign(hash_algo,m, g, p, q, x);
|
||||||
|
|
||||||
|
return result[0].toString() + result[1].toString();
|
||||||
|
case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
|
||||||
|
throw new Error('Signing with Elgamal is not defined in the OpenPGP standard.');
|
||||||
|
default:
|
||||||
|
throw new Error('Invalid signature algorithm.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,11 @@
|
||||||
|
|
||||||
// The GPG4Browsers symmetric crypto interface
|
// The GPG4Browsers symmetric crypto interface
|
||||||
|
|
||||||
|
var cfb = require('./cfb.js'),
|
||||||
|
cipher = require('./cipher');
|
||||||
|
|
||||||
|
module.exports {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Symmetrically encrypts data using prefixedrandom, a key with length
|
* Symmetrically encrypts data using prefixedrandom, a key with length
|
||||||
* depending on the algorithm in openpgp_cfb mode with or without resync
|
* depending on the algorithm in openpgp_cfb mode with or without resync
|
||||||
|
@ -30,22 +35,22 @@
|
||||||
* @param {Boolean} openpgp_cfb
|
* @param {Boolean} openpgp_cfb
|
||||||
* @return {String} Encrypted data
|
* @return {String} Encrypted data
|
||||||
*/
|
*/
|
||||||
function openpgp_crypto_symmetricEncrypt(prefixrandom, algo, key, data, openpgp_cfb) {
|
encrypt: function (prefixrandom, algo, key, data, openpgp_cfb) {
|
||||||
switch(algo) {
|
switch(algo) {
|
||||||
case 0: // Plaintext or unencrypted data
|
case 0: // Plaintext or unencrypted data
|
||||||
return data; // blockcipherencryptfn, plaintext, block_size, key
|
return data; // blockcipherencryptfn, plaintext, block_size, key
|
||||||
case 2: // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
|
case 2: // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
|
||||||
return openpgp_cfb_encrypt(prefixrandom, desede, data,8,key, openpgp_cfb).substring(0, data.length + 10);
|
return cfb.encrypt(prefixrandom, cipher.des, data,8,key, openpgp_cfb).substring(0, data.length + 10);
|
||||||
case 3: // CAST5 (128 bit key, as per [RFC2144])
|
case 3: // CAST5 (128 bit key, as per [RFC2144])
|
||||||
return openpgp_cfb_encrypt(prefixrandom, cast5_encrypt, data,8,key, openpgp_cfb).substring(0, data.length + 10);
|
return cfb.encrypt(prefixrandom, cipher.cast5, data,8,key, openpgp_cfb).substring(0, data.length + 10);
|
||||||
case 4: // Blowfish (128 bit key, 16 rounds) [BLOWFISH]
|
case 4: // Blowfish (128 bit key, 16 rounds) [BLOWFISH]
|
||||||
return openpgp_cfb_encrypt(prefixrandom, BFencrypt, data,8,key, openpgp_cfb).substring(0, data.length + 10);
|
return cfb.encrypt(prefixrandom, cipher.blowfish, data,8,key, openpgp_cfb).substring(0, data.length + 10);
|
||||||
case 7: // AES with 128-bit key [AES]
|
case 7: // AES with 128-bit key [AES]
|
||||||
case 8: // AES with 192-bit key
|
case 8: // AES with 192-bit key
|
||||||
case 9: // AES with 256-bit key
|
case 9: // AES with 256-bit key
|
||||||
return openpgp_cfb_encrypt(prefixrandom, AESencrypt, data, 16, keyExpansion(key), openpgp_cfb).substring(0, data.length + 18);
|
return cfb.encrypt(prefixrandom, cipher.aes.encrypt, data, 16, cipher.aes.keyExpansion(key), openpgp_cfb).substring(0, data.length + 18);
|
||||||
case 10: // Twofish with 256-bit key [TWOFISH]
|
case 10: // Twofish with 256-bit key [TWOFISH]
|
||||||
return openpgp_cfb_encrypt(prefixrandom, TFencrypt, data,16, key, openpgp_cfb).substring(0, data.length + 18);
|
return cfb.encrypt(prefixrandom, cipher.twofish, data,16, key, openpgp_cfb).substring(0, data.length + 18);
|
||||||
case 1: // IDEA [IDEA]
|
case 1: // IDEA [IDEA]
|
||||||
util.print_error("IDEA Algorithm not implemented");
|
util.print_error("IDEA Algorithm not implemented");
|
||||||
return null;
|
return null;
|
||||||
|
@ -64,7 +69,7 @@ function openpgp_crypto_symmetricEncrypt(prefixrandom, algo, key, data, openpgp_
|
||||||
* otherwise use without the resync (for MDC encrypted data)
|
* otherwise use without the resync (for MDC encrypted data)
|
||||||
* @return {String} Plaintext data
|
* @return {String} Plaintext data
|
||||||
*/
|
*/
|
||||||
function openpgp_crypto_symmetricDecrypt(algo, key, data, openpgp_cfb) {
|
decrypt: function (algo, key, data, openpgp_cfb) {
|
||||||
util.print_debug_hexstr_dump("openpgp_crypto_symmetricDecrypt:\nalgo:"+algo+"\nencrypteddata:",data);
|
util.print_debug_hexstr_dump("openpgp_crypto_symmetricDecrypt:\nalgo:"+algo+"\nencrypteddata:",data);
|
||||||
var n = 0;
|
var n = 0;
|
||||||
if (!openpgp_cfb)
|
if (!openpgp_cfb)
|
||||||
|
@ -73,17 +78,17 @@ function openpgp_crypto_symmetricDecrypt(algo, key, data, openpgp_cfb) {
|
||||||
case 0: // Plaintext or unencrypted data
|
case 0: // Plaintext or unencrypted data
|
||||||
return data;
|
return data;
|
||||||
case 2: // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
|
case 2: // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
|
||||||
return openpgp_cfb_decrypt(desede, 8, key, data, openpgp_cfb).substring(n, (data.length+n)-10);
|
return cfb.decrypt(cipher.des, 8, key, data, openpgp_cfb).substring(n, (data.length+n)-10);
|
||||||
case 3: // CAST5 (128 bit key, as per [RFC2144])
|
case 3: // CAST5 (128 bit key, as per [RFC2144])
|
||||||
return openpgp_cfb_decrypt(cast5_encrypt, 8, key, data, openpgp_cfb).substring(n, (data.length+n)-10);
|
return cfb.decrypt(cipher.cast5, 8, key, data, openpgp_cfb).substring(n, (data.length+n)-10);
|
||||||
case 4: // Blowfish (128 bit key, 16 rounds) [BLOWFISH]
|
case 4: // Blowfish (128 bit key, 16 rounds) [BLOWFISH]
|
||||||
return openpgp_cfb_decrypt(BFencrypt, 8, key, data, openpgp_cfb).substring(n, (data.length+n)-10);
|
return cfb.decrypt(cipher.blowfish, 8, key, data, openpgp_cfb).substring(n, (data.length+n)-10);
|
||||||
case 7: // AES with 128-bit key [AES]
|
case 7: // AES with 128-bit key [AES]
|
||||||
case 8: // AES with 192-bit key
|
case 8: // AES with 192-bit key
|
||||||
case 9: // AES with 256-bit key
|
case 9: // AES with 256-bit key
|
||||||
return openpgp_cfb_decrypt(AESencrypt, 16, keyExpansion(key), data, openpgp_cfb).substring(n, (data.length+n)-18);
|
return cfb.decrypt(cipher.aes.encrypt, 16, cipher.aes.keyExpansion(key), data, openpgp_cfb).substring(n, (data.length+n)-18);
|
||||||
case 10: // Twofish with 256-bit key [TWOFISH]
|
case 10: // Twofish with 256-bit key [TWOFISH]
|
||||||
var result = openpgp_cfb_decrypt(TFencrypt, 16, key, data, openpgp_cfb).substring(n, (data.length+n)-18);
|
var result = cfb.decrypt(cipher.twofish, 16, key, data, openpgp_cfb).substring(n, (data.length+n)-18);
|
||||||
return result;
|
return result;
|
||||||
case 1: // IDEA [IDEA]
|
case 1: // IDEA [IDEA]
|
||||||
util.print_error(""+ (algo == 1 ? "IDEA Algorithm not implemented" : "Twofish Algorithm not implemented"));
|
util.print_error(""+ (algo == 1 ? "IDEA Algorithm not implemented" : "Twofish Algorithm not implemented"));
|
|
@ -15,72 +15,9 @@
|
||||||
// License along with this library; if not, write to the Free Software
|
// License along with this library; if not, write to the Free Software
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
/**
|
var base64 = require('./base64.js');
|
||||||
* 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) {
|
|
||||||
text = text.replace(/\r/g, '')
|
|
||||||
|
|
||||||
var type = openpgp_encoding_get_type(text);
|
|
||||||
|
|
||||||
if (type != 2) {
|
|
||||||
var splittedtext = text.split('-----');
|
|
||||||
|
|
||||||
var data = {
|
|
||||||
openpgp: openpgp_encoding_base64_decode(
|
|
||||||
splittedtext[2]
|
|
||||||
.split('\n\n')[1]
|
|
||||||
.split("\n=")[0]
|
|
||||||
.replace(/\n- /g,"\n")),
|
|
||||||
type: type
|
|
||||||
};
|
|
||||||
|
|
||||||
if (verifyCheckSum(data.openpgp,
|
|
||||||
splittedtext[2]
|
|
||||||
.split('\n\n')[1]
|
|
||||||
.split("\n=")[1]
|
|
||||||
.split('\n')[0]))
|
|
||||||
|
|
||||||
return data;
|
|
||||||
else {
|
|
||||||
util.print_error("Ascii armor integrity check on message failed: '"
|
|
||||||
+ splittedtext[2]
|
|
||||||
.split('\n\n')[1]
|
|
||||||
.split("\n=")[1]
|
|
||||||
.split('\n')[0]
|
|
||||||
+ "' should be '"
|
|
||||||
+ getCheckSum(data)) + "'";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var splittedtext = text.split('-----');
|
|
||||||
|
|
||||||
var result = {
|
|
||||||
text: splittedtext[2]
|
|
||||||
.replace(/\n- /g,"\n")
|
|
||||||
.split("\n\n")[1],
|
|
||||||
openpgp: openpgp_encoding_base64_decode(splittedtext[4]
|
|
||||||
.split("\n\n")[1]
|
|
||||||
.split("\n=")[0]),
|
|
||||||
type: type
|
|
||||||
};
|
|
||||||
|
|
||||||
if (verifyCheckSum(result.openpgp, splittedtext[4]
|
|
||||||
.split("\n\n")[1]
|
|
||||||
.split("\n=")[1]))
|
|
||||||
|
|
||||||
return result;
|
|
||||||
else {
|
|
||||||
util.print_error("Ascii armor integrity check on message failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds out which Ascii Armoring type is used. This is an internal function
|
* Finds out which Ascii Armoring type is used. This is an internal function
|
||||||
|
@ -93,7 +30,7 @@ function openpgp_encoding_dearmor(text) {
|
||||||
* 5 = PRIVATE KEY BLOCK
|
* 5 = PRIVATE KEY BLOCK
|
||||||
* null = unknown
|
* null = unknown
|
||||||
*/
|
*/
|
||||||
function openpgp_encoding_get_type(text) {
|
function get_type(text) {
|
||||||
var splittedtext = text.split('-----');
|
var splittedtext = text.split('-----');
|
||||||
// BEGIN PGP MESSAGE, PART X/Y
|
// BEGIN PGP MESSAGE, PART X/Y
|
||||||
// Used for multi-part messages, where the armor is split amongst Y
|
// Used for multi-part messages, where the armor is split amongst Y
|
||||||
|
@ -143,7 +80,7 @@ function openpgp_encoding_get_type(text) {
|
||||||
* @version 2011-12-16
|
* @version 2011-12-16
|
||||||
* @returns {String} The header information
|
* @returns {String} The header information
|
||||||
*/
|
*/
|
||||||
function openpgp_encoding_armor_addheader() {
|
function armor_addheader() {
|
||||||
var result = "";
|
var result = "";
|
||||||
if (openpgp.config.config.show_version) {
|
if (openpgp.config.config.show_version) {
|
||||||
result += "Version: "+openpgp.config.versionstring+'\r\n';
|
result += "Version: "+openpgp.config.versionstring+'\r\n';
|
||||||
|
@ -155,65 +92,7 @@ function openpgp_encoding_armor_addheader() {
|
||||||
return result;
|
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
|
* Calculates a checksum over the given data and returns it base64 encoded
|
||||||
|
@ -225,7 +104,7 @@ function getCheckSum(data) {
|
||||||
var str = "" + String.fromCharCode(c >> 16)+
|
var str = "" + String.fromCharCode(c >> 16)+
|
||||||
String.fromCharCode((c >> 8) & 0xFF)+
|
String.fromCharCode((c >> 8) & 0xFF)+
|
||||||
String.fromCharCode(c & 0xFF);
|
String.fromCharCode(c & 0xFF);
|
||||||
return openpgp_encoding_base64_encode(str);
|
return base64_encode(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -281,3 +160,135 @@ function createcrc24(input) {
|
||||||
return crc & 0xffffff;
|
return crc & 0xffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DeArmor an OpenPGP armored message; verify the checksum and return
|
||||||
|
* the encoded bytes
|
||||||
|
* @param {String} text OpenPGP armored message
|
||||||
|
* @returns {(Boolean|Object)} Either false in case of an error
|
||||||
|
* or an object with attribute "text" containing the message text
|
||||||
|
* and an attribute "openpgp" containing the bytes.
|
||||||
|
*/
|
||||||
|
function dearmor(text) {
|
||||||
|
text = text.replace(/\r/g, '')
|
||||||
|
|
||||||
|
var type = get_type(text);
|
||||||
|
|
||||||
|
if (type != 2) {
|
||||||
|
var splittedtext = text.split('-----');
|
||||||
|
|
||||||
|
var data = {
|
||||||
|
openpgp: base64_decode(
|
||||||
|
splittedtext[2]
|
||||||
|
.split('\n\n')[1]
|
||||||
|
.split("\n=")[0]
|
||||||
|
.replace(/\n- /g,"\n")),
|
||||||
|
type: type
|
||||||
|
};
|
||||||
|
|
||||||
|
if (verifyCheckSum(data.openpgp,
|
||||||
|
splittedtext[2]
|
||||||
|
.split('\n\n')[1]
|
||||||
|
.split("\n=")[1]
|
||||||
|
.split('\n')[0]))
|
||||||
|
|
||||||
|
return data;
|
||||||
|
else {
|
||||||
|
util.print_error("Ascii armor integrity check on message failed: '"
|
||||||
|
+ splittedtext[2]
|
||||||
|
.split('\n\n')[1]
|
||||||
|
.split("\n=")[1]
|
||||||
|
.split('\n')[0]
|
||||||
|
+ "' should be '"
|
||||||
|
+ getCheckSum(data)) + "'";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var splittedtext = text.split('-----');
|
||||||
|
|
||||||
|
var result = {
|
||||||
|
text: splittedtext[2]
|
||||||
|
.replace(/\n- /g,"\n")
|
||||||
|
.split("\n\n")[1],
|
||||||
|
openpgp: base64_decode(splittedtext[4]
|
||||||
|
.split("\n\n")[1]
|
||||||
|
.split("\n=")[0]),
|
||||||
|
type: type
|
||||||
|
};
|
||||||
|
|
||||||
|
if (verifyCheckSum(result.openpgp, splittedtext[4]
|
||||||
|
.split("\n\n")[1]
|
||||||
|
.split("\n=")[1]))
|
||||||
|
|
||||||
|
return result;
|
||||||
|
else {
|
||||||
|
util.print_error("Ascii armor integrity check on message failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Armor an OpenPGP binary packet block
|
||||||
|
* @param {Integer} messagetype type of the message
|
||||||
|
* @param data
|
||||||
|
* @param {Integer} partindex
|
||||||
|
* @param {Integer} parttotal
|
||||||
|
* @returns {String} Armored text
|
||||||
|
*/
|
||||||
|
function armor(messagetype, data, partindex, parttotal) {
|
||||||
|
var result = "";
|
||||||
|
switch(messagetype) {
|
||||||
|
case 0:
|
||||||
|
result += "-----BEGIN PGP MESSAGE, PART "+partindex+"/"+parttotal+"-----\r\n";
|
||||||
|
result += armor_addheader();
|
||||||
|
result += base64.encode(data);
|
||||||
|
result += "\r\n="+getCheckSum(data)+"\r\n";
|
||||||
|
result += "-----END PGP MESSAGE, PART "+partindex+"/"+parttotal+"-----\r\n";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
result += "-----BEGIN PGP MESSAGE, PART "+partindex+"-----\r\n";
|
||||||
|
result += armor_addheader();
|
||||||
|
result += base64.encode(data);
|
||||||
|
result += "\r\n="+getCheckSum(data)+"\r\n";
|
||||||
|
result += "-----END PGP MESSAGE, PART "+partindex+"-----\r\n";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
result += "\r\n-----BEGIN PGP SIGNED MESSAGE-----\r\nHash: "+data.hash+"\r\n\r\n";
|
||||||
|
result += data.text.replace(/\n-/g,"\n- -");
|
||||||
|
result += "\r\n-----BEGIN PGP SIGNATURE-----\r\n";
|
||||||
|
result += armor_addheader();
|
||||||
|
result += base64.encode(data.openpgp);
|
||||||
|
result += "\r\n="+getCheckSum(data.openpgp)+"\r\n";
|
||||||
|
result += "-----END PGP SIGNATURE-----\r\n";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
result += "-----BEGIN PGP MESSAGE-----\r\n";
|
||||||
|
result += armor_addheader();
|
||||||
|
result += base64.encode(data);
|
||||||
|
result += "\r\n="+getCheckSum(data)+"\r\n";
|
||||||
|
result += "-----END PGP MESSAGE-----\r\n";
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
result += "-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n";
|
||||||
|
result += armor_addheader();
|
||||||
|
result += base64.encode(data);
|
||||||
|
result += "\r\n="+getCheckSum(data)+"\r\n";
|
||||||
|
result += "-----END PGP PUBLIC KEY BLOCK-----\r\n\r\n";
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
result += "-----BEGIN PGP PRIVATE KEY BLOCK-----\r\n";
|
||||||
|
result += armor_addheader();
|
||||||
|
result += base64.encode(data);
|
||||||
|
result += "\r\n="+getCheckSum(data)+"\r\n";
|
||||||
|
result += "-----END PGP PRIVATE KEY BLOCK-----\r\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
encode: armor,
|
||||||
|
decode: dearmor
|
||||||
|
}
|
|
@ -74,3 +74,8 @@ function r2s(t) {
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
encode: s2r,
|
||||||
|
decode: r2s
|
||||||
|
}
|
||||||
|
|
|
@ -1,128 +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
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper function for the base64 codec.
|
|
||||||
* This function encodes a String (message) in base64 (radix-64)
|
|
||||||
* @param {String} message The message to encode
|
|
||||||
* @return {String} The base64 encoded data
|
|
||||||
*/
|
|
||||||
function openpgp_encoding_base64_encode(message) {
|
|
||||||
return s2r(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper function for the base64 codec.
|
|
||||||
* This function decodes a String(message) in base64 (radix-64)
|
|
||||||
* @param {String} message Base64 encoded data
|
|
||||||
* @return {String} Raw data after decoding
|
|
||||||
*/
|
|
||||||
function openpgp_encoding_base64_decode(message) {
|
|
||||||
return r2s(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create a EME-PKCS1-v1_5 padding (See RFC4880 13.1.1)
|
|
||||||
* @param {String} message message to be padded
|
|
||||||
* @param {Integer} length Length to the resulting message
|
|
||||||
* @return {String} EME-PKCS1 padded message
|
|
||||||
*/
|
|
||||||
function openpgp_encoding_eme_pkcs1_encode(message, length) {
|
|
||||||
if (message.length > length-11)
|
|
||||||
return -1;
|
|
||||||
var result = "";
|
|
||||||
result += String.fromCharCode(0);
|
|
||||||
result += String.fromCharCode(2);
|
|
||||||
for (var i = 0; i < length - message.length - 3; i++) {
|
|
||||||
result += String.fromCharCode(openpgp_crypto_getPseudoRandom(1,255));
|
|
||||||
}
|
|
||||||
result += String.fromCharCode(0);
|
|
||||||
result += message;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* decodes a EME-PKCS1-v1_5 padding (See RFC4880 13.1.2)
|
|
||||||
* @param {String} message EME-PKCS1 padded message
|
|
||||||
* @return {String} decoded message
|
|
||||||
*/
|
|
||||||
function openpgp_encoding_eme_pkcs1_decode(message, len) {
|
|
||||||
if (message.length < len)
|
|
||||||
message = String.fromCharCode(0)+message;
|
|
||||||
if (message.length < 12 || message.charCodeAt(0) != 0 || message.charCodeAt(1) != 2)
|
|
||||||
return -1;
|
|
||||||
var i = 2;
|
|
||||||
while (message.charCodeAt(i) != 0 && message.length > i)
|
|
||||||
i++;
|
|
||||||
return message.substring(i+1, message.length);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* ASN1 object identifiers for hashes (See RFC4880 5.2.2)
|
|
||||||
*/
|
|
||||||
hash_headers = new Array();
|
|
||||||
hash_headers[1] = [0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x04,0x10];
|
|
||||||
hash_headers[3] = [0x30,0x21,0x30,0x09,0x06,0x05,0x2B,0x24,0x03,0x02,0x01,0x05,0x00,0x04,0x14];
|
|
||||||
hash_headers[2] = [0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14];
|
|
||||||
hash_headers[8] = [0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20];
|
|
||||||
hash_headers[9] = [0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04,0x30];
|
|
||||||
hash_headers[10] = [0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,0x40];
|
|
||||||
hash_headers[11] = [0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x04,0x05,0x00,0x04,0x1C];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create a EMSA-PKCS1-v1_5 padding (See RFC4880 13.1.3)
|
|
||||||
* @param {Integer} algo Hash algorithm type used
|
|
||||||
* @param {String} data Data to be hashed
|
|
||||||
* @param {Integer} keylength Key size of the public mpi in bytes
|
|
||||||
* @returns {String} Hashcode with pkcs1padding as string
|
|
||||||
*/
|
|
||||||
function openpgp_encoding_emsa_pkcs1_encode(algo, data, keylength) {
|
|
||||||
var data2 = "";
|
|
||||||
data2 += String.fromCharCode(0x00);
|
|
||||||
data2 += String.fromCharCode(0x01);
|
|
||||||
for (var i = 0; i < (keylength - hash_headers[algo].length - 3 - openpgp_crypto_getHashByteLength(algo)); i++)
|
|
||||||
data2 += String.fromCharCode(0xff);
|
|
||||||
data2 += String.fromCharCode(0x00);
|
|
||||||
|
|
||||||
for (var i = 0; i < hash_headers[algo].length; i++)
|
|
||||||
data2 += String.fromCharCode(hash_headers[algo][i]);
|
|
||||||
|
|
||||||
data2 += openpgp_crypto_hashData(algo, data);
|
|
||||||
return new BigInteger(util.hexstrdump(data2),16);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* extract the hash out of an EMSA-PKCS1-v1.5 padding (See RFC4880 13.1.3)
|
|
||||||
* @param {String} data Hash in pkcs1 encoding
|
|
||||||
* @returns {String} The hash as string
|
|
||||||
*/
|
|
||||||
function openpgp_encoding_emsa_pkcs1_decode(algo, data) {
|
|
||||||
var i = 0;
|
|
||||||
if (data.charCodeAt(0) == 0) i++;
|
|
||||||
else if (data.charCodeAt(0) != 1) return -1;
|
|
||||||
else i++;
|
|
||||||
|
|
||||||
while (data.charCodeAt(i) == 0xFF) i++;
|
|
||||||
if (data.charCodeAt(i++) != 0) return -1;
|
|
||||||
var j = 0;
|
|
||||||
for (j = 0; j < hash_headers[algo].length && j+i < data.length; j++) {
|
|
||||||
if (data.charCodeAt(j+i) != hash_headers[algo][j]) return -1;
|
|
||||||
}
|
|
||||||
i+= j;
|
|
||||||
if (data.substring(i).length < openpgp_crypto_getHashByteLength(algo)) return -1;
|
|
||||||
return data.substring(i);
|
|
||||||
}
|
|
|
@ -2,13 +2,13 @@ module.exports = {
|
||||||
/** RFC4880, section 9.1
|
/** RFC4880, section 9.1
|
||||||
* @enum {String}
|
* @enum {String}
|
||||||
*/
|
*/
|
||||||
openpgp.publicKey = {
|
publicKey: {
|
||||||
rsa_encrypt_sign: 1,
|
rsa_encrypt_sign: 1,
|
||||||
rsa_encrypt: 2,
|
rsa_encrypt: 2,
|
||||||
rsa_sign: 3,
|
rsa_sign: 3,
|
||||||
elgamal: 16,
|
elgamal: 16,
|
||||||
dsa: 17
|
dsa: 17
|
||||||
};
|
},
|
||||||
|
|
||||||
/** RFC4880, section 9.2
|
/** RFC4880, section 9.2
|
||||||
* @enum {String}
|
* @enum {String}
|
||||||
|
@ -57,7 +57,6 @@ module.exports = {
|
||||||
* A list of packet types and numeric tags associated with them.
|
* A list of packet types and numeric tags associated with them.
|
||||||
*/
|
*/
|
||||||
packet: {
|
packet: {
|
||||||
reserved: 0,
|
|
||||||
public_key_encrypted_session_key: 1,
|
public_key_encrypted_session_key: 1,
|
||||||
signature: 2,
|
signature: 2,
|
||||||
sym_encrypted_session_key: 3,
|
sym_encrypted_session_key: 3,
|
||||||
|
@ -201,7 +200,7 @@ module.exports = {
|
||||||
|
|
||||||
// Asserts validity and converts from string/integer to integer.
|
// Asserts validity and converts from string/integer to integer.
|
||||||
write: function(type, e) {
|
write: function(type, e) {
|
||||||
if(typeof n == 'number') {
|
if(typeof e == 'number') {
|
||||||
e = this.read(type, e);
|
e = this.read(type, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +211,7 @@ module.exports = {
|
||||||
// Converts from an integer to string.
|
// Converts from an integer to string.
|
||||||
read: function(type, e) {
|
read: function(type, e) {
|
||||||
for(var i in type)
|
for(var i in type)
|
||||||
if(type[i] == e) return type[e];
|
if(type[i] == e) return i;
|
||||||
|
|
||||||
throw new Error('Invalid enum value.');
|
throw new Error('Invalid enum value.');
|
||||||
}
|
}
|
16
src/index.js
Normal file
16
src/index.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var crypto = require('./crypto');
|
||||||
|
|
||||||
|
module.exports = require('./openpgp.js');
|
||||||
|
module.exports.util = require('./util');
|
||||||
|
module.exports.packet = require('./packet');
|
||||||
|
module.exports.mpi = require('./type/mpi.js');
|
||||||
|
module.exports.s2k = require('./type/s2k.js');
|
||||||
|
module.exports.keyid = require('./type/keyid.js');
|
||||||
|
module.exports.armor = require('./encoding/armor.js');
|
||||||
|
|
||||||
|
for(var i in crypto)
|
||||||
|
module.exports[i] = crypto[i];
|
||||||
|
|
|
@ -456,10 +456,5 @@ function _openpgp () {
|
||||||
this.init = init;
|
this.init = init;
|
||||||
}
|
}
|
||||||
|
|
||||||
var openpgp = new _openpgp();
|
module.exports = new _openpgp();
|
||||||
|
|
||||||
var crypto = require('./crypto');
|
|
||||||
|
|
||||||
module.exports = crypto;
|
|
||||||
module.exports.util = require('./util/util.js');
|
|
||||||
|
|
||||||
|
|
5
src/package.json
Normal file
5
src/package.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"name": "openpgpjs",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"main": "./index.js"
|
||||||
|
}
|
29
src/packet/all_packets.js
Normal file
29
src/packet/all_packets.js
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
|
||||||
|
var enums = require('../enums.js');
|
||||||
|
|
||||||
|
// This is pretty ugly, but browserify needs to have the requires explicitly written.
|
||||||
|
module.exports = {
|
||||||
|
compressed: require('./compressed.js'),
|
||||||
|
sym_encrypted_integrity_protected: require('./sym_encrypted_integrity_protected.js'),
|
||||||
|
public_key_encrypted_session_key: require('./public_key_encrypted_session_key.js'),
|
||||||
|
sym_encrypted_session_key: require('./sym_encrypted_session_key.js'),
|
||||||
|
literal: require('./literal.js'),
|
||||||
|
public_key: require('./public_key.js'),
|
||||||
|
symmetrically_encrypted: require('./symmetrically_encrypted.js'),
|
||||||
|
marker: require('./marker.js'),
|
||||||
|
public_subkey: require('./public_subkey.js'),
|
||||||
|
user_attribute: require('./user_attribute.js'),
|
||||||
|
one_pass_signature: require('./one_pass_signature.js'),
|
||||||
|
secret_key: require('./secret_key.js'),
|
||||||
|
userid: require('./userid.js'),
|
||||||
|
secret_subkey: require('./secret_subkey.js'),
|
||||||
|
signature: require('./signature.js'),
|
||||||
|
trust: require('./trust.js')
|
||||||
|
}
|
||||||
|
|
||||||
|
for(var i in enums.packet) {
|
||||||
|
var packetClass = module.exports[i];
|
||||||
|
|
||||||
|
if(packetClass != undefined)
|
||||||
|
packetClass.prototype.tag = enums.packet[i];
|
||||||
|
}
|
|
@ -15,8 +15,7 @@
|
||||||
// License along with this library; if not, write to the Free Software
|
// License along with this library; if not, write to the Free Software
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
var packetlist = require('./packetlist.js'),
|
var enums = require('../enums.js');
|
||||||
enums = require('../enums.js');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class
|
* @class
|
||||||
|
@ -28,9 +27,9 @@ var packetlist = require('./packetlist.js'),
|
||||||
* a Signature or One-Pass Signature packet, and contains a literal data
|
* a Signature or One-Pass Signature packet, and contains a literal data
|
||||||
* packet.
|
* packet.
|
||||||
*/
|
*/
|
||||||
function packet_compressed() {
|
module.exports = function packet_compressed() {
|
||||||
/** @type {packetlist} */
|
/** @type {packetlist} */
|
||||||
this.packets = new packetlist();
|
this.packets;
|
||||||
/** @type {compression} */
|
/** @type {compression} */
|
||||||
this.algorithm = 'uncompressed';
|
this.algorithm = 'uncompressed';
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
|
|
||||||
var enums = require('../enums.js');
|
var enums = require('../enums.js');
|
||||||
|
|
||||||
module.exports {
|
module.exports = {
|
||||||
list: require('./packetlist.js')
|
list: require('./packetlist.js'),
|
||||||
}
|
}
|
||||||
|
|
||||||
// This need to be invoked before we do stuff with individual packets.
|
var packets = require('./all_packets.js');
|
||||||
for(var i in enums.packets) {
|
|
||||||
var packet = require('./' + i + '.js');
|
|
||||||
|
|
||||||
// Setting the tag in one place.
|
for(var i in packets)
|
||||||
packet.prototype.tag = enum.packets[i];
|
module.exports[i] = packets[i];
|
||||||
}
|
|
||||||
|
|
|
@ -15,6 +15,9 @@
|
||||||
// License along with this library; if not, write to the Free Software
|
// License along with this library; if not, write to the Free Software
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
var util = require('../util'),
|
||||||
|
enums = require('../enums.js');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class
|
* @class
|
||||||
* @classdesc Implementation of the Literal Data Packet (Tag 11)
|
* @classdesc Implementation of the Literal Data Packet (Tag 11)
|
||||||
|
@ -22,7 +25,7 @@
|
||||||
* RFC4880 5.9: A Literal Data packet contains the body of a message; data that
|
* RFC4880 5.9: A Literal Data packet contains the body of a message; data that
|
||||||
* is not to be further interpreted.
|
* is not to be further interpreted.
|
||||||
*/
|
*/
|
||||||
function literal() {
|
module.exports = function packet_literal() {
|
||||||
this.format = 'utf8';
|
this.format = 'utf8';
|
||||||
this.data = '';
|
this.data = '';
|
||||||
this.date = new Date();
|
this.date = new Date();
|
||||||
|
@ -82,17 +85,17 @@ function literal() {
|
||||||
this.read = function(bytes) {
|
this.read = function(bytes) {
|
||||||
// - A one-octet field that describes how the data is formatted.
|
// - A one-octet field that describes how the data is formatted.
|
||||||
|
|
||||||
var format = enums.read(bytes[0]);
|
var format = enums.read(enums.literal, bytes[0].charCodeAt());
|
||||||
|
|
||||||
var filename_len = bytes.charCodeAt(1);
|
var filename_len = bytes.charCodeAt(1);
|
||||||
this.filename = util.decode_utf8(bytes.substr(2, filename_len));
|
this.filename = util.decode_utf8(bytes.substr(2, filename_len));
|
||||||
|
|
||||||
this.date = openpgp_packet_time_read(bytes.substr(2
|
this.date = util.readDate(bytes.substr(2
|
||||||
+ filename_len, 4));
|
+ filename_len, 4));
|
||||||
|
|
||||||
var data = bytes.substring(6 + filename_len);
|
var data = bytes.substring(6 + filename_len);
|
||||||
|
|
||||||
this.set_data_bytes(data, format);
|
this.setBytes(data, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -104,15 +107,14 @@ function literal() {
|
||||||
this.write = function() {
|
this.write = function() {
|
||||||
var filename = util.encode_utf8("msg.txt");
|
var filename = util.encode_utf8("msg.txt");
|
||||||
|
|
||||||
var data = this.get_data_bytes();
|
var data = this.getBytes();
|
||||||
|
|
||||||
var result = '';
|
var result = '';
|
||||||
result += enums.write(this.format);
|
result += String.fromCharCode(enums.write(enums.literal, this.format));
|
||||||
result += String.fromCharCode(filename.length);
|
result += String.fromCharCode(filename.length);
|
||||||
result += filename;
|
result += filename;
|
||||||
result += openpgp_packet_time_write(this.date);
|
result += util.writeDate(this.date);
|
||||||
result += data;
|
result += data;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
*
|
*
|
||||||
* Such a packet MUST be ignored when received.
|
* Such a packet MUST be ignored when received.
|
||||||
*/
|
*/
|
||||||
function openpgp_packet_marker() {
|
function packet_marker() {
|
||||||
/**
|
/**
|
||||||
* Parsing function for a literal data packet (tag 10).
|
* Parsing function for a literal data packet (tag 10).
|
||||||
*
|
*
|
||||||
|
@ -47,3 +47,5 @@ function openpgp_packet_marker() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports = packet_marker;
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
var enums = require('../enums.js');
|
var enums = require('../enums.js');
|
||||||
|
|
||||||
function packet_one_pass_signature() {
|
module.exports = function packet_one_pass_signature() {
|
||||||
this.version = null; // A one-octet version number. The current version is 3.
|
this.version = null; // A one-octet version number. The current version is 3.
|
||||||
this.type = null; // A one-octet signature type. Signature types are described in RFC4880 Section 5.2.1.
|
this.type = null; // A one-octet signature type. Signature types are described in RFC4880 Section 5.2.1.
|
||||||
this.hashAlgorithm = null; // A one-octet number describing the hash algorithm used. (See RFC4880 9.4)
|
this.hashAlgorithm = null; // A one-octet number describing the hash algorithm used. (See RFC4880 9.4)
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
// License along with this library; if not, write to the Free Software
|
// License along with this library; if not, write to the Free Software
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
var enums = require('./enum.js');
|
var enums = require('../enums.js'),
|
||||||
|
util = require('../util');
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
@ -32,7 +33,7 @@ module.exports = {
|
||||||
len = ((bytes[0].charCodeAt() - 192) << 8) + (bytes[1].charCodeAt()) + 192;
|
len = ((bytes[0].charCodeAt() - 192) << 8) + (bytes[1].charCodeAt()) + 192;
|
||||||
offset = 2;
|
offset = 2;
|
||||||
} else if (type == 255) {
|
} else if (type == 255) {
|
||||||
len = openpgp_packet_integer_read(bytes.substr(1, 4));
|
len = util.readNumber(bytes.substr(1, 4));
|
||||||
offset = 5;
|
offset = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,13 +60,10 @@ module.exports = {
|
||||||
result += String.fromCharCode((length - 192) & 0xFF);
|
result += String.fromCharCode((length - 192) & 0xFF);
|
||||||
} else {
|
} else {
|
||||||
result += String.fromCharCode(255);
|
result += String.fromCharCode(255);
|
||||||
result += String.fromCharCode((length >> 24) & 0xFF);
|
result += util.writeNumber(length, 4);
|
||||||
result += String.fromCharCode((length >> 16) & 0xFF);
|
|
||||||
result += String.fromCharCode((length >> 8) & 0xFF);
|
|
||||||
result += String.fromCharCode(length & 0xFF);
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a packet header version 4 with the given tag_type and length to a
|
* Writes a packet header version 4 with the given tag_type and length to a
|
||||||
|
@ -79,9 +77,9 @@ module.exports = {
|
||||||
/* we're only generating v4 packet headers here */
|
/* we're only generating v4 packet headers here */
|
||||||
var result = "";
|
var result = "";
|
||||||
result += String.fromCharCode(0xC0 | tag_type);
|
result += String.fromCharCode(0xC0 | tag_type);
|
||||||
result += this.encode_length(length);
|
result += this.writeSimpleLength(length);
|
||||||
return result;
|
return result;
|
||||||
}
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a packet header Version 3 with the given tag_type and length to a
|
* Writes a packet header Version 3 with the given tag_type and length to a
|
||||||
|
@ -98,17 +96,13 @@ module.exports = {
|
||||||
result += String.fromCharCode(length);
|
result += String.fromCharCode(length);
|
||||||
} else if (length < 65536) {
|
} else if (length < 65536) {
|
||||||
result += String.fromCharCode(0x80 | (tag_type << 2) | 1);
|
result += String.fromCharCode(0x80 | (tag_type << 2) | 1);
|
||||||
result += String.fromCharCode(length >> 8);
|
result += util.writeNumber(length, 2);
|
||||||
result += String.fromCharCode(length & 0xFF);
|
|
||||||
} else {
|
} else {
|
||||||
result += String.fromCharCode(0x80 | (tag_type << 2) | 2);
|
result += String.fromCharCode(0x80 | (tag_type << 2) | 2);
|
||||||
result += String.fromCharCode((length >> 24) & 0xFF);
|
result += util.writeNumber(length, 4);
|
||||||
result += String.fromCharCode((length >> 16) & 0xFF);
|
|
||||||
result += String.fromCharCode((length >> 8) & 0xFF);
|
|
||||||
result += String.fromCharCode(length & 0xFF);
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic static Packet Parser function
|
* Generic static Packet Parser function
|
||||||
|
@ -118,7 +112,7 @@ module.exports = {
|
||||||
* @param {integer} len Length of the input from position on
|
* @param {integer} len Length of the input from position on
|
||||||
* @return {Object} Returns a parsed openpgp_packet
|
* @return {Object} Returns a parsed openpgp_packet
|
||||||
*/
|
*/
|
||||||
this.read_packet = function(input, position, len) {
|
read: function(input, position, len) {
|
||||||
// some sanity checks
|
// some sanity checks
|
||||||
if (input == null || input.length <= position
|
if (input == null || input.length <= position
|
||||||
|| input.substring(position).length < 2
|
|| input.substring(position).length < 2
|
||||||
|
@ -264,35 +258,9 @@ module.exports = {
|
||||||
bodydata = input.substring(mypos, mypos + real_packet_length);
|
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[mypos++].charCodeAt() > 15)
|
|
||||||
// version = 2;
|
|
||||||
|
|
||||||
var names_by_tag = {};
|
|
||||||
|
|
||||||
for(var i in this.type)
|
|
||||||
names_by_tag[this.type[i]] = i;
|
|
||||||
|
|
||||||
var classname = 'openpgp_packet_' + names_by_tag[tag];
|
|
||||||
|
|
||||||
var packetclass = window[classname];
|
|
||||||
|
|
||||||
if(packetclass == undefined) {
|
|
||||||
throw classname;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = new packetclass();
|
|
||||||
result.read(bodydata);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
packet: result,
|
tag: tag,
|
||||||
|
packet: bodydata,
|
||||||
offset: mypos + real_packet_length
|
offset: mypos + real_packet_length
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
|
|
||||||
|
|
||||||
|
var packetParser = require('./packet.js'),
|
||||||
|
packets = require('./all_packets.js'),
|
||||||
|
enums = require('../enums.js');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class
|
* @class
|
||||||
* @classdesc This class represents a list of openpgp packets.
|
* @classdesc This class represents a list of openpgp packets.
|
||||||
* Take care when iterating over it - the packets themselves
|
* Take care when iterating over it - the packets themselves
|
||||||
* are stored as numerical indices.
|
* are stored as numerical indices.
|
||||||
*/
|
*/
|
||||||
function packetlist() {
|
module.exports = function packetlist() {
|
||||||
/** The number of packets contained within the list.
|
/** The number of packets contained within the list.
|
||||||
* @readonly
|
* @readonly
|
||||||
* @type {Integer} */
|
* @type {Integer} */
|
||||||
|
@ -22,10 +26,15 @@ function packetlist() {
|
||||||
var i = 0;
|
var i = 0;
|
||||||
|
|
||||||
while(i < bytes.length) {
|
while(i < bytes.length) {
|
||||||
var parsed = openpgp_packet.read_packet(bytes, i, bytes.length - i);
|
var parsed = packetParser.read(bytes, i, bytes.length - i);
|
||||||
i = parsed.offset;
|
i = parsed.offset;
|
||||||
|
|
||||||
this.push(parsed.packet);
|
var tag = enums.read(enums.packet, parsed.tag);
|
||||||
|
var packet = new packets[tag]();
|
||||||
|
|
||||||
|
this.push(packet);
|
||||||
|
|
||||||
|
packet.read(parsed.packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,18 +48,22 @@ function packetlist() {
|
||||||
|
|
||||||
for(var i = 0; i < this.length; i++) {
|
for(var i = 0; i < this.length; i++) {
|
||||||
var packetbytes = this[i].write();
|
var packetbytes = this[i].write();
|
||||||
bytes += openpgp_packet.write_packet_header(this[i].tag, packetbytes.length);
|
bytes += packetParser.writeHeader(this[i].tag, packetbytes.length);
|
||||||
bytes += packetbytes;
|
bytes += packetbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a packet to the list. This is the only supported method of doing so;
|
||||||
|
* writing to packetlist[i] directly will result in an error.
|
||||||
|
*/
|
||||||
this.push = function(packet) {
|
this.push = function(packet) {
|
||||||
|
packet.packets = new packetlist();
|
||||||
|
|
||||||
this[this.length] = packet;
|
this[this.length] = packet;
|
||||||
this.length++;
|
this.length++;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = packetlist;
|
|
||||||
|
|
|
@ -24,8 +24,7 @@
|
||||||
* private key. There are four variants of this packet type, and two
|
* private key. There are four variants of this packet type, and two
|
||||||
* major versions. Consequently, this section is complex.
|
* major versions. Consequently, this section is complex.
|
||||||
*/
|
*/
|
||||||
function openpgp_packet_public_key() {
|
module.exports = function packet_public_key() {
|
||||||
this.tag = 6;
|
|
||||||
/** Key creation date.
|
/** Key creation date.
|
||||||
* @type {Date} */
|
* @type {Date} */
|
||||||
this.created = new Date();
|
this.created = new Date();
|
||||||
|
@ -34,7 +33,7 @@ function openpgp_packet_public_key() {
|
||||||
this.mpi = [];
|
this.mpi = [];
|
||||||
/** Public key algorithm
|
/** Public key algorithm
|
||||||
* @type {openpgp.publickey} */
|
* @type {openpgp.publickey} */
|
||||||
this.algorithm = openpgp.publickey.rsa_sign;
|
this.algorithm = 'rsa_sign';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -31,15 +31,14 @@
|
||||||
* public key, decrypts the session key, and then uses the session key to
|
* public key, decrypts the session key, and then uses the session key to
|
||||||
* decrypt the message.
|
* decrypt the message.
|
||||||
*/
|
*/
|
||||||
function openpgp_packet_public_key_encrypted_session_key() {
|
module.exports = function packet_public_key_encrypted_session_key() {
|
||||||
this.tag = 1;
|
|
||||||
this.version = 3;
|
this.version = 3;
|
||||||
|
|
||||||
this.public_key_id = new openpgp_type_keyid();
|
this.publicKeyId = new openpgp_type_keyid();
|
||||||
this.public_key_algorithm = openpgp.publickey.rsa_encrypt;
|
this.publicKeyAlgorithm = 'rsa_encrypt';
|
||||||
|
|
||||||
this.symmetric_key = null;
|
this.sessionKey = null;
|
||||||
this.symmetric_algorithm = openpgp.symmetric.plaintext;
|
this.sessionKeyAlgorithm = 'aes256';
|
||||||
|
|
||||||
/** @type {openpgp_type_mpi[]} */
|
/** @type {openpgp_type_mpi[]} */
|
||||||
this.encrypted = [];
|
this.encrypted = [];
|
||||||
|
|
|
@ -17,9 +17,6 @@
|
||||||
|
|
||||||
var public_key = require('./public_key.js');
|
var public_key = require('./public_key.js');
|
||||||
|
|
||||||
function public_subkey() {
|
module.exports = function public_subkey() {
|
||||||
public_key.call(this);
|
public_key.call(this);
|
||||||
this.tag = 14;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = public_subkey;
|
|
||||||
|
|
|
@ -15,6 +15,10 @@
|
||||||
// License along with this library; if not, write to the Free Software
|
// License along with this library; if not, write to the Free Software
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
var publicKey = require('./public_key.js'),
|
||||||
|
util = require('../util'),
|
||||||
|
crypto = require('../crypto');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class
|
* @class
|
||||||
* @classdesc Implementation of the Key Material Packet (Tag 5,6,7,14)
|
* @classdesc Implementation of the Key Material Packet (Tag 5,6,7,14)
|
||||||
|
@ -24,10 +28,9 @@
|
||||||
* private key. There are four variants of this packet type, and two
|
* private key. There are four variants of this packet type, and two
|
||||||
* major versions. Consequently, this section is complex.
|
* major versions. Consequently, this section is complex.
|
||||||
*/
|
*/
|
||||||
function openpgp_packet_secret_key() {
|
function packet_secret_key() {
|
||||||
openpgp_packet_public_key.call(this);
|
publicKey.call(this);
|
||||||
|
|
||||||
this.tag = 5;
|
|
||||||
this.encrypted = null;
|
this.encrypted = null;
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,7 +46,7 @@ function openpgp_packet_secret_key() {
|
||||||
return str_sha1;
|
return str_sha1;
|
||||||
else
|
else
|
||||||
return function(c) {
|
return function(c) {
|
||||||
return openpgp_packet_number_write(util.calc_checksum(c), 2);
|
return util.writeNumber(util.calc_checksum(c), 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +63,7 @@ function openpgp_packet_secret_key() {
|
||||||
if(hash != hashtext)
|
if(hash != hashtext)
|
||||||
throw new Error("Hash mismatch.");
|
throw new Error("Hash mismatch.");
|
||||||
|
|
||||||
var mpis = openpgp_crypto_getPrivateMpiCount(algorithm);
|
var mpis = crypto.getPrivateMpiCount(algorithm);
|
||||||
|
|
||||||
var j = 0;
|
var j = 0;
|
||||||
var mpi = [];
|
var mpi = [];
|
||||||
|
@ -74,7 +77,7 @@ function openpgp_packet_secret_key() {
|
||||||
|
|
||||||
function write_cleartext_mpi(hash_algorithm, mpi) {
|
function write_cleartext_mpi(hash_algorithm, mpi) {
|
||||||
var bytes= '';
|
var bytes= '';
|
||||||
var discard = openpgp_crypto_getPublicMpiCount(this.algorithm);
|
var discard = crypto.getPublicMpiCount(this.algorithm);
|
||||||
|
|
||||||
for(var i = discard; i < mpi.length; i++) {
|
for(var i = discard; i < mpi.length; i++) {
|
||||||
bytes += mpi[i].write();
|
bytes += mpi[i].write();
|
||||||
|
@ -305,5 +308,6 @@ function openpgp_packet_secret_key() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
openpgp_packet_secret_key.prototype = new openpgp_packet_public_key();
|
packet_secret_key.prototype = new publicKey;
|
||||||
|
|
||||||
|
module.exports = packet_secret_key;
|
||||||
|
|
|
@ -17,9 +17,6 @@
|
||||||
|
|
||||||
var secret_key = require('./secret_key.js');
|
var secret_key = require('./secret_key.js');
|
||||||
|
|
||||||
function secret_subkey() {
|
module.exports = function secret_subkey() {
|
||||||
secret_key.call(this);
|
secret_key.call(this);
|
||||||
this.tag = 7;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = secret_subkey.js;
|
|
||||||
|
|
|
@ -15,6 +15,12 @@
|
||||||
// License along with this library; if not, write to the Free Software
|
// License along with this library; if not, write to the Free Software
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
var util = require('../util'),
|
||||||
|
packet = require('./packet.js'),
|
||||||
|
enums = require('../enums.js'),
|
||||||
|
crypto = require('../crypto'),
|
||||||
|
type_mpi = require('../type/mpi.js');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class
|
* @class
|
||||||
* @classdesc Implementation of the Signature Packet (Tag 2)
|
* @classdesc Implementation of the Signature Packet (Tag 2)
|
||||||
|
@ -24,8 +30,7 @@
|
||||||
* some data. The most common signatures are a signature of a file or a
|
* 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.
|
* block of text, and a signature that is a certification of a User ID.
|
||||||
*/
|
*/
|
||||||
function openpgp_packet_signature() {
|
module.exports = function packet_signature() {
|
||||||
this.tag = 2;
|
|
||||||
|
|
||||||
this.signatureType = null;
|
this.signatureType = null;
|
||||||
this.hashAlgorithm = null;
|
this.hashAlgorithm = null;
|
||||||
|
@ -94,7 +99,7 @@ function openpgp_packet_signature() {
|
||||||
this.signatureType = bytes[i++].charCodeAt();
|
this.signatureType = bytes[i++].charCodeAt();
|
||||||
|
|
||||||
// Four-octet creation time.
|
// Four-octet creation time.
|
||||||
this.created = openpgp_packet_time_read(bytes.substr(i, 4));
|
this.created = util.readDate(bytes.substr(i, 4));
|
||||||
i += 4;
|
i += 4;
|
||||||
|
|
||||||
// storing data appended to data which gets verified
|
// storing data appended to data which gets verified
|
||||||
|
@ -119,7 +124,7 @@ function openpgp_packet_signature() {
|
||||||
function subpackets(bytes, signed) {
|
function subpackets(bytes, signed) {
|
||||||
// Two-octet scalar octet count for following hashed subpacket
|
// Two-octet scalar octet count for following hashed subpacket
|
||||||
// data.
|
// data.
|
||||||
var subpacket_length = openpgp_packet_number_read(
|
var subpacket_length = util.readNumber(
|
||||||
bytes.substr(0, 2));
|
bytes.substr(0, 2));
|
||||||
|
|
||||||
var i = 2;
|
var i = 2;
|
||||||
|
@ -128,7 +133,7 @@ function openpgp_packet_signature() {
|
||||||
var subpacked_read = 0;
|
var subpacked_read = 0;
|
||||||
while (i < 2 + subpacket_length) {
|
while (i < 2 + subpacket_length) {
|
||||||
|
|
||||||
var len = openpgp_packet.read_simple_length(bytes.substr(i));
|
var len = packet.readSimpleLength(bytes.substr(i));
|
||||||
i += len.offset;
|
i += len.offset;
|
||||||
|
|
||||||
// Since it is trivial to add data to the unhashed portion of
|
// Since it is trivial to add data to the unhashed portion of
|
||||||
|
@ -169,7 +174,7 @@ function openpgp_packet_signature() {
|
||||||
|
|
||||||
this.write = function() {
|
this.write = function() {
|
||||||
return this.signatureData +
|
return this.signatureData +
|
||||||
openpgp_packet_number_write(0, 2) + // Number of unsigned subpackets.
|
util.writeNumber(0, 2) + // Number of unsigned subpackets.
|
||||||
this.signedHashValue +
|
this.signedHashValue +
|
||||||
this.signature;
|
this.signature;
|
||||||
}
|
}
|
||||||
|
@ -180,30 +185,34 @@ function openpgp_packet_signature() {
|
||||||
* @param {openpgp_msg_privatekey} privatekey private key used to sign the message.
|
* @param {openpgp_msg_privatekey} privatekey private key used to sign the message.
|
||||||
*/
|
*/
|
||||||
this.sign = function(key, data) {
|
this.sign = function(key, data) {
|
||||||
|
var signatureType = enums.write(enums.signature, this.signatureType),
|
||||||
|
publicKeyAlgorithm = enums.write(enums.publicKey, this.publicKeyAlgorithm),
|
||||||
|
hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm);
|
||||||
|
|
||||||
var result = String.fromCharCode(4);
|
var result = String.fromCharCode(4);
|
||||||
result += String.fromCharCode(this.signatureType);
|
result += String.fromCharCode(signatureType);
|
||||||
result += String.fromCharCode(this.publicKeyAlgorithm);
|
result += String.fromCharCode(publicKeyAlgorithm);
|
||||||
result += String.fromCharCode(this.hashAlgorithm);
|
result += String.fromCharCode(hashAlgorithm);
|
||||||
|
|
||||||
|
|
||||||
// Add subpackets here
|
// Add subpackets here
|
||||||
result += openpgp_packet_number_write(0, 2);
|
result += util.writeNumber(0, 2);
|
||||||
|
|
||||||
|
|
||||||
this.signatureData = result;
|
this.signatureData = result;
|
||||||
|
|
||||||
var trailer = this.calculateTrailer();
|
var trailer = this.calculateTrailer();
|
||||||
|
|
||||||
var toHash = this.toSign(this.signatureType, data) +
|
var toHash = this.toSign(signatureType, data) +
|
||||||
this.signatureData + trailer;
|
this.signatureData + trailer;
|
||||||
var hash = openpgp_crypto_hashData(this.hashAlgorithm, toHash);
|
|
||||||
|
var hash = crypto.hash.digest(hashAlgorithm, toHash);
|
||||||
|
|
||||||
this.signedHashValue = hash.substr(0, 2);
|
this.signedHashValue = hash.substr(0, 2);
|
||||||
|
|
||||||
|
|
||||||
this.signature = openpgp_crypto_signData(this.hashAlgorithm,
|
this.signature = crypto.signature.sign(hashAlgorithm,
|
||||||
this.publicKeyAlgorithm, key.mpi, toHash);
|
publicKeyAlgorithm, key.mpi, toHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -215,7 +224,7 @@ function openpgp_packet_signature() {
|
||||||
*/
|
*/
|
||||||
function write_sub_packet(type, data) {
|
function write_sub_packet(type, data) {
|
||||||
var result = "";
|
var result = "";
|
||||||
result += openpgp_packet.encode_length(data.length+1);
|
result += packet.writeSimpleLength(data.length+1);
|
||||||
result += String.fromCharCode(type);
|
result += String.fromCharCode(type);
|
||||||
result += data;
|
result += data;
|
||||||
return result;
|
return result;
|
||||||
|
@ -240,10 +249,10 @@ function openpgp_packet_signature() {
|
||||||
// subpacket type
|
// subpacket type
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 2: // Signature Creation Time
|
case 2: // Signature Creation Time
|
||||||
this.created = openpgp_packet_time_read(bytes.substr(mypos));
|
this.created = util.readDate(bytes.substr(mypos));
|
||||||
break;
|
break;
|
||||||
case 3: // Signature Expiration Time
|
case 3: // Signature Expiration Time
|
||||||
var time = openpgp_packet_time_read(bytes.substr(mypos));
|
var time = util.readDate(bytes.substr(mypos));
|
||||||
|
|
||||||
this.signatureNeverExpires = time.getTime() == 0;
|
this.signatureNeverExpires = time.getTime() == 0;
|
||||||
this.signatureExpirationTime = time;
|
this.signatureExpirationTime = time;
|
||||||
|
@ -263,7 +272,7 @@ function openpgp_packet_signature() {
|
||||||
this.revocable = bytes[mypos++].charCodeAt() == 1;
|
this.revocable = bytes[mypos++].charCodeAt() == 1;
|
||||||
break;
|
break;
|
||||||
case 9: // Key Expiration Time
|
case 9: // Key Expiration Time
|
||||||
var time = openpgp_packet_time_read(bytes.substr(mypos));
|
var time = util.readDate(bytes.substr(mypos));
|
||||||
|
|
||||||
this.keyExpirationTime = time;
|
this.keyExpirationTime = time;
|
||||||
this.keyNeverExpires = time.getTime() == 0;
|
this.keyNeverExpires = time.getTime() == 0;
|
||||||
|
@ -296,9 +305,9 @@ function openpgp_packet_signature() {
|
||||||
|
|
||||||
// We extract key/value tuple from the byte stream.
|
// We extract key/value tuple from the byte stream.
|
||||||
mypos += 4;
|
mypos += 4;
|
||||||
var m = openpgp_packet_number_read(bytes.substr(mypos, 2));
|
var m = util.writeNumber(bytes.substr(mypos, 2));
|
||||||
mypos += 2
|
mypos += 2
|
||||||
var n = openpgp_packet_number_read(bytes.substr(mypos, 2));
|
var n = util.writeNumber(bytes.substr(mypos, 2));
|
||||||
mypos += 2
|
mypos += 2
|
||||||
|
|
||||||
var name = bytes.substr(mypos, m),
|
var name = bytes.substr(mypos, m),
|
||||||
|
@ -344,12 +353,12 @@ function openpgp_packet_signature() {
|
||||||
this.signatureTargetPublicKeyAlgorithm = bytes[mypos++].charCodeAt();
|
this.signatureTargetPublicKeyAlgorithm = bytes[mypos++].charCodeAt();
|
||||||
this.signatureTargetHashAlgorithm = bytes[mypos++].charCodeAt();
|
this.signatureTargetHashAlgorithm = bytes[mypos++].charCodeAt();
|
||||||
|
|
||||||
var len = openpgp_crypto_getHashByteLength(this.signatureTargetHashAlgorithm);
|
var len = crypto.getHashByteLength(this.signatureTargetHashAlgorithm);
|
||||||
|
|
||||||
this.signatureTargetHash = bytes.substr(mypos, len);
|
this.signatureTargetHash = bytes.substr(mypos, len);
|
||||||
break;
|
break;
|
||||||
case 32: // Embedded Signature
|
case 32: // Embedded Signature
|
||||||
this.embeddedSignature = new openpgp_packet_signature();
|
this.embeddedSignature = new packet_signature();
|
||||||
this.embeddedSignature.read(bytes.substr(mypos));
|
this.embeddedSignature.read(bytes.substr(mypos));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -362,11 +371,11 @@ function openpgp_packet_signature() {
|
||||||
|
|
||||||
// Produces data to produce signature on
|
// Produces data to produce signature on
|
||||||
this.toSign = function(type, data) {
|
this.toSign = function(type, data) {
|
||||||
var t = openpgp_packet_signature.type;
|
var t = enums.signature
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case t.binary:
|
case t.binary:
|
||||||
return data.literal.get_data_bytes();
|
return data.literal.getBytes();
|
||||||
|
|
||||||
case t.text:
|
case t.text:
|
||||||
return this.toSign(t.binary, data)
|
return this.toSign(t.binary, data)
|
||||||
|
@ -401,7 +410,7 @@ function openpgp_packet_signature() {
|
||||||
|
|
||||||
return this.toSign(t.key, data) +
|
return this.toSign(t.key, data) +
|
||||||
String.fromCharCode(tag) +
|
String.fromCharCode(tag) +
|
||||||
openpgp_packet_number_write(bytes.length, 4) +
|
util.writeNumber(bytes.length, 4) +
|
||||||
bytes;
|
bytes;
|
||||||
}
|
}
|
||||||
case t.subkey_binding:
|
case t.subkey_binding:
|
||||||
|
@ -435,7 +444,7 @@ function openpgp_packet_signature() {
|
||||||
var trailer = '';
|
var trailer = '';
|
||||||
trailer += String.fromCharCode(4); // Version
|
trailer += String.fromCharCode(4); // Version
|
||||||
trailer += String.fromCharCode(0xFF);
|
trailer += String.fromCharCode(0xFF);
|
||||||
trailer += openpgp_packet_number_write(this.signatureData.length, 4);
|
trailer += util.writeNumber(this.signatureData.length, 4);
|
||||||
return trailer
|
return trailer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,30 +456,33 @@ function openpgp_packet_signature() {
|
||||||
* @return {boolean} True if message is verified, else false.
|
* @return {boolean} True if message is verified, else false.
|
||||||
*/
|
*/
|
||||||
this.verify = function(key, data) {
|
this.verify = function(key, data) {
|
||||||
|
var signatureType = enums.write(enums.signature, this.signatureType),
|
||||||
|
publicKeyAlgorithm = enums.write(enums.publicKey, this.publicKeyAlgorithm),
|
||||||
|
hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm);
|
||||||
|
|
||||||
var bytes = this.toSign(this.signatureType, data),
|
var bytes = this.toSign(signatureType, data),
|
||||||
trailer = this.calculateTrailer();
|
trailer = this.calculateTrailer();
|
||||||
|
|
||||||
|
|
||||||
var mpicount = 0;
|
var mpicount = 0;
|
||||||
// Algorithm-Specific Fields for RSA signatures:
|
// Algorithm-Specific Fields for RSA signatures:
|
||||||
// - multiprecision number (MPI) of RSA signature value m**d mod n.
|
// - multiprecision number (MPI) of RSA signature value m**d mod n.
|
||||||
if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4)
|
if (publicKeyAlgorithm > 0 && publicKeyAlgorithm < 4)
|
||||||
mpicount = 1;
|
mpicount = 1;
|
||||||
// Algorithm-Specific Fields for DSA signatures:
|
// Algorithm-Specific Fields for DSA signatures:
|
||||||
// - MPI of DSA value r.
|
// - MPI of DSA value r.
|
||||||
// - MPI of DSA value s.
|
// - MPI of DSA value s.
|
||||||
else if (this.publicKeyAlgorithm == 17)
|
else if (publicKeyAlgorithm == 17)
|
||||||
mpicount = 2;
|
mpicount = 2;
|
||||||
|
|
||||||
var mpi = [], i = 0;
|
var mpi = [], i = 0;
|
||||||
for (var j = 0; j < mpicount; j++) {
|
for (var j = 0; j < mpicount; j++) {
|
||||||
mpi[j] = new openpgp_type_mpi();
|
mpi[j] = new type_mpi();
|
||||||
i += mpi[j].read(this.signature.substr(i));
|
i += mpi[j].read(this.signature.substr(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm,
|
this.verified = crypto.signature.verify(publicKeyAlgorithm,
|
||||||
this.hashAlgorithm, mpi, key.mpi,
|
hashAlgorithm, mpi, key.mpi,
|
||||||
bytes + this.signatureData + trailer);
|
bytes + this.signatureData + trailer);
|
||||||
|
|
||||||
return this.verified;
|
return this.verified;
|
||||||
|
|
|
@ -27,8 +27,7 @@
|
||||||
* packet.
|
* packet.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function openpgp_packet_sym_encrypted_integrity_protected() {
|
module.exports = function packet_sym_encrypted_integrity_protected() {
|
||||||
this.tag = 18;
|
|
||||||
/** The encrypted payload. */
|
/** The encrypted payload. */
|
||||||
this.encrypted = null; // string
|
this.encrypted = null; // string
|
||||||
/** @type {Boolean}
|
/** @type {Boolean}
|
||||||
|
@ -37,7 +36,7 @@ function openpgp_packet_sym_encrypted_integrity_protected() {
|
||||||
* should be discarded.
|
* should be discarded.
|
||||||
*/
|
*/
|
||||||
this.modification = false;
|
this.modification = false;
|
||||||
this.packets = new openpgp_packetlist();
|
this.packets;
|
||||||
|
|
||||||
|
|
||||||
this.read = function(bytes) {
|
this.read = function(bytes) {
|
||||||
|
@ -116,9 +115,7 @@ function openpgp_packet_sym_encrypted_integrity_protected() {
|
||||||
var mdc = decrypted.substr(decrypted.length - 20, 20);
|
var mdc = decrypted.substr(decrypted.length - 20, 20);
|
||||||
|
|
||||||
if(this.hash != mdc) {
|
if(this.hash != mdc) {
|
||||||
this.packets = new openpgp_packetlist();
|
|
||||||
throw new Error('Modification detected.');
|
throw new Error('Modification detected.');
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
this.packets.read(decrypted.substr(0, decrypted.length - 22));
|
this.packets.read(decrypted.substr(0, decrypted.length - 22));
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
* public key, decrypts the session key, and then uses the session key to
|
* public key, decrypts the session key, and then uses the session key to
|
||||||
* decrypt the message.
|
* decrypt the message.
|
||||||
*/
|
*/
|
||||||
function openpgp_packet_sym_encrypted_session_key() {
|
module.exports = function packet_sym_encrypted_session_key() {
|
||||||
this.tag = 3;
|
this.tag = 3;
|
||||||
this.private_algorithm = null;
|
this.private_algorithm = null;
|
||||||
this.algorithm = openpgp.symmetric.aes256;
|
this.algorithm = openpgp.symmetric.aes256;
|
||||||
|
|
|
@ -26,12 +26,11 @@
|
||||||
* that form whole OpenPGP messages).
|
* that form whole OpenPGP messages).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function openpgp_packet_symmetrically_encrypted() {
|
module.exports = function packet_symmetrically_encrypted() {
|
||||||
this.tag = 9;
|
|
||||||
this.encrypted = null;
|
this.encrypted = null;
|
||||||
/** Decrypted packets contained within.
|
/** Decrypted packets contained within.
|
||||||
* @type {openpgp_packetlist} */
|
* @type {openpgp_packetlist} */
|
||||||
this.packets = new openpgp_packetlist();
|
this.packets;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function openpgp_packet_number_read(bytes) {
|
|
||||||
var n = 0;
|
|
||||||
|
|
||||||
for(var i = 0; i < bytes.length; i++) {
|
|
||||||
n <<= 8;
|
|
||||||
n += bytes[i].charCodeAt()
|
|
||||||
}
|
|
||||||
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
function openpgp_packet_number_write(n, bytes) {
|
|
||||||
var b = '';
|
|
||||||
for(var i = 0; i < bytes; i++) {
|
|
||||||
b += String.fromCharCode((n >> (8 * (bytes- i - 1))) & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function openpgp_packet_time_read(bytes) {
|
|
||||||
var n = openpgp_packet_number_read(bytes);
|
|
||||||
var d = new Date();
|
|
||||||
d.setTime(n * 1000);
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
function openpgp_packet_time_write(time) {
|
|
||||||
var numeric = Math.round(time.getTime() / 1000);
|
|
||||||
|
|
||||||
return openpgp_packet_number_write(numeric, 4);
|
|
||||||
}
|
|
4
src/packet/trust.js
Normal file
4
src/packet/trust.js
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
module.exports = function packet_trust() {
|
||||||
|
|
||||||
|
};
|
|
@ -32,7 +32,7 @@
|
||||||
* User Attribute packet as a User ID packet with opaque contents, but
|
* User Attribute packet as a User ID packet with opaque contents, but
|
||||||
* an implementation may use any method desired.
|
* an implementation may use any method desired.
|
||||||
*/
|
*/
|
||||||
function openpgp_packet_user_attribute() {
|
module.exports = function packet_user_attribute() {
|
||||||
this.tag = 17;
|
this.tag = 17;
|
||||||
this.attributes = [];
|
this.attributes = [];
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
// License along with this library; if not, write to the Free Software
|
// License along with this library; if not, write to the Free Software
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
var util = require('../util/util.js');
|
var util = require('../util');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class
|
* @class
|
||||||
|
@ -26,7 +26,7 @@ var util = require('../util/util.js');
|
||||||
* restrictions on its content. The packet length in the header
|
* restrictions on its content. The packet length in the header
|
||||||
* specifies the length of the User ID.
|
* specifies the length of the User ID.
|
||||||
*/
|
*/
|
||||||
function packet_userid() {
|
module.exports = function packet_userid() {
|
||||||
/** @type {String} A string containing the user id. Usually in the form
|
/** @type {String} A string containing the user id. Usually in the form
|
||||||
* John Doe <john@example.com>
|
* John Doe <john@example.com>
|
||||||
*/
|
*/
|
||||||
|
@ -54,5 +54,3 @@ function packet_userid() {
|
||||||
return util.encode_utf8(this.userid);
|
return util.encode_utf8(this.userid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = packet_userid;
|
|
||||||
|
|
|
@ -20,6 +20,9 @@
|
||||||
// - MPI size: (a << 8) | b
|
// - MPI size: (a << 8) | b
|
||||||
// - MPI = c | d << 8 | e << ((MPI.length -2)*8) | f ((MPI.length -2)*8)
|
// - MPI = c | d << 8 | e << ((MPI.length -2)*8) | f ((MPI.length -2)*8)
|
||||||
|
|
||||||
|
var BigInteger = require('../crypto/public_key/jsbn.js'),
|
||||||
|
util = require('../util');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class
|
* @class
|
||||||
* @classdescImplementation of type MPI (RFC4880 3.2)
|
* @classdescImplementation of type MPI (RFC4880 3.2)
|
||||||
|
@ -30,7 +33,7 @@
|
||||||
* of the MPI in bits followed by a string of octets that contain the
|
* of the MPI in bits followed by a string of octets that contain the
|
||||||
* actual integer.
|
* actual integer.
|
||||||
*/
|
*/
|
||||||
function openpgp_type_mpi() {
|
module.exports = function mpi() {
|
||||||
/** An implementation dependent integer */
|
/** An implementation dependent integer */
|
||||||
this.data = null;
|
this.data = null;
|
||||||
|
|
||||||
|
@ -91,15 +94,5 @@ function openpgp_type_mpi() {
|
||||||
this.fromBigInteger = function(bn) {
|
this.fromBigInteger = function(bn) {
|
||||||
this.data = bn.clone();
|
this.data = bn.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates debug output (pretty print)
|
|
||||||
* @return {String} String which gives some information about the mpi
|
|
||||||
*/
|
|
||||||
this.toString = function() {
|
|
||||||
var r = " MPI("+this.mpiBitLength+"b/"+this.mpiByteLength+"B) : 0x";
|
|
||||||
r+=util.hexstrdump(this.MPI);
|
|
||||||
return r+'\n';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,151 +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[mypos++].charCodeAt();
|
|
||||||
switch (this.type) {
|
|
||||||
case 0: // Simple S2K
|
|
||||||
// Octet 1: hash algorithm
|
|
||||||
this.hashAlgorithm = input[mypos++].charCodeAt();
|
|
||||||
this.s2kLength = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1: // Salted S2K
|
|
||||||
// Octet 1: hash algorithm
|
|
||||||
this.hashAlgorithm = input[mypos++].charCodeAt();
|
|
||||||
|
|
||||||
// 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[mypos++].charCodeAt();
|
|
||||||
|
|
||||||
// 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[mypos++].charCodeAt();
|
|
||||||
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[mypos++].charCodeAt();
|
|
||||||
mypos += 3; // GNU
|
|
||||||
var gnuExtType = 1000 + input[mypos++].charCodeAt();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
this.packetLength = mypos - position;
|
|
||||||
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);
|
|
||||||
var result;
|
|
||||||
|
|
||||||
if (this.type == 0) {
|
|
||||||
result = openpgp_crypto_hashData(this.hashAlgorithm,passphrase);
|
|
||||||
} else if (this.type == 1) {
|
|
||||||
result = 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);
|
|
||||||
result = key + openpgp_crypto_hashData(this.hashAlgorithm,
|
|
||||||
String.fromCharCode(0)+isp);
|
|
||||||
}
|
|
||||||
else result = openpgp_crypto_hashData(this.hashAlgorithm,isp);
|
|
||||||
} else return null;
|
|
||||||
|
|
||||||
return result.substr(0, numBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.read = read;
|
|
||||||
this.write = write;
|
|
||||||
this.produce_key = produce_key;
|
|
||||||
}
|
|
5
src/util/package.json
Normal file
5
src/util/package.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"name": "openpgp-util",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"main": "./util.js"
|
||||||
|
}
|
|
@ -17,6 +17,43 @@
|
||||||
|
|
||||||
var Util = function() {
|
var Util = function() {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
this.readNumber = function (bytes) {
|
||||||
|
var n = 0;
|
||||||
|
|
||||||
|
for(var i = 0; i < bytes.length; i++) {
|
||||||
|
n <<= 8;
|
||||||
|
n += bytes[i].charCodeAt()
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.writeNumber = function(n, bytes) {
|
||||||
|
var b = '';
|
||||||
|
for(var i = 0; i < bytes; i++) {
|
||||||
|
b += String.fromCharCode((n >> (8 * (bytes- i - 1))) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
this.readDate = function(bytes) {
|
||||||
|
var n = this.readNumber(bytes);
|
||||||
|
var d = new Date();
|
||||||
|
d.setTime(n * 1000);
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.writeDate = function(time) {
|
||||||
|
var numeric = Math.round(time.getTime() / 1000);
|
||||||
|
|
||||||
|
return this.writeNumber(numeric, 4);
|
||||||
|
}
|
||||||
|
|
||||||
this.emailRegEx = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/;
|
this.emailRegEx = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/;
|
||||||
|
|
||||||
this.debug = false;
|
this.debug = false;
|
||||||
|
|
|
@ -3,29 +3,29 @@
|
||||||
unittests.register("SHA* test with test vectors from NIST FIPS 180-2", function() {
|
unittests.register("SHA* test with test vectors from NIST FIPS 180-2", function() {
|
||||||
var openpgp = require('openpgp'),
|
var openpgp = require('openpgp'),
|
||||||
util = openpgp.util,
|
util = openpgp.util,
|
||||||
sha = openpgp.hash.sha;
|
hash = openpgp.hash;
|
||||||
|
|
||||||
var result = new Array();
|
var result = new Array();
|
||||||
|
|
||||||
result[0] = new test_result("SHA1 - a9993e364706816aba3e25717850c26c9cd0d89d = sha.sha1(\"abc\") ",
|
result[0] = new test_result("SHA1 - a9993e364706816aba3e25717850c26c9cd0d89d = hash.sha1(\"abc\") ",
|
||||||
"a9993e364706816aba3e25717850c26c9cd0d89d" == util.hexstrdump(sha.sha1("abc")));
|
"a9993e364706816aba3e25717850c26c9cd0d89d" == util.hexstrdump(hash.sha1("abc")));
|
||||||
result[1] = new test_result("SHA1 - 84983e441c3bd26ebaae4aa1f95129e5e54670f1 = sha.sha1(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ",
|
result[1] = new test_result("SHA1 - 84983e441c3bd26ebaae4aa1f95129e5e54670f1 = hash.sha1(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ",
|
||||||
"84983e441c3bd26ebaae4aa1f95129e5e54670f1" == util.hexstrdump(sha.sha1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")));
|
"84983e441c3bd26ebaae4aa1f95129e5e54670f1" == util.hexstrdump(hash.sha1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")));
|
||||||
result[2] = new test_result("SHA224 - 23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 = sha.sha224(\"abc\") ",
|
result[2] = new test_result("SHA224 - 23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 = hash.sha224(\"abc\") ",
|
||||||
"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7" == util.hexstrdump(sha.sha224("abc")));
|
"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7" == util.hexstrdump(hash.sha224("abc")));
|
||||||
result[3] = new test_result("SHA224 - 75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525 = sha.sha224(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ",
|
result[3] = new test_result("SHA224 - 75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525 = hash.sha224(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ",
|
||||||
"75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525" == util.hexstrdump(sha.sha224("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")));
|
"75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525" == util.hexstrdump(hash.sha224("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")));
|
||||||
result[4] = new test_result("SHA256 - ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad = sha.sha256(\"abc\") ",
|
result[4] = new test_result("SHA256 - ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad = hash.sha256(\"abc\") ",
|
||||||
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" == util.hexstrdump(sha.sha256("abc")));
|
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" == util.hexstrdump(hash.sha256("abc")));
|
||||||
result[5] = new test_result("SHA256 - 248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1 = sha.sha256(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ",
|
result[5] = new test_result("SHA256 - 248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1 = hash.sha256(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ",
|
||||||
"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" == util.hexstrdump(sha.sha256("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")));
|
"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" == util.hexstrdump(hash.sha256("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")));
|
||||||
result[6] = new test_result("SHA384 - cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7 = sha.sha384(\"abc\") ",
|
result[6] = new test_result("SHA384 - cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7 = hash.sha384(\"abc\") ",
|
||||||
"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7" == util.hexstrdump(sha.sha384("abc")));
|
"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7" == util.hexstrdump(hash.sha384("abc")));
|
||||||
result[7] = new test_result("SHA384 - 3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b = str384(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ",
|
result[7] = new test_result("SHA384 - 3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b = str384(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ",
|
||||||
"3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b" == util.hexstrdump(sha.sha384("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")));
|
"3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b" == util.hexstrdump(hash.sha384("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")));
|
||||||
result[8] = new test_result("SHA512 - ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f = sha.sha512(\"abc\") ",
|
result[8] = new test_result("SHA512 - ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f = hash.sha512(\"abc\") ",
|
||||||
"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f" == util.hexstrdump(sha.sha512("abc")));
|
"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f" == util.hexstrdump(hash.sha512("abc")));
|
||||||
result[9] = new test_result("SHA512 - 204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445 = sha.sha512(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ",
|
result[9] = new test_result("SHA512 - 204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445 = hash.sha512(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ",
|
||||||
"204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445" == util.hexstrdump(sha.sha512("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")));
|
"204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445" == util.hexstrdump(hash.sha512("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")));
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,7 +4,7 @@ var openpgp = require('openpgp')
|
||||||
unittests.register("AES Rijndael cipher test with test vectors from ecb_tbl.txt", function() {
|
unittests.register("AES Rijndael cipher test with test vectors from ecb_tbl.txt", function() {
|
||||||
var util = openpgp.util,
|
var util = openpgp.util,
|
||||||
keyExpansion = openpgp.cipher.aes.keyExpansion,
|
keyExpansion = openpgp.cipher.aes.keyExpansion,
|
||||||
AESencrypt = openpgp.cipher.aes.AESencrypt;
|
AESencrypt = openpgp.cipher.aes.encrypt;
|
||||||
|
|
||||||
var result = new Array();
|
var result = new Array();
|
||||||
function test_aes(input, key, output) {
|
function test_aes(input, key, output) {
|
||||||
|
|
|
@ -40,23 +40,23 @@ unittests.register("Packet testing", function() {
|
||||||
|
|
||||||
|
|
||||||
var tests = [function() {
|
var tests = [function() {
|
||||||
|
var message = new openpgp_packetlist();
|
||||||
|
|
||||||
var literal = new openpgp_packet_literal();
|
var literal = new openpgp.packet.literal();
|
||||||
literal.set_data('Hello world', openpgp_packet_literal.format.utf8);
|
literal.set('Hello world', 'utf8');
|
||||||
|
|
||||||
var enc = new openpgp_packet_symmetrically_encrypted();
|
var enc = new openpgp.packet.symmetrically_encrypted();
|
||||||
|
message.push(enc);
|
||||||
enc.packets.push(literal);
|
enc.packets.push(literal);
|
||||||
|
|
||||||
var key = '12345678901234567890123456789012',
|
var key = '12345678901234567890123456789012',
|
||||||
algo = openpgp.symmetric.aes256;
|
algo = 'aes256';
|
||||||
|
|
||||||
enc.encrypt(algo, key);
|
enc.encrypt(algo, key);
|
||||||
|
|
||||||
var message = new openpgp_packetlist();
|
|
||||||
message.push(enc);
|
|
||||||
|
|
||||||
|
|
||||||
var msg2 = new openpgp_packetlist();
|
var msg2 = new openpgp.packet.list();
|
||||||
msg2.read(message.write());
|
msg2.read(message.write());
|
||||||
|
|
||||||
msg2[0].decrypt(algo, key);
|
msg2[0].decrypt(algo, key);
|
||||||
|
@ -66,20 +66,20 @@ unittests.register("Packet testing", function() {
|
||||||
|
|
||||||
}, function() {
|
}, function() {
|
||||||
var key = '12345678901234567890123456789012',
|
var key = '12345678901234567890123456789012',
|
||||||
algo = openpgp.symmetric.aes256;
|
algo = 'aes256';
|
||||||
|
|
||||||
var literal = new openpgp_packet_literal(),
|
var literal = new openpgp.packet.literal(),
|
||||||
enc = new openpgp_packet_sym_encrypted_integrity_protected(),
|
enc = new openpgp.packet.sym_encrypted_integrity_protected(),
|
||||||
msg = new openpgp_packetlist();
|
msg = new openpgp.packet.list();
|
||||||
|
|
||||||
literal.set_data('Hello world!', openpgp_packet_literal.format.utf8);
|
msg.push(enc);
|
||||||
|
literal.set('Hello world!', 'utf8');
|
||||||
enc.packets.push(literal);
|
enc.packets.push(literal);
|
||||||
enc.encrypt(algo, key);
|
enc.encrypt(algo, key);
|
||||||
msg.push(enc);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var msg2 = new openpgp_packetlist();
|
var msg2 = new openpgp.packet.list();
|
||||||
msg2.read(msg.write());
|
msg2.read(msg.write());
|
||||||
|
|
||||||
msg2[0].decrypt(algo, key);
|
msg2[0].decrypt(algo, key);
|
||||||
|
@ -100,9 +100,9 @@ unittests.register("Packet testing", function() {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var msgbytes = openpgp_encoding_dearmor(msg).openpgp;
|
var msgbytes = openpgp.armor.decode(msg).openpgp;
|
||||||
|
|
||||||
var parsed = new openpgp_packetlist();
|
var parsed = new openpgp.packet.list();
|
||||||
parsed.read(msgbytes);
|
parsed.read(msgbytes);
|
||||||
|
|
||||||
parsed[0].decrypt('test');
|
parsed[0].decrypt('test');
|
||||||
|
@ -118,24 +118,24 @@ unittests.register("Packet testing", function() {
|
||||||
|
|
||||||
}, function() {
|
}, function() {
|
||||||
|
|
||||||
var rsa = new RSA(),
|
var rsa = new openpgp.publicKey.rsa(),
|
||||||
mpi = rsa.generate(512, "10001")
|
mpi = rsa.generate(512, "10001")
|
||||||
|
|
||||||
var mpi = [mpi.n, mpi.ee, mpi.d, mpi.p, mpi.q, mpi.u];
|
var mpi = [mpi.n, mpi.ee, mpi.d, mpi.p, mpi.q, mpi.u];
|
||||||
|
|
||||||
mpi = mpi.map(function(k) {
|
mpi = mpi.map(function(k) {
|
||||||
var mpi = new openpgp_type_mpi();
|
var mpi = new openpgp.mpi();
|
||||||
mpi.fromBigInteger(k);
|
mpi.fromBigInteger(k);
|
||||||
return mpi;
|
return mpi;
|
||||||
});
|
});
|
||||||
|
|
||||||
var enc = new openpgp_packet_public_key_encrypted_session_key(),
|
var enc = new openpgp.packet.public_key_encrypted_session_key(),
|
||||||
msg = new openpgp_packetlist(),
|
msg = new openpgp.packet.list(),
|
||||||
msg2 = new openpgp_packetlist();
|
msg2 = new openpgp.packet.list();
|
||||||
|
|
||||||
enc.symmetric_key = '12345678901234567890123456789012';
|
enc.symmetric_key = '12345678901234567890123456789012';
|
||||||
enc.public_key_algorithm = openpgp.publickey.rsa_encrypt;
|
enc.public_key_algorithm = 'rsa_encrypt';
|
||||||
enc.symmetric_algorithm = openpgp.symmetric.aes256;
|
enc.symmetric_algorithm = 'aes256';
|
||||||
enc.public_key_id.bytes = '12345678';
|
enc.public_key_id.bytes = '12345678';
|
||||||
enc.encrypt({ mpi: mpi });
|
enc.encrypt({ mpi: mpi });
|
||||||
|
|
||||||
|
@ -171,11 +171,11 @@ unittests.register("Packet testing", function() {
|
||||||
'=lKiS\n' +
|
'=lKiS\n' +
|
||||||
'-----END PGP PRIVATE KEY BLOCK-----';
|
'-----END PGP PRIVATE KEY BLOCK-----';
|
||||||
|
|
||||||
key = new openpgp_packetlist();
|
key = new openpgp.packet.list();
|
||||||
key.read(openpgp_encoding_dearmor(armored_key).openpgp);
|
key.read(openpgp.armor.decoce(armored_key).openpgp);
|
||||||
key = key[0];
|
key = key[0];
|
||||||
|
|
||||||
var enc = new openpgp_packet_public_key_encrypted_session_key(),
|
var enc = new openpgp.packet.public_key_encrypted_session_key(),
|
||||||
secret = '12345678901234567890123456789012';
|
secret = '12345678901234567890123456789012';
|
||||||
|
|
||||||
enc.symmetric_key = secret;
|
enc.symmetric_key = secret;
|
||||||
|
@ -239,12 +239,12 @@ unittests.register("Packet testing", function() {
|
||||||
'-----END PGP MESSAGE-----';
|
'-----END PGP MESSAGE-----';
|
||||||
|
|
||||||
|
|
||||||
var key = new openpgp_packetlist();
|
var key = new openpgp.packet.list();
|
||||||
key.read(openpgp_encoding_dearmor(armored_key).openpgp);
|
key.read(openpgp.armor.decode(armored_key).openpgp);
|
||||||
key = key[3];
|
key = key[3];
|
||||||
|
|
||||||
var msg = new openpgp_packetlist();
|
var msg = new openpgp.packet.list();
|
||||||
msg.read(openpgp_encoding_dearmor(armored_msg).openpgp);
|
msg.read(openpgp.armor.decode(armored_msg).openpgp);
|
||||||
|
|
||||||
msg[0].decrypt(key);
|
msg[0].decrypt(key);
|
||||||
msg[1].decrypt(msg[0].symmetric_algorithm, msg[0].symmetric_key);
|
msg[1].decrypt(msg[0].symmetric_algorithm, msg[0].symmetric_key);
|
||||||
|
@ -257,26 +257,27 @@ unittests.register("Packet testing", function() {
|
||||||
}, function() {
|
}, function() {
|
||||||
|
|
||||||
var passphrase = 'hello',
|
var passphrase = 'hello',
|
||||||
algo = openpgp.symmetric.aes256;
|
algo = 'aes256';
|
||||||
|
|
||||||
var literal = new openpgp_packet_literal(),
|
var literal = new openpgp.packet.literal(),
|
||||||
key_enc = new openpgp_packet_sym_encrypted_session_key(),
|
key_enc = new openpgp.packet.sym_encrypted_session_key(),
|
||||||
enc = new openpgp_packet_sym_encrypted_integrity_protected(),
|
enc = new openpgp.packet.sym_encrypted_integrity_protected(),
|
||||||
msg = new openpgp_packetlist();
|
msg = new openpgp.packet.list();
|
||||||
|
|
||||||
|
|
||||||
key_enc.algorithm = algo;
|
|
||||||
key_enc.decrypt(passphrase);
|
|
||||||
var key = key_enc.key;
|
|
||||||
|
|
||||||
literal.set_data('Hello world!', openpgp_packet_literal.format.utf8);
|
|
||||||
enc.packets.push(literal);
|
|
||||||
enc.encrypt(algo, key);
|
|
||||||
|
|
||||||
msg.push(key_enc);
|
msg.push(key_enc);
|
||||||
msg.push(enc);
|
msg.push(enc);
|
||||||
|
|
||||||
var msg2 = new openpgp_packetlist();
|
key_enc.algorithm = algo;
|
||||||
|
key_enc.decrypt(passphrase);
|
||||||
|
|
||||||
|
var key = key_enc.key;
|
||||||
|
|
||||||
|
literal.set_data('Hello world!', 'utf8');
|
||||||
|
enc.packets.push(literal);
|
||||||
|
enc.encrypt(algo, key);
|
||||||
|
|
||||||
|
|
||||||
|
var msg2 = new openpgp.packet.list();
|
||||||
msg2.read(msg.write());
|
msg2.read(msg.write());
|
||||||
|
|
||||||
msg2[0].decrypt(passphrase);
|
msg2[0].decrypt(passphrase);
|
||||||
|
@ -300,13 +301,13 @@ unittests.register("Packet testing", function() {
|
||||||
'=pR+C\n' +
|
'=pR+C\n' +
|
||||||
'-----END PGP MESSAGE-----';
|
'-----END PGP MESSAGE-----';
|
||||||
|
|
||||||
var key = new openpgp_packetlist();
|
var key = new openpgp.packet.list();
|
||||||
key.read(openpgp_encoding_dearmor(armored_key).openpgp);
|
key.read(openpgp.armor.decoce(armored_key).openpgp);
|
||||||
key = key[3];
|
key = key[3];
|
||||||
key.decrypt('test');
|
key.decrypt('test');
|
||||||
|
|
||||||
var msg = new openpgp_packetlist();
|
var msg = new openpgp.packet.list();
|
||||||
msg.read(openpgp_encoding_dearmor(armored_msg).openpgp);
|
msg.read(openpgp.armor.decode(armored_msg).openpgp);
|
||||||
|
|
||||||
msg[0].decrypt(key);
|
msg[0].decrypt(key);
|
||||||
msg[1].decrypt(msg[0].symmetric_algorithm, msg[0].symmetric_key);
|
msg[1].decrypt(msg[0].symmetric_algorithm, msg[0].symmetric_key);
|
||||||
|
@ -320,8 +321,8 @@ unittests.register("Packet testing", function() {
|
||||||
}, function() {
|
}, function() {
|
||||||
|
|
||||||
|
|
||||||
var key = new openpgp_packetlist();
|
var key = new openpgp.packet.list();
|
||||||
key.read(openpgp_encoding_dearmor(armored_key).openpgp);
|
key.read(openpgp.armor.decode(armored_key).openpgp);
|
||||||
|
|
||||||
|
|
||||||
var verified = key[2].verify(key[0],
|
var verified = key[2].verify(key[0],
|
||||||
|
@ -357,12 +358,12 @@ unittests.register("Packet testing", function() {
|
||||||
'=htrB\n' +
|
'=htrB\n' +
|
||||||
'-----END PGP MESSAGE-----'
|
'-----END PGP MESSAGE-----'
|
||||||
|
|
||||||
var key = new openpgp_packetlist();
|
var key = new openpgp.packet.list();
|
||||||
key.read(openpgp_encoding_dearmor(armored_key).openpgp);
|
key.read(openpgp.armor.decode(armored_key).openpgp);
|
||||||
key[3].decrypt('test')
|
key[3].decrypt('test')
|
||||||
|
|
||||||
var msg = new openpgp_packetlist();
|
var msg = new openpgp.packet.list();
|
||||||
msg.read(openpgp_encoding_dearmor(armored_msg).openpgp);
|
msg.read(openpgp.armor.decode(armored_msg).openpgp);
|
||||||
|
|
||||||
|
|
||||||
msg[0].decrypt(key[3]);
|
msg[0].decrypt(key[3]);
|
||||||
|
@ -382,17 +383,17 @@ unittests.register("Packet testing", function() {
|
||||||
return new test_result('Reading a signed, encrypted message.',
|
return new test_result('Reading a signed, encrypted message.',
|
||||||
verified == true);
|
verified == true);
|
||||||
}, function() {
|
}, function() {
|
||||||
var key = new openpgp_packetlist();
|
var key = new openpgp.packet.list();
|
||||||
key.push(new openpgp_packet_secret_key);
|
key.push(new openpgp.packet.secret_key);
|
||||||
|
|
||||||
var rsa = new RSA(),
|
var rsa = new openpgp.publicKey.rsa(),
|
||||||
mpi = rsa.generate(512, "10001")
|
mpi = rsa.generate(512, "10001")
|
||||||
|
|
||||||
|
|
||||||
var mpi = [mpi.n, mpi.ee, mpi.d, mpi.p, mpi.q, mpi.u];
|
var mpi = [mpi.n, mpi.ee, mpi.d, mpi.p, mpi.q, mpi.u];
|
||||||
|
|
||||||
mpi = mpi.map(function(k) {
|
mpi = mpi.map(function(k) {
|
||||||
var mpi = new openpgp_type_mpi();
|
var mpi = new openpgp.mpi();
|
||||||
mpi.fromBigInteger(k);
|
mpi.fromBigInteger(k);
|
||||||
return mpi;
|
return mpi;
|
||||||
});
|
});
|
||||||
|
@ -403,7 +404,7 @@ unittests.register("Packet testing", function() {
|
||||||
|
|
||||||
var raw = key.write();
|
var raw = key.write();
|
||||||
|
|
||||||
var key2 = new openpgp_packetlist();
|
var key2 = new openpgp.packet.list();
|
||||||
key2.read(raw);
|
key2.read(raw);
|
||||||
key2[0].decrypt('hello');
|
key2[0].decrypt('hello');
|
||||||
|
|
||||||
|
@ -411,30 +412,32 @@ unittests.register("Packet testing", function() {
|
||||||
return new test_result('Writing and encryptio of a secret key packet.',
|
return new test_result('Writing and encryptio of a secret key packet.',
|
||||||
key[0].mpi.toString() == key2[0].mpi.toString());
|
key[0].mpi.toString() == key2[0].mpi.toString());
|
||||||
}, function() {
|
}, function() {
|
||||||
var key = new openpgp_packet_secret_key;
|
var openpgp = require('openpgp');
|
||||||
|
|
||||||
var rsa = new RSA(),
|
var key = new openpgp.packet.secret_key();
|
||||||
|
|
||||||
|
var rsa = new openpgp.publicKey.rsa,
|
||||||
mpi = rsa.generate(512, "10001")
|
mpi = rsa.generate(512, "10001")
|
||||||
|
|
||||||
var mpi = [mpi.n, mpi.ee, mpi.d, mpi.p, mpi.q, mpi.u];
|
var mpi = [mpi.n, mpi.ee, mpi.d, mpi.p, mpi.q, mpi.u];
|
||||||
|
|
||||||
mpi = mpi.map(function(k) {
|
mpi = mpi.map(function(k) {
|
||||||
var mpi = new openpgp_type_mpi();
|
var mpi = new openpgp.mpi();
|
||||||
mpi.fromBigInteger(k);
|
mpi.fromBigInteger(k);
|
||||||
return mpi;
|
return mpi;
|
||||||
});
|
});
|
||||||
|
|
||||||
key.mpi = mpi;
|
key.mpi = mpi;
|
||||||
|
|
||||||
var signed = new openpgp_packetlist(),
|
var signed = new openpgp.packet.list(),
|
||||||
literal = new openpgp_packet_literal(),
|
literal = new openpgp.packet.literal(),
|
||||||
signature = new openpgp_packet_signature();
|
signature = new openpgp.packet.signature();
|
||||||
|
|
||||||
literal.set_data('Hello world', openpgp_packet_literal.format.utf8);
|
literal.set('Hello world', 'utf8');
|
||||||
|
|
||||||
signature.hashAlgorithm = openpgp.hash.sha256;
|
signature.hashAlgorithm = 'sha256';
|
||||||
signature.publicKeyAlgorithm = openpgp.publickey.rsa_sign;
|
signature.publicKeyAlgorithm = 'rsa_sign';
|
||||||
signature.signatureType = openpgp_packet_signature.type.binary;
|
signature.signatureType = 'binary';
|
||||||
|
|
||||||
signature.sign(key, { literal: literal });
|
signature.sign(key, { literal: literal });
|
||||||
|
|
||||||
|
@ -443,7 +446,7 @@ unittests.register("Packet testing", function() {
|
||||||
|
|
||||||
var raw = signed.write();
|
var raw = signed.write();
|
||||||
|
|
||||||
var signed2 = new openpgp_packetlist();
|
var signed2 = new openpgp.packet.list();
|
||||||
signed2.read(raw);
|
signed2.read(raw);
|
||||||
|
|
||||||
var verified = signed2[1].verify(key, { literal: signed2[0] });
|
var verified = signed2[1].verify(key, { literal: signed2[0] });
|
||||||
|
|
Loading…
Reference in New Issue
Block a user