diff --git a/doc/jsxcompressor.js.html b/doc/jsxcompressor.js.html new file mode 100644 index 00000000..c505c58f --- /dev/null +++ b/doc/jsxcompressor.js.html @@ -0,0 +1,1275 @@ + + + + + JSDoc: Source: compression/zlib/jsxcompressor.js + + + + + + + + + + +
+ +

Source: compression/zlib/jsxcompressor.js

+ + + + + +
+
+
JXG = {exists: (function(undefined){return function(v){return !(v===undefined || v===null);}})()};
+JXG.decompress = function(str) {return unescape((new JXG.Util.Unzip(JXG.Util.Base64.decodeAsArray(str))).unzip()[0][0]);};
+/*
+    Copyright 2008-2012
+        Matthias Ehmann,
+        Michael Gerhaeuser,
+        Carsten Miller,
+        Bianca Valentin,
+        Alfred Wassermann,
+        Peter Wilfahrt
+
+    This file is part of JSXGraph.
+    
+    Dual licensed under the Apache License Version 2.0, or LGPL Version 3 licenses.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with JSXCompressor.  If not, see <http://www.gnu.org/licenses/>.
+    
+    You should have received a copy of the Apache License along with JSXCompressor.  
+    If not, see <http://www.apache.org/licenses/>.
+
+*/
+
+/**
+  * @class Util class
+  * @classdesc Utilities for uncompressing and base64 decoding
+  * Class for gunzipping, unzipping and base64 decoding of files.
+  * It is used for reading GEONExT, Geogebra and Intergeo files.
+  *
+  * Only Huffman codes are decoded in gunzip.
+  * The code is based on the source code for gunzip.c by Pasi Ojala 
+  * {@link http://www.cs.tut.fi/~albert/Dev/gunzip/gunzip.c}
+  * {@link http://www.cs.tut.fi/~albert}
+  */
+JXG.Util = {};
+                                 
+/**
+ * Unzip zip files
+ */
+JXG.Util.Unzip = function (barray){
+    var outputArr = [],
+        output = "",
+        debug = false,
+        gpflags,
+        files = 0,
+        unzipped = [],
+        crc,
+        buf32k = new Array(32768),
+        bIdx = 0,
+        modeZIP=false,
+
+        CRC, SIZE,
+    
+        bitReverse = [
+        0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+        0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+        0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+        0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+        0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+        0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+        0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+        0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+        0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+        0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+        0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+        0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+        0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+        0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+        0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+        0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+        0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+        0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+        0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+        0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+        0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+        0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+        0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+        0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+        0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+        0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+        0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+        0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+        0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+        0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+        0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+        0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+    ],
+    
+    cplens = [
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
+    ],
+
+    cplext = [
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99
+    ], /* 99==invalid */
+
+    cpdist = [
+        0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0007, 0x0009, 0x000d,
+        0x0011, 0x0019, 0x0021, 0x0031, 0x0041, 0x0061, 0x0081, 0x00c1,
+        0x0101, 0x0181, 0x0201, 0x0301, 0x0401, 0x0601, 0x0801, 0x0c01,
+        0x1001, 0x1801, 0x2001, 0x3001, 0x4001, 0x6001
+    ],
+
+    cpdext = [
+        0,  0,  0,  0,  1,  1,  2,  2,
+        3,  3,  4,  4,  5,  5,  6,  6,
+        7,  7,  8,  8,  9,  9, 10, 10,
+        11, 11, 12, 12, 13, 13
+    ],
+    
+    border = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15],
+    
+    bA = barray,
+
+    bytepos=0,
+    bitpos=0,
+    bb = 1,
+    bits=0,
+    
+    NAMEMAX = 256,
+    
+    nameBuf = [],
+    
+    fileout;
+    
+    function readByte(){
+        bits+=8;
+        if (bytepos<bA.length){
+            //if (debug)
+            //    document.write(bytepos+": "+bA[bytepos]+"<br>");
+            return bA[bytepos++];
+        } else
+            return -1;
+    };
+
+    function byteAlign(){
+        bb = 1;
+    };
+    
+    function readBit(){
+        var carry;
+        bits++;
+        carry = (bb & 1);
+        bb >>= 1;
+        if (bb==0){
+            bb = readByte();
+            carry = (bb & 1);
+            bb = (bb>>1) | 0x80;
+        }
+        return carry;
+    };
+
+    function readBits(a) {
+        var res = 0,
+            i = a;
+    
+        while(i--) {
+            res = (res<<1) | readBit();
+        }
+        if(a) {
+            res = bitReverse[res]>>(8-a);
+        }
+        return res;
+    };
+        
+    function flushBuffer(){
+        //document.write('FLUSHBUFFER:'+buf32k);
+        bIdx = 0;
+    };
+    function addBuffer(a){
+        SIZE++;
+        //CRC=updcrc(a,crc);
+        buf32k[bIdx++] = a;
+        outputArr.push(String.fromCharCode(a));
+        //output+=String.fromCharCode(a);
+        if(bIdx==0x8000){
+            //document.write('ADDBUFFER:'+buf32k);
+            bIdx=0;
+        }
+    };
+    
+    function HufNode() {
+        this.b0=0;
+        this.b1=0;
+        this.jump = null;
+        this.jumppos = -1;
+    };
+
+    var LITERALS = 288;
+    
+    var literalTree = new Array(LITERALS);
+    var distanceTree = new Array(32);
+    var treepos=0;
+    var Places = null;
+    var Places2 = null;
+    
+    var impDistanceTree = new Array(64);
+    var impLengthTree = new Array(64);
+    
+    var len = 0;
+    var fpos = new Array(17);
+    fpos[0]=0;
+    var flens;
+    var fmax;
+    
+    function IsPat() {
+        while (1) {
+            if (fpos[len] >= fmax)
+                return -1;
+            if (flens[fpos[len]] == len)
+                return fpos[len]++;
+            fpos[len]++;
+        }
+    };
+
+    function Rec() {
+        var curplace = Places[treepos];
+        var tmp;
+        if (debug)
+    		document.write("<br>len:"+len+" treepos:"+treepos);
+        if(len==17) { //war 17
+            return -1;
+        }
+        treepos++;
+        len++;
+    	
+        tmp = IsPat();
+        if (debug)
+        	document.write("<br>IsPat "+tmp);
+        if(tmp >= 0) {
+            curplace.b0 = tmp;    /* leaf cell for 0-bit */
+            if (debug)
+            	document.write("<br>b0 "+curplace.b0);
+        } else {
+        /* Not a Leaf cell */
+        curplace.b0 = 0x8000;
+        if (debug)
+        	document.write("<br>b0 "+curplace.b0);
+        if(Rec())
+            return -1;
+        }
+        tmp = IsPat();
+        if(tmp >= 0) {
+            curplace.b1 = tmp;    /* leaf cell for 1-bit */
+            if (debug)
+            	document.write("<br>b1 "+curplace.b1);
+            curplace.jump = null;    /* Just for the display routine */
+        } else {
+            /* Not a Leaf cell */
+            curplace.b1 = 0x8000;
+            if (debug)
+            	document.write("<br>b1 "+curplace.b1);
+            curplace.jump = Places[treepos];
+            curplace.jumppos = treepos;
+            if(Rec())
+                return -1;
+        }
+        len--;
+        return 0;
+    };
+
+    function CreateTree(currentTree, numval, lengths, show) {
+        var i;
+        /* Create the Huffman decode tree/table */
+        //document.write("<br>createtree<br>");
+        if (debug)
+        	document.write("currentTree "+currentTree+" numval "+numval+" lengths "+lengths+" show "+show);
+        Places = currentTree;
+        treepos=0;
+        flens = lengths;
+        fmax  = numval;
+        for (i=0;i<17;i++)
+            fpos[i] = 0;
+        len = 0;
+        if(Rec()) {
+            //fprintf(stderr, "invalid huffman tree\n");
+            if (debug)
+            	alert("invalid huffman tree\n");
+            return -1;
+        }
+        if (debug){
+        	document.write('<br>Tree: '+Places.length);
+        	for (var a=0;a<32;a++){
+            	document.write("Places["+a+"].b0="+Places[a].b0+"<br>");
+            	document.write("Places["+a+"].b1="+Places[a].b1+"<br>");
+        	}
+        }
+    
+        /*if(show) {
+            var tmp;
+            for(tmp=currentTree;tmp<Places;tmp++) {
+                fprintf(stdout, "0x%03x  0x%03x (0x%04x)",tmp-currentTree, tmp->jump?tmp->jump-currentTree:0,(tmp->jump?tmp->jump-currentTree:0)*6+0xcf0);
+                if(!(tmp.b0 & 0x8000)) {
+                    //fprintf(stdout, "  0x%03x (%c)", tmp->b0,(tmp->b0<256 && isprint(tmp->b0))?tmp->b0:'�');
+                }
+                if(!(tmp.b1 & 0x8000)) {
+                    if((tmp.b0 & 0x8000))
+                        fprintf(stdout, "           ");
+                    fprintf(stdout, "  0x%03x (%c)", tmp->b1,(tmp->b1<256 && isprint(tmp->b1))?tmp->b1:'�');
+                }
+                fprintf(stdout, "\n");
+            }
+        }*/
+        return 0;
+    };
+    
+    function DecodeValue(currentTree) {
+        var len, i,
+            xtreepos=0,
+            X = currentTree[xtreepos],
+            b;
+
+        /* decode one symbol of the data */
+        while(1) {
+            b=readBit();
+            if (debug)
+            	document.write("b="+b);
+            if(b) {
+                if(!(X.b1 & 0x8000)){
+                	if (debug)
+                    	document.write("ret1");
+                    return X.b1;    /* If leaf node, return data */
+                }
+                X = X.jump;
+                len = currentTree.length;
+                for (i=0;i<len;i++){
+                    if (currentTree[i]===X){
+                        xtreepos=i;
+                        break;
+                    }
+                }
+                //xtreepos++;
+            } else {
+                if(!(X.b0 & 0x8000)){
+                	if (debug)
+                    	document.write("ret2");
+                    return X.b0;    /* If leaf node, return data */
+                }
+                //X++; //??????????????????
+                xtreepos++;
+                X = currentTree[xtreepos];
+            }
+        }
+        if (debug)
+        	document.write("ret3");
+        return -1;
+    };
+    
+    function DeflateLoop() {
+    var last, c, type, i, len;
+
+    do {
+        /*if((last = readBit())){
+            fprintf(errfp, "Last Block: ");
+        } else {
+            fprintf(errfp, "Not Last Block: ");
+        }*/
+        last = readBit();
+        type = readBits(2);
+        switch(type) {
+            case 0:
+            	if (debug)
+                	alert("Stored\n");
+                break;
+            case 1:
+            	if (debug)
+                	alert("Fixed Huffman codes\n");
+                break;
+            case 2:
+            	if (debug)
+                	alert("Dynamic Huffman codes\n");
+                break;
+            case 3:
+            	if (debug)
+                	alert("Reserved block type!!\n");
+                break;
+            default:
+            	if (debug)
+                	alert("Unexpected value %d!\n", type);
+                break;
+        }
+
+        if(type==0) {
+            var blockLen, cSum;
+
+            // Stored 
+            byteAlign();
+            blockLen = readByte();
+            blockLen |= (readByte()<<8);
+
+            cSum = readByte();
+            cSum |= (readByte()<<8);
+
+            if(((blockLen ^ ~cSum) & 0xffff)) {
+                document.write("BlockLen checksum mismatch\n");
+            }
+            while(blockLen--) {
+                c = readByte();
+                addBuffer(c);
+            }
+        } else if(type==1) {
+            var j;
+
+            /* Fixed Huffman tables -- fixed decode routine */
+            while(1) {
+            /*
+                256    0000000        0
+                :   :     :
+                279    0010111        23
+                0   00110000    48
+                :    :      :
+                143    10111111    191
+                280 11000000    192
+                :    :      :
+                287 11000111    199
+                144    110010000    400
+                :    :       :
+                255    111111111    511
+    
+                Note the bit order!
+                */
+
+            j = (bitReverse[readBits(7)]>>1);
+            if(j > 23) {
+                j = (j<<1) | readBit();    /* 48..255 */
+
+                if(j > 199) {    /* 200..255 */
+                    j -= 128;    /*  72..127 */
+                    j = (j<<1) | readBit();        /* 144..255 << */
+                } else {        /*  48..199 */
+                    j -= 48;    /*   0..151 */
+                    if(j > 143) {
+                        j = j+136;    /* 280..287 << */
+                        /*   0..143 << */
+                    }
+                }
+            } else {    /*   0..23 */
+                j += 256;    /* 256..279 << */
+            }
+            if(j < 256) {
+                addBuffer(j);
+                //document.write("out:"+String.fromCharCode(j));
+                /*fprintf(errfp, "@%d %02x\n", SIZE, j);*/
+            } else if(j == 256) {
+                /* EOF */
+                break;
+            } else {
+                var len, dist;
+
+                j -= 256 + 1;    /* bytes + EOF */
+                len = readBits(cplext[j]) + cplens[j];
+
+                j = bitReverse[readBits(5)]>>3;
+                if(cpdext[j] > 8) {
+                    dist = readBits(8);
+                    dist |= (readBits(cpdext[j]-8)<<8);
+                } else {
+                    dist = readBits(cpdext[j]);
+                }
+                dist += cpdist[j];
+
+                /*fprintf(errfp, "@%d (l%02x,d%04x)\n", SIZE, len, dist);*/
+                for(j=0;j<len;j++) {
+                    var c = buf32k[(bIdx - dist) & 0x7fff];
+                    addBuffer(c);
+                }
+            }
+            } // while
+        } else if(type==2) {
+            var j, n, literalCodes, distCodes, lenCodes;
+            var ll = new Array(288+32);    // "static" just to preserve stack
+    
+            // Dynamic Huffman tables 
+    
+            literalCodes = 257 + readBits(5);
+            distCodes = 1 + readBits(5);
+            lenCodes = 4 + readBits(4);
+            //document.write("<br>param: "+literalCodes+" "+distCodes+" "+lenCodes+"<br>");
+            for(j=0; j<19; j++) {
+                ll[j] = 0;
+            }
+    
+            // Get the decode tree code lengths
+    
+            //document.write("<br>");
+            for(j=0; j<lenCodes; j++) {
+                ll[border[j]] = readBits(3);
+                //document.write(ll[border[j]]+" ");
+            }
+            //fprintf(errfp, "\n");
+            //document.write('<br>ll:'+ll);
+            len = distanceTree.length;
+            for (i=0; i<len; i++)
+                distanceTree[i]=new HufNode();
+            if(CreateTree(distanceTree, 19, ll, 0)) {
+                flushBuffer();
+                return 1;
+            }
+            if (debug){
+            	document.write("<br>distanceTree");
+            	for(var a=0;a<distanceTree.length;a++){
+                	document.write("<br>"+distanceTree[a].b0+" "+distanceTree[a].b1+" "+distanceTree[a].jump+" "+distanceTree[a].jumppos);
+                	/*if (distanceTree[a].jumppos!=-1)
+                    	document.write(" "+distanceTree[a].jump.b0+" "+distanceTree[a].jump.b1);
+                	*/
+            	}
+            }
+            //document.write('<BR>tree created');
+    
+            //read in literal and distance code lengths
+            n = literalCodes + distCodes;
+            i = 0;
+            var z=-1;
+            if (debug)
+            	document.write("<br>n="+n+" bits: "+bits+"<br>");
+            while(i < n) {
+                z++;
+                j = DecodeValue(distanceTree);
+                if (debug)
+                	document.write("<br>"+z+" i:"+i+" decode: "+j+"    bits "+bits+"<br>");
+                if(j<16) {    // length of code in bits (0..15)
+                       ll[i++] = j;
+                } else if(j==16) {    // repeat last length 3 to 6 times 
+                       var l;
+                    j = 3 + readBits(2);
+                    if(i+j > n) {
+                        flushBuffer();
+                        return 1;
+                    }
+                    l = i ? ll[i-1] : 0;
+                    while(j--) {
+                        ll[i++] = l;
+                    }
+                } else {
+                    if(j==17) {        // 3 to 10 zero length codes
+                        j = 3 + readBits(3);
+                    } else {        // j == 18: 11 to 138 zero length codes 
+                        j = 11 + readBits(7);
+                    }
+                    if(i+j > n) {
+                        flushBuffer();
+                        return 1;
+                    }
+                    while(j--) {
+                        ll[i++] = 0;
+                    }
+                }
+            }
+            /*for(j=0; j<literalCodes+distCodes; j++) {
+                //fprintf(errfp, "%d ", ll[j]);
+                if ((j&7)==7)
+                    fprintf(errfp, "\n");
+            }
+            fprintf(errfp, "\n");*/
+            // Can overwrite tree decode tree as it is not used anymore
+            len = literalTree.length;
+            for (i=0; i<len; i++)
+                literalTree[i]=new HufNode();
+            if(CreateTree(literalTree, literalCodes, ll, 0)) {
+                flushBuffer();
+                return 1;
+            }
+            len = literalTree.length;
+            for (i=0; i<len; i++)
+                distanceTree[i]=new HufNode();
+            var ll2 = new Array();
+            for (i=literalCodes; i <ll.length; i++){
+                ll2[i-literalCodes]=ll[i];
+            }    
+            if(CreateTree(distanceTree, distCodes, ll2, 0)) {
+                flushBuffer();
+                return 1;
+            }
+            if (debug)
+           		document.write("<br>literalTree");
+            outer:
+            while(1) {
+                j = DecodeValue(literalTree);
+                if(j >= 256) {        // In C64: if carry set
+                    var len, dist;
+                    j -= 256;
+                    if(j == 0) {
+                        // EOF
+                        break;
+                    }
+                    j--;
+                    len = readBits(cplext[j]) + cplens[j];
+    
+                    j = DecodeValue(distanceTree);
+                    if(cpdext[j] > 8) {
+                        dist = readBits(8);
+                        dist |= (readBits(cpdext[j]-8)<<8);
+                    } else {
+                        dist = readBits(cpdext[j]);
+                    }
+                    dist += cpdist[j];
+                    while(len--) {
+                        if(bIdx - dist < 0) {
+                            break outer;
+                        }
+                        var c = buf32k[(bIdx - dist) & 0x7fff];
+                        addBuffer(c);
+                    }
+                } else {
+                    addBuffer(j);
+                }
+            }
+        }
+    } while(!last);
+    flushBuffer();
+
+    byteAlign();
+    return 0;
+};
+
+JXG.Util.Unzip.prototype.unzipFile = function(name) {
+    var i;
+	this.unzip();
+	//alert(unzipped[0][1]);
+	for (i=0;i<unzipped.length;i++){
+		if(unzipped[i][1]==name) {
+			return unzipped[i][0];
+		}
+	}
+	
+  };
+
+JXG.Util.Unzip.prototype.deflate = function() {
+    outputArr = [];
+    var tmp = [];
+    modeZIP = false;
+    DeflateLoop();
+    if (debug)
+        alert(outputArr.join(''));
+    unzipped[files] = new Array(2);
+    unzipped[files][0] = outputArr.join('');
+    unzipped[files][1] = "DEFLATE";
+    files++;
+    return unzipped;
+}    
+    
+JXG.Util.Unzip.prototype.unzip = function() {
+	//convertToByteArray(input);
+	if (debug)
+		alert(bA);
+	/*for (i=0;i<bA.length*8;i++){
+		document.write(readBit());
+		if ((i+1)%8==0)
+			document.write(" ");
+	}*/
+	/*for (i=0;i<bA.length;i++){
+		document.write(readByte()+" ");
+		if ((i+1)%8==0)
+			document.write(" ");
+	}
+	for (i=0;i<bA.length;i++){
+		document.write(bA[i]+" ");
+		if ((i+1)%16==0)
+			document.write("<br>");
+	}	
+	*/
+	//alert(bA);
+	nextFile();
+	return unzipped;
+  };
+    
+ function nextFile(){
+ 	if (debug)
+ 		alert("NEXTFILE");
+ 	outputArr = [];
+ 	var tmp = [];
+ 	modeZIP = false;
+	tmp[0] = readByte();
+	tmp[1] = readByte();
+	if (debug)
+		alert("type: "+tmp[0]+" "+tmp[1]);
+	if (tmp[0] == parseInt("78",16) && tmp[1] == parseInt("da",16)){ //GZIP
+		if (debug)
+			alert("GEONExT-GZIP");
+		DeflateLoop();
+		if (debug)
+			alert(outputArr.join(''));
+		unzipped[files] = new Array(2);
+    	unzipped[files][0] = outputArr.join('');
+    	unzipped[files][1] = "geonext.gxt";
+    	files++;
+	}
+	if (tmp[0] == parseInt("78",16) && tmp[1] == parseInt("9c",16)){ //ZLIB
+		if (debug)
+			alert("ZLIB");
+		DeflateLoop();
+		if (debug)
+			alert(outputArr.join(''));
+		unzipped[files] = new Array(2);
+    	unzipped[files][0] = outputArr.join('');
+    	unzipped[files][1] = "ZLIB";
+    	files++;
+	}
+	if (tmp[0] == parseInt("1f",16) && tmp[1] == parseInt("8b",16)){ //GZIP
+		if (debug)
+			alert("GZIP");
+		//DeflateLoop();
+		skipdir();
+		if (debug)
+			alert(outputArr.join(''));
+		unzipped[files] = new Array(2);
+    	unzipped[files][0] = outputArr.join('');
+    	unzipped[files][1] = "file";
+    	files++;
+	}
+	if (tmp[0] == parseInt("50",16) && tmp[1] == parseInt("4b",16)){ //ZIP
+		modeZIP = true;
+		tmp[2] = readByte();
+		tmp[3] = readByte();
+		if (tmp[2] == parseInt("3",16) && tmp[3] == parseInt("4",16)){
+			//MODE_ZIP
+			tmp[0] = readByte();
+			tmp[1] = readByte();
+			if (debug)
+				alert("ZIP-Version: "+tmp[1]+" "+tmp[0]/10+"."+tmp[0]%10);
+			
+			gpflags = readByte();
+			gpflags |= (readByte()<<8);
+			if (debug)
+				alert("gpflags: "+gpflags);
+			
+			var method = readByte();
+			method |= (readByte()<<8);
+			if (debug)
+				alert("method: "+method);
+			
+			readByte();
+			readByte();
+			readByte();
+			readByte();
+			
+			var crc = readByte();
+			crc |= (readByte()<<8);
+			crc |= (readByte()<<16);
+			crc |= (readByte()<<24);
+			
+			var compSize = readByte();
+			compSize |= (readByte()<<8);
+			compSize |= (readByte()<<16);
+			compSize |= (readByte()<<24);
+			
+			var size = readByte();
+			size |= (readByte()<<8);
+			size |= (readByte()<<16);
+			size |= (readByte()<<24);
+			
+			if (debug)
+				alert("local CRC: "+crc+"\nlocal Size: "+size+"\nlocal CompSize: "+compSize);
+			
+			var filelen = readByte();
+			filelen |= (readByte()<<8);
+			
+			var extralen = readByte();
+			extralen |= (readByte()<<8);
+			
+			if (debug)
+				alert("filelen "+filelen);
+			i = 0;
+			nameBuf = [];
+			while (filelen--){ 
+				var c = readByte();
+				if (c == "/" | c ==":"){
+					i = 0;
+				} else if (i < NAMEMAX-1)
+					nameBuf[i++] = String.fromCharCode(c);
+			}
+			if (debug)
+				alert("nameBuf: "+nameBuf);
+			
+			//nameBuf[i] = "\0";
+			if (!fileout)
+				fileout = nameBuf;
+			
+			var i = 0;
+			while (i < extralen){
+				c = readByte();
+				i++;
+			}
+				
+			CRC = 0xffffffff;
+			SIZE = 0;
+			
+			if (size = 0 && fileOut.charAt(fileout.length-1)=="/"){
+				//skipdir
+				if (debug)
+					alert("skipdir");
+			}
+			if (method == 8){
+				DeflateLoop();
+				if (debug)
+					alert(outputArr.join(''));
+				unzipped[files] = new Array(2);
+				unzipped[files][0] = outputArr.join('');
+    			unzipped[files][1] = nameBuf.join('');
+    			files++;
+				//return outputArr.join('');
+			}
+			skipdir();
+		}
+	}
+ };
+	
+function skipdir(){
+    var crc, 
+        tmp = [],
+        compSize, size, os, i, c;
+    
+	if ((gpflags & 8)) {
+		tmp[0] = readByte();
+		tmp[1] = readByte();
+		tmp[2] = readByte();
+		tmp[3] = readByte();
+		
+		if (tmp[0] == parseInt("50",16) && 
+            tmp[1] == parseInt("4b",16) && 
+            tmp[2] == parseInt("07",16) && 
+            tmp[3] == parseInt("08",16))
+        {
+            crc = readByte();
+            crc |= (readByte()<<8);
+            crc |= (readByte()<<16);
+            crc |= (readByte()<<24);
+		} else {
+			crc = tmp[0] | (tmp[1]<<8) | (tmp[2]<<16) | (tmp[3]<<24);
+		}
+		
+		compSize = readByte();
+		compSize |= (readByte()<<8);
+		compSize |= (readByte()<<16);
+		compSize |= (readByte()<<24);
+		
+		size = readByte();
+		size |= (readByte()<<8);
+		size |= (readByte()<<16);
+		size |= (readByte()<<24);
+		
+		if (debug)
+			alert("CRC:");
+	}
+
+	if (modeZIP)
+		nextFile();
+	
+	tmp[0] = readByte();
+	if (tmp[0] != 8) {
+		if (debug)
+			alert("Unknown compression method!");
+        return 0;	
+	}
+	
+	gpflags = readByte();
+	if (debug){
+		if ((gpflags & ~(parseInt("1f",16))))
+			alert("Unknown flags set!");
+	}
+	
+	readByte();
+	readByte();
+	readByte();
+	readByte();
+	
+	readByte();
+	os = readByte();
+	
+	if ((gpflags & 4)){
+		tmp[0] = readByte();
+		tmp[2] = readByte();
+		len = tmp[0] + 256*tmp[1];
+		if (debug)
+			alert("Extra field size: "+len);
+		for (i=0;i<len;i++)
+			readByte();
+	}
+	
+	if ((gpflags & 8)){
+		i=0;
+		nameBuf=[];
+		while (c=readByte()){
+			if(c == "7" || c == ":")
+				i=0;
+			if (i<NAMEMAX-1)
+				nameBuf[i++] = c;
+		}
+		//nameBuf[i] = "\0";
+		if (debug)
+			alert("original file name: "+nameBuf);
+	}
+		
+	if ((gpflags & 16)){
+		while (c=readByte()){
+			//FILE COMMENT
+		}
+	}
+	
+	if ((gpflags & 2)){
+		readByte();
+		readByte();
+	}
+	
+	DeflateLoop();
+	
+	crc = readByte();
+	crc |= (readByte()<<8);
+	crc |= (readByte()<<16);
+	crc |= (readByte()<<24);
+	
+	size = readByte();
+	size |= (readByte()<<8);
+	size |= (readByte()<<16);
+	size |= (readByte()<<24);
+	
+	if (modeZIP)
+		nextFile();
+	
+};
+
+};
+
+/**
+*  Base64 encoding / decoding
+*  {@link http://www.webtoolkit.info/}
+*/
+JXG.Util.Base64 = {
+
+    // private property
+    _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
+
+    // public method for encoding
+    encode : function (input) {
+        var output = [],
+            chr1, chr2, chr3, enc1, enc2, enc3, enc4,
+            i = 0;
+
+        input = JXG.Util.Base64._utf8_encode(input);
+
+        while (i < input.length) {
+
+            chr1 = input.charCodeAt(i++);
+            chr2 = input.charCodeAt(i++);
+            chr3 = input.charCodeAt(i++);
+
+            enc1 = chr1 >> 2;
+            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
+            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
+            enc4 = chr3 & 63;
+
+            if (isNaN(chr2)) {
+                enc3 = enc4 = 64;
+            } else if (isNaN(chr3)) {
+                enc4 = 64;
+            }
+
+            output.push([this._keyStr.charAt(enc1),
+                         this._keyStr.charAt(enc2),
+                         this._keyStr.charAt(enc3),
+                         this._keyStr.charAt(enc4)].join(''));
+        }
+
+        return output.join('');
+    },
+
+    // public method for decoding
+    decode : function (input, utf8) {
+        var output = [],
+            chr1, chr2, chr3,
+            enc1, enc2, enc3, enc4,
+            i = 0;
+
+        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
+
+        while (i < input.length) {
+
+            enc1 = this._keyStr.indexOf(input.charAt(i++));
+            enc2 = this._keyStr.indexOf(input.charAt(i++));
+            enc3 = this._keyStr.indexOf(input.charAt(i++));
+            enc4 = this._keyStr.indexOf(input.charAt(i++));
+
+            chr1 = (enc1 << 2) | (enc2 >> 4);
+            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
+            chr3 = ((enc3 & 3) << 6) | enc4;
+
+            output.push(String.fromCharCode(chr1));
+
+            if (enc3 != 64) {
+                output.push(String.fromCharCode(chr2));
+            }
+            if (enc4 != 64) {
+                output.push(String.fromCharCode(chr3));
+            }
+        }
+        
+        output = output.join(''); 
+        
+        if (utf8) {
+            output = JXG.Util.Base64._utf8_decode(output);
+        }
+        return output;
+
+    },
+
+    // private method for UTF-8 encoding
+    _utf8_encode : function (string) {
+        string = string.replace(/\r\n/g,"\n");
+        var utftext = "";
+
+        for (var n = 0; n < string.length; n++) {
+
+            var c = string.charCodeAt(n);
+
+            if (c < 128) {
+                utftext += String.fromCharCode(c);
+            }
+            else if((c > 127) && (c < 2048)) {
+                utftext += String.fromCharCode((c >> 6) | 192);
+                utftext += String.fromCharCode((c & 63) | 128);
+            }
+            else {
+                utftext += String.fromCharCode((c >> 12) | 224);
+                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
+                utftext += String.fromCharCode((c & 63) | 128);
+            }
+
+        }
+
+        return utftext;
+    },
+
+    // private method for UTF-8 decoding
+    _utf8_decode : function (utftext) {
+        var string = [],
+            i = 0,
+            c = 0, c2 = 0, c3 = 0;
+
+        while ( i < utftext.length ) {
+            c = utftext.charCodeAt(i);
+            if (c < 128) {
+                string.push(String.fromCharCode(c));
+                i++;
+            }
+            else if((c > 191) && (c < 224)) {
+                c2 = utftext.charCodeAt(i+1);
+                string.push(String.fromCharCode(((c & 31) << 6) | (c2 & 63)));
+                i += 2;
+            }
+            else {
+                c2 = utftext.charCodeAt(i+1);
+                c3 = utftext.charCodeAt(i+2);
+                string.push(String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)));
+                i += 3;
+            }
+        }
+        return string.join('');
+    },
+    
+    _destrip: function (stripped, wrap){
+        var lines = [], lineno, i,
+            destripped = [];
+        
+        if (wrap==null) 
+            wrap = 76;
+            
+        stripped.replace(/ /g, "");
+        lineno = stripped.length / wrap;
+        for (i = 0; i < lineno; i++)
+            lines[i]=stripped.substr(i * wrap, wrap);
+        if (lineno != stripped.length / wrap)
+            lines[lines.length]=stripped.substr(lineno * wrap, stripped.length-(lineno * wrap));
+            
+        for (i = 0; i < lines.length; i++)
+            destripped.push(lines[i]);
+        return destripped.join('\n');
+    },
+    
+    decodeAsArray: function (input){
+        var dec = this.decode(input),
+            ar = [], i;
+        for (i=0;i<dec.length;i++){
+            ar[i]=dec.charCodeAt(i);
+        }
+        return ar;
+    },
+    
+    decodeGEONExT : function (input) {
+        return decodeAsArray(destrip(input),false);
+    }
+};
+
+/**
+ * @private
+ */
+JXG.Util.asciiCharCodeAt = function(str,i){
+	var c = str.charCodeAt(i);
+	if (c>255){
+    	switch (c) {
+			case 8364: c=128;
+	    	break;
+	    	case 8218: c=130;
+	    	break;
+	    	case 402: c=131;
+	    	break;
+	    	case 8222: c=132;
+	    	break;
+	    	case 8230: c=133;
+	    	break;
+	    	case 8224: c=134;
+	    	break;
+	    	case 8225: c=135;
+	    	break;
+	    	case 710: c=136;
+	    	break;
+	    	case 8240: c=137;
+	    	break;
+	    	case 352: c=138;
+	    	break;
+	    	case 8249: c=139;
+	    	break;
+	    	case 338: c=140;
+	    	break;
+	    	case 381: c=142;
+	    	break;
+	    	case 8216: c=145;
+	    	break;
+	    	case 8217: c=146;
+	    	break;
+	    	case 8220: c=147;
+	    	break;
+	    	case 8221: c=148;
+	    	break;
+	    	case 8226: c=149;
+	    	break;
+	    	case 8211: c=150;
+	    	break;
+	    	case 8212: c=151;
+	    	break;
+	    	case 732: c=152;
+	    	break;
+	    	case 8482: c=153;
+	    	break;
+	    	case 353: c=154;
+	    	break;
+	    	case 8250: c=155;
+	    	break;
+	    	case 339: c=156;
+	    	break;
+	    	case 382: c=158;
+	    	break;
+	    	case 376: c=159;
+	    	break;
+	    	default:
+	    	break;
+	    }
+	}
+	return c;
+};
+
+/**
+ * Decoding string into utf-8
+ * @param {String} string to decode
+ * @return {String} utf8 decoded string
+ */
+JXG.Util.utf8Decode = function(utftext) {
+  var string = [];
+  var i = 0;
+  var c = 0, c1 = 0, c2 = 0, c3;
+  if (!JXG.exists(utftext)) return '';
+  
+  while ( i < utftext.length ) {
+    c = utftext.charCodeAt(i);
+
+    if (c < 128) {
+      string.push(String.fromCharCode(c));
+      i++;
+    } else if((c > 191) && (c < 224)) {
+      c2 = utftext.charCodeAt(i+1);
+      string.push(String.fromCharCode(((c & 31) << 6) | (c2 & 63)));
+      i += 2;
+    } else {
+      c2 = utftext.charCodeAt(i+1);
+      c3 = utftext.charCodeAt(i+2);
+      string.push(String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)));
+      i += 3;
+    }
+  };
+  return string.join('');
+};
+
+/**
+ * Generate a random uuid.
+ * http://www.broofa.com
+ * mailto:robert@broofa.com
+ *
+ * Copyright (c) 2010 Robert Kieffer
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ * EXAMPLES:
+ *   >>> Math.uuid()
+ *   "92329D39-6F5C-4520-ABFC-AAB64544E172"
+ */
+JXG.Util.genUUID = function() {
+    // Private array of chars to use
+    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''),
+        uuid = new Array(36), rnd=0, r;
+
+    for (var i = 0; i < 36; i++) {
+      if (i==8 || i==13 ||  i==18 || i==23) {
+        uuid[i] = '-';
+      } else if (i==14) {
+        uuid[i] = '4';
+      } else {
+        if (rnd <= 0x02) rnd = 0x2000000 + (Math.random()*0x1000000)|0;
+        r = rnd & 0xf;
+        rnd = rnd >> 4;
+        uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
+      }
+    }
+
+    return uuid.join('');
+};
+
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/md5.js.html b/doc/md5.js.html new file mode 100644 index 00000000..92594e93 --- /dev/null +++ b/doc/md5.js.html @@ -0,0 +1,253 @@ + + + + + JSDoc: Source: ciphers/hash/md5.js + + + + + + + + + + +
+ +

Source: ciphers/hash/md5.js

+ + + + + +
+
+
/**
+ * A fast MD5 JavaScript implementation
+ * Copyright (c) 2012 Joseph Myers
+ * http://www.myersdaily.org/joseph/javascript/md5-text.html
+ *
+ * Permission to use, copy, modify, and distribute this software
+ * and its documentation for any purposes and without
+ * fee is hereby granted provided that this copyright notice
+ * appears in all copies.
+ *
+ * Of course, this soft is provided "as is" without express or implied
+ * warranty of any kind.
+ */
+
+function MD5(entree) {
+	var hex = md5(entree);
+	var bin = util.hex2bin(hex);
+	return bin;
+}
+
+function md5cycle(x, k) {
+var a = x[0], b = x[1], c = x[2], d = x[3];
+
+a = ff(a, b, c, d, k[0], 7, -680876936);
+d = ff(d, a, b, c, k[1], 12, -389564586);
+c = ff(c, d, a, b, k[2], 17,  606105819);
+b = ff(b, c, d, a, k[3], 22, -1044525330);
+a = ff(a, b, c, d, k[4], 7, -176418897);
+d = ff(d, a, b, c, k[5], 12,  1200080426);
+c = ff(c, d, a, b, k[6], 17, -1473231341);
+b = ff(b, c, d, a, k[7], 22, -45705983);
+a = ff(a, b, c, d, k[8], 7,  1770035416);
+d = ff(d, a, b, c, k[9], 12, -1958414417);
+c = ff(c, d, a, b, k[10], 17, -42063);
+b = ff(b, c, d, a, k[11], 22, -1990404162);
+a = ff(a, b, c, d, k[12], 7,  1804603682);
+d = ff(d, a, b, c, k[13], 12, -40341101);
+c = ff(c, d, a, b, k[14], 17, -1502002290);
+b = ff(b, c, d, a, k[15], 22,  1236535329);
+
+a = gg(a, b, c, d, k[1], 5, -165796510);
+d = gg(d, a, b, c, k[6], 9, -1069501632);
+c = gg(c, d, a, b, k[11], 14,  643717713);
+b = gg(b, c, d, a, k[0], 20, -373897302);
+a = gg(a, b, c, d, k[5], 5, -701558691);
+d = gg(d, a, b, c, k[10], 9,  38016083);
+c = gg(c, d, a, b, k[15], 14, -660478335);
+b = gg(b, c, d, a, k[4], 20, -405537848);
+a = gg(a, b, c, d, k[9], 5,  568446438);
+d = gg(d, a, b, c, k[14], 9, -1019803690);
+c = gg(c, d, a, b, k[3], 14, -187363961);
+b = gg(b, c, d, a, k[8], 20,  1163531501);
+a = gg(a, b, c, d, k[13], 5, -1444681467);
+d = gg(d, a, b, c, k[2], 9, -51403784);
+c = gg(c, d, a, b, k[7], 14,  1735328473);
+b = gg(b, c, d, a, k[12], 20, -1926607734);
+
+a = hh(a, b, c, d, k[5], 4, -378558);
+d = hh(d, a, b, c, k[8], 11, -2022574463);
+c = hh(c, d, a, b, k[11], 16,  1839030562);
+b = hh(b, c, d, a, k[14], 23, -35309556);
+a = hh(a, b, c, d, k[1], 4, -1530992060);
+d = hh(d, a, b, c, k[4], 11,  1272893353);
+c = hh(c, d, a, b, k[7], 16, -155497632);
+b = hh(b, c, d, a, k[10], 23, -1094730640);
+a = hh(a, b, c, d, k[13], 4,  681279174);
+d = hh(d, a, b, c, k[0], 11, -358537222);
+c = hh(c, d, a, b, k[3], 16, -722521979);
+b = hh(b, c, d, a, k[6], 23,  76029189);
+a = hh(a, b, c, d, k[9], 4, -640364487);
+d = hh(d, a, b, c, k[12], 11, -421815835);
+c = hh(c, d, a, b, k[15], 16,  530742520);
+b = hh(b, c, d, a, k[2], 23, -995338651);
+
+a = ii(a, b, c, d, k[0], 6, -198630844);
+d = ii(d, a, b, c, k[7], 10,  1126891415);
+c = ii(c, d, a, b, k[14], 15, -1416354905);
+b = ii(b, c, d, a, k[5], 21, -57434055);
+a = ii(a, b, c, d, k[12], 6,  1700485571);
+d = ii(d, a, b, c, k[3], 10, -1894986606);
+c = ii(c, d, a, b, k[10], 15, -1051523);
+b = ii(b, c, d, a, k[1], 21, -2054922799);
+a = ii(a, b, c, d, k[8], 6,  1873313359);
+d = ii(d, a, b, c, k[15], 10, -30611744);
+c = ii(c, d, a, b, k[6], 15, -1560198380);
+b = ii(b, c, d, a, k[13], 21,  1309151649);
+a = ii(a, b, c, d, k[4], 6, -145523070);
+d = ii(d, a, b, c, k[11], 10, -1120210379);
+c = ii(c, d, a, b, k[2], 15,  718787259);
+b = ii(b, c, d, a, k[9], 21, -343485551);
+
+x[0] = add32(a, x[0]);
+x[1] = add32(b, x[1]);
+x[2] = add32(c, x[2]);
+x[3] = add32(d, x[3]);
+
+}
+
+function cmn(q, a, b, x, s, t) {
+a = add32(add32(a, q), add32(x, t));
+return add32((a << s) | (a >>> (32 - s)), b);
+}
+
+function ff(a, b, c, d, x, s, t) {
+return cmn((b & c) | ((~b) & d), a, b, x, s, t);
+}
+
+function gg(a, b, c, d, x, s, t) {
+return cmn((b & d) | (c & (~d)), a, b, x, s, t);
+}
+
+function hh(a, b, c, d, x, s, t) {
+return cmn(b ^ c ^ d, a, b, x, s, t);
+}
+
+function ii(a, b, c, d, x, s, t) {
+return cmn(c ^ (b | (~d)), a, b, x, s, t);
+}
+
+function md51(s) {
+txt = '';
+var n = s.length,
+state = [1732584193, -271733879, -1732584194, 271733878], i;
+for (i=64; i<=s.length; i+=64) {
+md5cycle(state, md5blk(s.substring(i-64, i)));
+}
+s = s.substring(i-64);
+var tail = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
+for (i=0; i<s.length; i++)
+tail[i>>2] |= s.charCodeAt(i) << ((i%4) << 3);
+tail[i>>2] |= 0x80 << ((i%4) << 3);
+if (i > 55) {
+md5cycle(state, tail);
+for (i=0; i<16; i++) tail[i] = 0;
+}
+tail[14] = n*8;
+md5cycle(state, tail);
+return state;
+}
+
+/* there needs to be support for Unicode here,
+ * unless we pretend that we can redefine the MD-5
+ * algorithm for multi-byte characters (perhaps
+ * by adding every four 16-bit characters and
+ * shortening the sum to 32 bits). Otherwise
+ * I suggest performing MD-5 as if every character
+ * was two bytes--e.g., 0040 0025 = @%--but then
+ * how will an ordinary MD-5 sum be matched?
+ * There is no way to standardize text to something
+ * like UTF-8 before transformation; speed cost is
+ * utterly prohibitive. The JavaScript standard
+ * itself needs to look at this: it should start
+ * providing access to strings as preformed UTF-8
+ * 8-bit unsigned value arrays.
+ */
+function md5blk(s) { /* I figured global was faster.   */
+var md5blks = [], i; /* Andy King said do it this way. */
+for (i=0; i<64; i+=4) {
+md5blks[i>>2] = s.charCodeAt(i)
++ (s.charCodeAt(i+1) << 8)
++ (s.charCodeAt(i+2) << 16)
++ (s.charCodeAt(i+3) << 24);
+}
+return md5blks;
+}
+
+var hex_chr = '0123456789abcdef'.split('');
+
+function rhex(n)
+{
+var s='', j=0;
+for(; j<4; j++)
+s += hex_chr[(n >> (j * 8 + 4)) & 0x0F]
++ hex_chr[(n >> (j * 8)) & 0x0F];
+return s;
+}
+
+function hex(x) {
+for (var i=0; i<x.length; i++)
+x[i] = rhex(x[i]);
+return x.join('');
+}
+
+function md5(s) {
+return hex(md51(s));
+}
+
+/* this function is much faster,
+so if possible we use it. Some IEs
+are the only ones I know of that
+need the idiotic second function,
+generated by an if clause.  */
+
+function add32(a, b) {
+return (a + b) & 0xFFFFFFFF;
+}
+
+if (md5('hello') != '5d41402abc4b2a76b9719d911017c592') {
+function add32(x, y) {
+var lsw = (x & 0xFFFF) + (y & 0xFFFF),
+msw = (x >> 16) + (y >> 16) + (lsw >> 16);
+return (msw << 16) | (lsw & 0xFFFF);
+}
+}
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.config.js.html b/doc/openpgp.config.js.html new file mode 100644 index 00000000..8c29fc92 --- /dev/null +++ b/doc/openpgp.config.js.html @@ -0,0 +1,139 @@ + + + + + JSDoc: Source: config/openpgp.config.js + + + + + + + + + + +
+ +

Source: config/openpgp.config.js

+ + + + + +
+
+
// 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
+
+/**
+ *
+ * This object contains configuration values and implements
+ * storing and retrieving configuration them from HTML5 local storage.
+ *
+ * This object can be accessed after calling openpgp.init()
+ * using openpgp.config
+ * Stored config parameters can be accessed using
+ * openpgp.config.config
+ * @class
+ * @classdesc Implementation of the GPG4Browsers config object
+ */
+function openpgp_config() {
+	/**
+	 * The variable with the actual configuration
+	 * @property {Integer} prefer_hash_algorithm
+	 * @property {Integer} encryption_cipher
+	 * @property {Integer} compression
+	 * @property {Boolean} show_version
+	 * @property {Boolean} show_comment
+	 * @property {Boolean} integrity_protect
+	 * @property {Integer} composition_behavior
+	 * @property {String} keyserver
+	 */
+	this.config = null;
+
+	/**
+	 * The default config object which is used if no
+	 * configuration was in place
+	 */
+	this.default_config = {
+			prefer_hash_algorithm: 2,
+			encryption_cipher: 9,
+			compression: 1,
+			show_version: true,
+			show_comment: true,
+			integrity_protect: true,
+			composition_behavior: 0,
+			keyserver: "keyserver.linux.it" // "pgp.mit.edu:11371"
+	};
+
+	this.versionstring ="OpenPGP.js VERSION";
+	this.commentstring ="http://openpgpjs.org";
+	/**
+	 * Reads the config out of the HTML5 local storage
+	 * and initializes the object config.
+	 * if config is null the default config will be used
+	 */
+	function read() {
+		var cf = JSON.parse(window.localStorage.getItem("config"));
+		if (cf == null) {
+			this.config = this.default_config;
+			this.write();
+		}
+		else
+			this.config = cf;
+	}
+
+	/**
+	 * If enabled, debug messages will be printed
+	 */
+	this.debug = false;
+
+	/**
+	 * Writes the config to HTML5 local storage
+	 */
+	function write() {
+		window.localStorage.setItem("config",JSON.stringify(this.config));
+	}
+
+	this.read = read;
+	this.write = write;
+}
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.crypto.sym.js.html b/doc/openpgp.crypto.sym.js.html new file mode 100644 index 00000000..8f3018b4 --- /dev/null +++ b/doc/openpgp.crypto.sym.js.html @@ -0,0 +1,143 @@ + + + + + JSDoc: Source: ciphers/openpgp.crypto.sym.js + + + + + + + + + + +
+ +

Source: ciphers/openpgp.crypto.sym.js

+ + + + + +
+
+
// 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 symmetric crypto interface
+
+/**
+ * Symmetrically encrypts data using prefixedrandom, a key with length 
+ * depending on the algorithm in openpgp_cfb mode with or without resync
+ * (MDC style)
+ * @param {String} prefixrandom Secure random bytes as string in 
+ * length equal to the block size of the algorithm used (use 
+ * openpgp_crypto_getPrefixRandom(algo) to retrieve that string
+ * @param {Integer} algo Algorithm to use (see RFC4880 9.2)
+ * @param {String} key Key as string. length is depending on the algorithm used
+ * @param {String} data Data to encrypt
+ * @param {Boolean} openpgp_cfb
+ * @return {String} Encrypted data
+ */
+function openpgp_crypto_symmetricEncrypt(prefixrandom, algo, key, data, openpgp_cfb) {
+	switch(algo) {
+		case 0: // Plaintext or unencrypted data
+			return data; // blockcipherencryptfn, plaintext, block_size, key
+		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);
+		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);
+		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);
+		case 7: // AES with 128-bit key [AES]
+		case 8: // AES with 192-bit key
+		case 9: // AES with 256-bit key
+			return openpgp_cfb_encrypt(prefixrandom, AESencrypt, data, 16, keyExpansion(key), openpgp_cfb).substring(0, data.length + 18);
+		case 10: // Twofish with 256-bit key [TWOFISH]
+			return openpgp_cfb_encrypt(prefixrandom, TFencrypt, data,16, key, openpgp_cfb).substring(0, data.length + 18);
+		case 1: // IDEA [IDEA]
+			util.print_error("IDEA Algorithm not implemented");
+			return null;
+		default:
+			return null;
+	}
+}
+
+/**
+ * Symmetrically decrypts data using a key with length depending on the
+ * algorithm in openpgp_cfb mode with or without resync (MDC style)
+ * @param {Integer} algo Algorithm to use (see RFC4880 9.2)
+ * @param {String} key Key as string. length is depending on the algorithm used
+ * @param {String} data Data to be decrypted
+ * @param {Boolean} openpgp_cfb If true use the resync (for encrypteddata); 
+ * otherwise use without the resync (for MDC encrypted data)
+ * @return {String} Plaintext data
+ */
+function openpgp_crypto_symmetricDecrypt(algo, key, data, openpgp_cfb) {
+	util.print_debug_hexstr_dump("openpgp_crypto_symmetricDecrypt:\nalgo:"+algo+"\nencrypteddata:",data);
+	var n = 0;
+	if (!openpgp_cfb)
+		n = 2;
+	switch(algo) {
+	case 0: // Plaintext or unencrypted data
+		return data;
+	case 2: // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
+		return openpgp_cfb_decrypt(desede, 8, key, data, openpgp_cfb).substring(n, (data.length+n)-10);
+	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);
+	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);
+	case 7: // AES with 128-bit key [AES]
+	case 8: // AES with 192-bit key
+	case 9: // AES with 256-bit key
+		return openpgp_cfb_decrypt(AESencrypt, 16, keyExpansion(key), data, openpgp_cfb).substring(n, (data.length+n)-18);
+	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);
+		return result;
+	case 1: // IDEA [IDEA]
+		util.print_error(""+ (algo == 1 ? "IDEA Algorithm not implemented" : "Twofish Algorithm not implemented"));
+		return null;
+	default:
+	}
+	return null;
+}
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.encoding.asciiarmor.js.html b/doc/openpgp.encoding.asciiarmor.js.html new file mode 100644 index 00000000..126f6b54 --- /dev/null +++ b/doc/openpgp.encoding.asciiarmor.js.html @@ -0,0 +1,295 @@ + + + + + JSDoc: Source: encoding/openpgp.encoding.asciiarmor.js + + + + + + + + + + +
+ +

Source: encoding/openpgp.encoding.asciiarmor.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * DeArmor an OpenPGP armored message; verify the checksum and return 
+ * the encoded bytes
+ * @param {String} text OpenPGP armored message
+ * @returns {(String|Object)} Either the bytes of the decoded message 
+ * or an object with attribute "text" containing the message text
+ * and an attribute "openpgp" containing the bytes.
+ */
+function openpgp_encoding_deArmor(text) {
+	var type = getPGPMessageType(text);
+	if (type != 2) {
+	var splittedtext = text.split('-----');
+	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))+"'";
+	} 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");
+	}
+}
+
+/**
+ * Finds out which Ascii Armoring type is used. This is an internal function
+ * @param {String} text [String] ascii armored text
+ * @returns {Integer} 0 = MESSAGE PART n of m
+ *         1 = MESSAGE PART n
+ *         2 = SIGNED MESSAGE
+ *         3 = PGP MESSAGE
+ *         4 = PUBLIC KEY BLOCK
+ *         5 = PRIVATE KEY BLOCK
+ *         null = unknown
+ */
+function getPGPMessageType(text) {
+	var splittedtext = text.split('-----');
+	// BEGIN PGP MESSAGE, PART X/Y
+	// Used for multi-part messages, where the armor is split amongst Y
+	// parts, and this is the Xth part out of Y.
+	if (splittedtext[1].match(/BEGIN PGP MESSAGE, PART \d+\/\d+/)) {
+		return 0;
+	} else
+		// BEGIN PGP MESSAGE, PART X
+		// Used for multi-part messages, where this is the Xth part of an
+		// unspecified number of parts. Requires the MESSAGE-ID Armor
+		// Header to be used.
+	if (splittedtext[1].match(/BEGIN PGP MESSAGE, PART \d+/)) {
+		return 1;
+
+	} else
+		// BEGIN PGP SIGNATURE
+		// Used for detached signatures, OpenPGP/MIME signatures, and
+		// cleartext signatures. Note that PGP 2.x uses BEGIN PGP MESSAGE
+		// for detached signatures.
+	if (splittedtext[1].match(/BEGIN PGP SIGNED MESSAGE/)) {
+		return 2;
+
+	} else
+  	    // BEGIN PGP MESSAGE
+	    // Used for signed, encrypted, or compressed files.
+	if (splittedtext[1].match(/BEGIN PGP MESSAGE/)) {
+		return 3;
+
+	} else
+		// BEGIN PGP PUBLIC KEY BLOCK
+		// Used for armoring public keys.
+	if (splittedtext[1].match(/BEGIN PGP PUBLIC KEY BLOCK/)) {
+		return 4;
+
+	} else
+		// BEGIN PGP PRIVATE KEY BLOCK
+		// Used for armoring private keys.
+	if (splittedtext[1].match(/BEGIN PGP PRIVATE KEY BLOCK/)) {
+		return 5;
+	}
+}
+
+/**
+ * Add additional information to the armor version of an OpenPGP binary
+ * packet block.
+ * @author  Alex
+ * @version 2011-12-16
+ * @returns {String} The header information
+ */
+function openpgp_encoding_armor_addheader() {
+    var result = "";
+	if (openpgp.config.config.show_version) {
+        result += "Version: "+openpgp.config.versionstring+'\r\n';
+    }
+	if (openpgp.config.config.show_comment) {
+        result += "Comment: "+openpgp.config.commentstring+'\r\n';
+    }
+    result += '\r\n';
+    return result;
+}
+
+/**
+ * Armor an OpenPGP binary packet block
+ * @param {Integer} messagetype type of the message
+ * @param data
+ * @param {Integer} partindex
+ * @param {Integer} parttotal
+ * @returns {String} Armored text
+ */
+function openpgp_encoding_armor(messagetype, data, partindex, parttotal) {
+	var result = "";
+	switch(messagetype) {
+	case 0:
+		result += "-----BEGIN PGP MESSAGE, PART "+partindex+"/"+parttotal+"-----\r\n";
+		result += openpgp_encoding_armor_addheader();
+		result += openpgp_encoding_base64_encode(data);
+		result += "\r\n="+getCheckSum(data)+"\r\n";
+		result += "-----END PGP MESSAGE, PART "+partindex+"/"+parttotal+"-----\r\n";
+		break;
+	case 1:
+		result += "-----BEGIN PGP MESSAGE, PART "+partindex+"-----\r\n";
+		result += openpgp_encoding_armor_addheader();
+		result += openpgp_encoding_base64_encode(data);
+		result += "\r\n="+getCheckSum(data)+"\r\n";
+		result += "-----END PGP MESSAGE, PART "+partindex+"-----\r\n";
+		break;
+	case 2:
+		result += "\r\n-----BEGIN PGP SIGNED MESSAGE-----\r\nHash: "+data.hash+"\r\n\r\n";
+		result += data.text.replace(/\n-/g,"\n- -");
+		result += "\r\n-----BEGIN PGP SIGNATURE-----\r\n";
+		result += openpgp_encoding_armor_addheader();
+		result += openpgp_encoding_base64_encode(data.openpgp);
+		result += "\r\n="+getCheckSum(data.openpgp)+"\r\n";
+		result += "-----END PGP SIGNATURE-----\r\n";
+		break;
+	case 3:
+		result += "-----BEGIN PGP MESSAGE-----\r\n";
+		result += openpgp_encoding_armor_addheader();
+		result += openpgp_encoding_base64_encode(data);
+		result += "\r\n="+getCheckSum(data)+"\r\n";
+		result += "-----END PGP MESSAGE-----\r\n";
+		break;
+	case 4:
+		result += "-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n";
+		result += openpgp_encoding_armor_addheader();
+		result += openpgp_encoding_base64_encode(data);
+		result += "\r\n="+getCheckSum(data)+"\r\n";
+		result += "-----END PGP PUBLIC KEY BLOCK-----\r\n\r\n";
+		break;
+	case 5:
+		result += "-----BEGIN PGP PRIVATE KEY BLOCK-----\r\n";
+		result += openpgp_encoding_armor_addheader();
+		result += openpgp_encoding_base64_encode(data);
+		result += "\r\n="+getCheckSum(data)+"\r\n";
+		result += "-----END PGP PRIVATE KEY BLOCK-----\r\n";
+		break;
+	}
+
+	return result;
+}
+
+/**
+ * Calculates a checksum over the given data and returns it base64 encoded
+ * @param {String} data Data to create a CRC-24 checksum for
+ * @return {String} Base64 encoded checksum
+ */
+function getCheckSum(data) {
+	var c = createcrc24(data);
+	var str = "" + String.fromCharCode(c >> 16)+
+				   String.fromCharCode((c >> 8) & 0xFF)+
+				   String.fromCharCode(c & 0xFF);
+	return openpgp_encoding_base64_encode(str);
+}
+
+/**
+ * Calculates the checksum over the given data and compares it with the 
+ * given base64 encoded checksum
+ * @param {String} data Data to create a CRC-24 checksum for
+ * @param {String} checksum Base64 encoded checksum
+ * @return {Boolean} True if the given checksum is correct; otherwise false
+ */
+function verifyCheckSum(data, checksum) {
+	var c = getCheckSum(data);
+	var d = checksum;
+	return c[0] == d[0] && c[1] == d[1] && c[2] == d[2];
+}
+/**
+ * Internal function to calculate a CRC-24 checksum over a given string (data)
+ * @param {String} data Data to create a CRC-24 checksum for
+ * @return {Integer} The CRC-24 checksum as number
+ */
+var crc_table = [
+0x00000000, 0x00864cfb, 0x018ad50d, 0x010c99f6, 0x0393e6e1, 0x0315aa1a, 0x021933ec, 0x029f7f17, 0x07a18139, 0x0727cdc2, 0x062b5434, 0x06ad18cf, 0x043267d8, 0x04b42b23, 0x05b8b2d5, 0x053efe2e, 0x0fc54e89, 0x0f430272, 0x0e4f9b84, 0x0ec9d77f, 0x0c56a868, 0x0cd0e493, 0x0ddc7d65, 0x0d5a319e, 0x0864cfb0, 0x08e2834b, 0x09ee1abd, 0x09685646, 0x0bf72951, 0x0b7165aa, 0x0a7dfc5c, 0x0afbb0a7, 0x1f0cd1e9, 0x1f8a9d12, 0x1e8604e4, 0x1e00481f, 0x1c9f3708, 0x1c197bf3, 0x1d15e205, 0x1d93aefe, 0x18ad50d0, 0x182b1c2b, 0x192785dd, 0x19a1c926, 0x1b3eb631, 0x1bb8faca, 0x1ab4633c, 0x1a322fc7, 0x10c99f60, 0x104fd39b, 0x11434a6d, 0x11c50696, 0x135a7981, 0x13dc357a, 0x12d0ac8c, 0x1256e077, 0x17681e59, 0x17ee52a2, 0x16e2cb54, 0x166487af, 0x14fbf8b8, 0x147db443, 0x15712db5, 0x15f7614e, 0x3e19a3d2, 0x3e9fef29, 0x3f9376df, 0x3f153a24, 0x3d8a4533, 0x3d0c09c8, 0x3c00903e, 0x3c86dcc5, 0x39b822eb, 0x393e6e10, 0x3832f7e6, 0x38b4bb1d, 0x3a2bc40a, 0x3aad88f1, 0x3ba11107, 0x3b275dfc, 0x31dced5b, 0x315aa1a0,
+0x30563856, 0x30d074ad, 0x324f0bba, 0x32c94741, 0x33c5deb7, 0x3343924c, 0x367d6c62, 0x36fb2099, 0x37f7b96f, 0x3771f594, 0x35ee8a83, 0x3568c678, 0x34645f8e, 0x34e21375, 0x2115723b, 0x21933ec0, 0x209fa736, 0x2019ebcd, 0x228694da, 0x2200d821, 0x230c41d7, 0x238a0d2c, 0x26b4f302, 0x2632bff9, 0x273e260f, 0x27b86af4, 0x252715e3, 0x25a15918, 0x24adc0ee, 0x242b8c15, 0x2ed03cb2, 0x2e567049, 0x2f5ae9bf, 0x2fdca544, 0x2d43da53, 0x2dc596a8, 0x2cc90f5e, 0x2c4f43a5, 0x2971bd8b, 0x29f7f170, 0x28fb6886, 0x287d247d, 0x2ae25b6a, 0x2a641791, 0x2b688e67, 0x2beec29c, 0x7c3347a4, 0x7cb50b5f, 0x7db992a9, 0x7d3fde52, 0x7fa0a145, 0x7f26edbe, 0x7e2a7448, 0x7eac38b3, 0x7b92c69d, 0x7b148a66, 0x7a181390, 0x7a9e5f6b, 0x7801207c, 0x78876c87, 0x798bf571, 0x790db98a, 0x73f6092d, 0x737045d6, 0x727cdc20, 0x72fa90db, 0x7065efcc, 0x70e3a337, 0x71ef3ac1, 0x7169763a, 0x74578814, 0x74d1c4ef, 0x75dd5d19, 0x755b11e2, 0x77c46ef5, 0x7742220e, 0x764ebbf8, 0x76c8f703, 0x633f964d, 0x63b9dab6, 0x62b54340, 0x62330fbb,
+0x60ac70ac, 0x602a3c57, 0x6126a5a1, 0x61a0e95a, 0x649e1774, 0x64185b8f, 0x6514c279, 0x65928e82, 0x670df195, 0x678bbd6e, 0x66872498, 0x66016863, 0x6cfad8c4, 0x6c7c943f, 0x6d700dc9, 0x6df64132, 0x6f693e25, 0x6fef72de, 0x6ee3eb28, 0x6e65a7d3, 0x6b5b59fd, 0x6bdd1506, 0x6ad18cf0, 0x6a57c00b, 0x68c8bf1c, 0x684ef3e7, 0x69426a11, 0x69c426ea, 0x422ae476, 0x42aca88d, 0x43a0317b, 0x43267d80, 0x41b90297, 0x413f4e6c, 0x4033d79a, 0x40b59b61, 0x458b654f, 0x450d29b4, 0x4401b042, 0x4487fcb9, 0x461883ae, 0x469ecf55, 0x479256a3, 0x47141a58, 0x4defaaff, 0x4d69e604, 0x4c657ff2, 0x4ce33309, 0x4e7c4c1e, 0x4efa00e5, 0x4ff69913, 0x4f70d5e8, 0x4a4e2bc6, 0x4ac8673d, 0x4bc4fecb, 0x4b42b230, 0x49ddcd27, 0x495b81dc, 0x4857182a, 0x48d154d1, 0x5d26359f, 0x5da07964, 0x5cace092, 0x5c2aac69, 0x5eb5d37e, 0x5e339f85, 0x5f3f0673, 0x5fb94a88, 0x5a87b4a6, 0x5a01f85d, 0x5b0d61ab, 0x5b8b2d50, 0x59145247, 0x59921ebc, 0x589e874a, 0x5818cbb1, 0x52e37b16, 0x526537ed, 0x5369ae1b, 0x53efe2e0, 0x51709df7, 0x51f6d10c,
+0x50fa48fa, 0x507c0401, 0x5542fa2f, 0x55c4b6d4, 0x54c82f22, 0x544e63d9, 0x56d11cce, 0x56575035, 0x575bc9c3, 0x57dd8538];
+
+function createcrc24(input) {
+  var crc = 0xB704CE;
+  var index = 0;
+
+  while((input.length - index) > 16)  {
+   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index)) & 0xff];
+   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+1)) & 0xff];
+   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+2)) & 0xff];
+   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+3)) & 0xff];
+   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+4)) & 0xff];
+   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+5)) & 0xff];
+   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+6)) & 0xff];
+   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+7)) & 0xff];
+   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+8)) & 0xff];
+   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+9)) & 0xff];
+   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+10)) & 0xff];
+   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+11)) & 0xff];
+   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+12)) & 0xff];
+   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+13)) & 0xff];
+   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+14)) & 0xff];
+   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index+15)) & 0xff];
+   index += 16;
+  }
+
+  for(var j = index; j < input.length; j++) {
+   crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index++)) & 0xff]
+  }
+  return crc & 0xffffff;
+}
+
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.encoding.js.html b/doc/openpgp.encoding.js.html new file mode 100644 index 00000000..a71a2c54 --- /dev/null +++ b/doc/openpgp.encoding.js.html @@ -0,0 +1,190 @@ + + + + + JSDoc: Source: encoding/openpgp.encoding.js + + + + + + + + + + +
+ +

Source: encoding/openpgp.encoding.js

+ + + + + +
+
+
// 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);
+}
+
+/**
+ * Wrapper function for jquery library.
+ * This function escapes HTML characters within a string. This is used 
+ * to prevent XSS.
+ * @param {String} message Message to escape
+ * @return {String} Html encoded string
+ */
+function openpgp_encoding_html_encode(message) {
+	if (message == null)
+		return "";
+	return $('<div/>').text(message).html();
+}
+
+/**
+ * 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);
+}
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.js.html b/doc/openpgp.js.html new file mode 100644 index 00000000..3e3183b2 --- /dev/null +++ b/doc/openpgp.js.html @@ -0,0 +1,509 @@ + + + + + JSDoc: Source: openpgp.js + + + + + + + + + + +
+ +

Source: openpgp.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * @fileoverview The openpgp base class should provide all of the functionality 
+ * to consume the openpgp.js library. All additional classes are documented 
+ * for extending and developing on top of the base library.
+ */
+
+/**
+ * GPG4Browsers Core interface. A single instance is hold
+ * from the beginning. To use this library call "openpgp.init()"
+ * @alias openpgp
+ * @class
+ * @classdesc Main Openpgp.js class. Use this to initiate and make all calls to this library.
+ */
+function _openpgp () {
+	this.tostring = "";
+	
+	/**
+	 * initializes the library:
+	 * - reading the keyring from local storage
+	 * - reading the config from local storage
+	 */
+	function init() {
+		this.config = new openpgp_config();
+		this.config.read();
+		this.keyring = new openpgp_keyring();
+		this.keyring.init();
+	}
+	
+	/**
+	 * reads several publicKey objects from a ascii armored
+	 * representation an returns openpgp_msg_publickey packets
+	 * @param {String} armoredText OpenPGP armored text containing
+	 * the public key(s)
+	 * @return {openpgp_msg_publickey[]} on error the function
+	 * returns null
+	 */
+	function read_publicKey(armoredText) {
+		var mypos = 0;
+		var publicKeys = new Array();
+		var publicKeyCount = 0;
+		var input = openpgp_encoding_deArmor(armoredText.replace(/\r/g,'')).openpgp;
+		var l = input.length;
+		while (mypos != input.length) {
+			var first_packet = openpgp_packet.read_packet(input, mypos, l);
+			// public key parser
+			if (input[mypos].charCodeAt() == 0x99 || first_packet.tagType == 6) {
+				publicKeys[publicKeyCount] = new openpgp_msg_publickey();				
+				publicKeys[publicKeyCount].header = input.substring(mypos,mypos+3);
+				if (input[mypos].charCodeAt() == 0x99) {
+					// parse the length and read a tag6 packet
+					mypos++;
+					var l = (input[mypos++].charCodeAt() << 8)
+							| input[mypos++].charCodeAt();
+					publicKeys[publicKeyCount].publicKeyPacket = new openpgp_packet_keymaterial();
+					publicKeys[publicKeyCount].publicKeyPacket.header = publicKeys[publicKeyCount].header;
+					publicKeys[publicKeyCount].publicKeyPacket.read_tag6(input, mypos, l);
+					mypos += publicKeys[publicKeyCount].publicKeyPacket.packetLength;
+					mypos += publicKeys[publicKeyCount].read_nodes(publicKeys[publicKeyCount].publicKeyPacket, input, mypos, (input.length - mypos));
+				} else {
+					publicKeys[publicKeyCount] = new openpgp_msg_publickey();
+					publicKeys[publicKeyCount].publicKeyPacket = first_packet;
+					mypos += first_packet.headerLength+first_packet.packetLength;
+					mypos += publicKeys[publicKeyCount].read_nodes(first_packet, input, mypos, input.length -mypos);
+				}
+			} else {
+				util.print_error("no public key found!");
+				return null;
+			}
+			publicKeys[publicKeyCount].data = input.substring(0,mypos);
+			publicKeyCount++;
+		}
+		return publicKeys;
+	}
+	
+	/**
+	 * reads several privateKey objects from a ascii armored
+	 * representation an returns openpgp_msg_privatekey objects
+	 * @param {String} armoredText OpenPGP armored text containing
+	 * the private key(s)
+	 * @return {openpgp_msg_privatekey[]} on error the function
+	 * returns null
+	 */
+	function read_privateKey(armoredText) {
+		var privateKeys = new Array();
+		var privateKeyCount = 0;
+		var mypos = 0;
+		var input = openpgp_encoding_deArmor(armoredText.replace(/\r/g,'')).openpgp;
+		var l = input.length;
+		while (mypos != input.length) {
+			var first_packet = openpgp_packet.read_packet(input, mypos, l);
+			if (first_packet.tagType == 5) {
+				privateKeys[privateKeys.length] = new openpgp_msg_privatekey();
+				mypos += first_packet.headerLength+first_packet.packetLength;
+				mypos += privateKeys[privateKeyCount].read_nodes(first_packet, input, mypos, l);
+			// other blocks	            
+			} else {
+				util.print_error('no block packet found!');
+				return null;
+			}
+			privateKeys[privateKeyCount].data = input.substring(0,mypos);
+			privateKeyCount++;
+		}
+		return privateKeys;		
+	}
+
+	/**
+	 * reads message packets out of an OpenPGP armored text and
+	 * returns an array of message objects
+	 * @param {String} armoredText text to be parsed
+	 * @return {openpgp_msg_message[]} on error the function
+	 * returns null
+	 */
+	function read_message(armoredText) {
+		var dearmored;
+		try{
+    		dearmored = openpgp_encoding_deArmor(armoredText.replace(/\r/g,''));
+		}
+		catch(e){
+    		util.print_error('no message found!');
+    		return null;
+		}
+		return read_messages_dearmored(dearmored);
+		}
+		
+	/**
+	 * reads message packets out of an OpenPGP armored text and
+	 * returns an array of message objects. Can be called externally or internally.
+	 * External call will parse a de-armored messaged and return messages found.
+	 * Internal will be called to read packets wrapped in other packets (i.e. compressed)
+	 * @param {String} input dearmored text of OpenPGP packets, to be parsed
+	 * @return {openpgp_msg_message[]} on error the function
+	 * returns null
+	 */
+	function read_messages_dearmored(input){
+		var messageString = input.openpgp;
+		var signatureText = input.text; //text to verify signatures against. Modified by Tag11.
+		var messages = new Array();
+		var messageCount = 0;
+		var mypos = 0;
+		var l = messageString.length;
+		while (mypos < messageString.length) {
+			var first_packet = openpgp_packet.read_packet(messageString, mypos, l);
+			if (!first_packet) {
+				break;
+			}
+			// public key parser (definition from the standard:)
+			// OpenPGP Message      :- Encrypted Message | Signed Message |
+			//                         Compressed Message | Literal Message.
+			// Compressed Message   :- Compressed Data Packet.
+			// 
+			// Literal Message      :- Literal Data Packet.
+			// 
+			// ESK                  :- Public-Key Encrypted Session Key Packet |
+			//                         Symmetric-Key Encrypted Session Key Packet.
+			// 
+			// ESK Sequence         :- ESK | ESK Sequence, ESK.
+			// 
+			// Encrypted Data       :- Symmetrically Encrypted Data Packet |
+			//                         Symmetrically Encrypted Integrity Protected Data Packet
+			// 
+			// Encrypted Message    :- Encrypted Data | ESK Sequence, Encrypted Data.
+			// 
+			// One-Pass Signed Message :- One-Pass Signature Packet,
+			//                         OpenPGP Message, Corresponding Signature Packet.
+
+			// Signed Message       :- Signature Packet, OpenPGP Message |
+			//                         One-Pass Signed Message.
+			if (first_packet.tagType ==  1 ||
+			    (first_packet.tagType == 2 && first_packet.signatureType < 16) ||
+			     first_packet.tagType ==  3 ||
+			     first_packet.tagType ==  4 ||
+				 first_packet.tagType ==  8 ||
+				 first_packet.tagType ==  9 ||
+				 first_packet.tagType == 10 ||
+				 first_packet.tagType == 11 ||
+				 first_packet.tagType == 18 ||
+				 first_packet.tagType == 19) {
+				messages[messages.length] = new openpgp_msg_message();
+				messages[messageCount].messagePacket = first_packet;
+				messages[messageCount].type = input.type;
+				// Encrypted Message
+				if (first_packet.tagType == 9 ||
+				    first_packet.tagType == 1 ||
+				    first_packet.tagType == 3 ||
+				    first_packet.tagType == 18) {
+					if (first_packet.tagType == 9) {
+						util.print_error("unexpected openpgp packet");
+						break;
+					} else if (first_packet.tagType == 1) {
+						util.print_debug("session key found:\n "+first_packet.toString());
+						var issessionkey = true;
+						messages[messageCount].sessionKeys = new Array();
+						var sessionKeyCount = 0;
+						while (issessionkey) {
+							messages[messageCount].sessionKeys[sessionKeyCount] = first_packet;
+							mypos += first_packet.packetLength + first_packet.headerLength;
+							l -= (first_packet.packetLength + first_packet.headerLength);
+							first_packet = openpgp_packet.read_packet(messageString, mypos, l);
+							
+							if (first_packet.tagType != 1 && first_packet.tagType != 3)
+								issessionkey = false;
+							sessionKeyCount++;
+						}
+						if (first_packet.tagType == 18 || first_packet.tagType == 9) {
+							util.print_debug("encrypted data found:\n "+first_packet.toString());
+							messages[messageCount].encryptedData = first_packet;
+							mypos += first_packet.packetLength+first_packet.headerLength;
+							l -= (first_packet.packetLength+first_packet.headerLength);
+							messageCount++;
+							
+						} else {
+							util.print_debug("something is wrong: "+first_packet.tagType);
+						}
+						
+					} else if (first_packet.tagType == 18) {
+						util.print_debug("symmetric encrypted data");
+						break;
+					}
+				} else 
+					if (first_packet.tagType == 2 && first_packet.signatureType < 3) {
+					// Signed Message
+						mypos += first_packet.packetLength + first_packet.headerLength;
+						l -= (first_packet.packetLength + first_packet.headerLength);
+						messages[messageCount].text = signatureText;
+						messages[messageCount].signature = first_packet;
+				        messageCount++;
+				} else 
+					// Signed Message
+					if (first_packet.tagType == 4) {
+						//TODO: Implement check
+						mypos += first_packet.packetLength + first_packet.headerLength;
+						l -= (first_packet.packetLength + first_packet.headerLength);
+				} else 
+					if (first_packet.tagType == 8) {
+					// Compressed Message
+						mypos += first_packet.packetLength + first_packet.headerLength;
+						l -= (first_packet.packetLength + first_packet.headerLength);
+				        var decompressedText = first_packet.decompress();
+				        messages = messages.concat(openpgp.read_messages_dearmored({text: decompressedText, openpgp: decompressedText}));
+				} else
+					// Marker Packet (Obsolete Literal Packet) (Tag 10)
+					// "Such a packet MUST be ignored when received." see http://tools.ietf.org/html/rfc4880#section-5.8
+					if (first_packet.tagType == 10) {
+						// reset messages
+						messages.length = 0;
+						// continue with next packet
+						mypos += first_packet.packetLength + first_packet.headerLength;
+						l -= (first_packet.packetLength + first_packet.headerLength);
+				} else 
+					if (first_packet.tagType == 11) {
+					// Literal Message -- work is already done in read_packet
+					mypos += first_packet.packetLength + first_packet.headerLength;
+					l -= (first_packet.packetLength + first_packet.headerLength);
+					signatureText = first_packet.data;
+					messages[messageCount].data = first_packet.data;
+					messageCount++;
+				} else 
+					if (first_packet.tagType == 19) {
+					// Modification Detect Code
+						mypos += first_packet.packetLength + first_packet.headerLength;
+						l -= (first_packet.packetLength + first_packet.headerLength);
+				}
+			} else {
+				util.print_error('no message found!');
+				return null;
+			}
+		}
+		
+		return messages;
+	}
+	
+	/**
+	 * creates a binary string representation of an encrypted and signed message.
+	 * The message will be encrypted with the public keys specified and signed
+	 * with the specified private key.
+	 * @param {Object} privatekey {obj: [openpgp_msg_privatekey]} Private key 
+	 * to be used to sign the message
+	 * @param {Object[]} publickeys An arraf of {obj: [openpgp_msg_publickey]}
+	 * - public keys to be used to encrypt the message 
+	 * @param {String} messagetext message text to encrypt and sign
+	 * @return {String} a binary string representation of the message which 
+	 * can be OpenPGP armored
+	 */
+	function write_signed_and_encrypted_message(privatekey, publickeys, messagetext) {
+		var result = "";
+		var literal = new openpgp_packet_literaldata().write_packet(messagetext.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n"));
+		util.print_debug_hexstr_dump("literal_packet: |"+literal+"|\n",literal);
+		for (var i = 0; i < publickeys.length; i++) {
+			var onepasssignature = new openpgp_packet_onepasssignature();
+			var onepasssigstr = "";
+			if (i == 0)
+				onepasssigstr = onepasssignature.write_packet(1, openpgp.config.config.prefer_hash_algorithm,  privatekey, false);
+			else
+				onepasssigstr = onepasssignature.write_packet(1, openpgp.config.config.prefer_hash_algorithm,  privatekey, false);
+			util.print_debug_hexstr_dump("onepasssigstr: |"+onepasssigstr+"|\n",onepasssigstr);
+			var datasignature = new openpgp_packet_signature().write_message_signature(1, messagetext.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n"), privatekey);
+			util.print_debug_hexstr_dump("datasignature: |"+datasignature.openpgp+"|\n",datasignature.openpgp);
+			if (i == 0) {
+				result = onepasssigstr+literal+datasignature.openpgp;
+			} else {
+				result = onepasssigstr+result+datasignature.openpgp;
+			}
+		}
+		
+		util.print_debug_hexstr_dump("signed packet: |"+result+"|\n",result);
+		// signatures done.. now encryption
+		var sessionkey = openpgp_crypto_generateSessionKey(openpgp.config.config.encryption_cipher); 
+		var result2 = "";
+		
+		// creating session keys for each recipient
+		for (var i = 0; i < publickeys.length; i++) {
+			var pkey = publickeys[i].getEncryptionKey();
+			if (pkey == null) {
+				util.print_error("no encryption key found! Key is for signing only.");
+				return null;
+			}
+			result2 += new openpgp_packet_encryptedsessionkey().
+					write_pub_key_packet(
+						pkey.getKeyId(),
+						pkey.MPIs,
+						pkey.publicKeyAlgorithm,
+						openpgp.config.config.encryption_cipher,
+						sessionkey);
+		}
+		if (openpgp.config.config.integrity_protect) {
+			result2 += new openpgp_packet_encryptedintegrityprotecteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result);
+		} else {
+			result2 += new openpgp_packet_encrypteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result);
+		}
+		return openpgp_encoding_armor(3,result2,null,null);
+	}
+	/**
+	 * creates a binary string representation of an encrypted message.
+	 * The message will be encrypted with the public keys specified 
+	 * @param {Object[]} publickeys An array of {obj: [openpgp_msg_publickey]}
+	 * -public keys to be used to encrypt the message 
+	 * @param {String} messagetext message text to encrypt
+	 * @return {String} a binary string representation of the message
+	 * which can be OpenPGP armored
+	 */
+	function write_encrypted_message(publickeys, messagetext) {
+		var result = "";
+		var literal = new openpgp_packet_literaldata().write_packet(messagetext.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n"));
+		util.print_debug_hexstr_dump("literal_packet: |"+literal+"|\n",literal);
+		result = literal;
+		
+		// signatures done.. now encryption
+		var sessionkey = openpgp_crypto_generateSessionKey(openpgp.config.config.encryption_cipher); 
+		var result2 = "";
+		
+		// creating session keys for each recipient
+		for (var i = 0; i < publickeys.length; i++) {
+			var pkey = publickeys[i].getEncryptionKey();
+			if (pkey == null) {
+				util.print_error("no encryption key found! Key is for signing only.");
+				return null;
+			}
+			result2 += new openpgp_packet_encryptedsessionkey().
+					write_pub_key_packet(
+						pkey.getKeyId(),
+						pkey.MPIs,
+						pkey.publicKeyAlgorithm,
+						openpgp.config.config.encryption_cipher,
+						sessionkey);
+		}
+		if (openpgp.config.config.integrity_protect) {
+			result2 += new openpgp_packet_encryptedintegrityprotecteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result);
+		} else {
+			result2 += new openpgp_packet_encrypteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result);
+		}
+		return openpgp_encoding_armor(3,result2,null,null);
+	}
+	
+	/**
+	 * creates a binary string representation a signed message.
+	 * The message will be signed with the specified private key.
+	 * @param {Object} privatekey {obj: [openpgp_msg_privatekey]}
+	 * - the private key to be used to sign the message 
+	 * @param {String} messagetext message text to sign
+	 * @return {Object} {Object: text [String]}, openpgp: {String} a binary
+	 *  string representation of the message which can be OpenPGP
+	 *   armored(openpgp) and a text representation of the message (text). 
+	 * This can be directly used to OpenPGP armor the message
+	 */
+	function write_signed_message(privatekey, messagetext) {
+		var sig = new openpgp_packet_signature().write_message_signature(1, messagetext.replace(/\r\n/g,"\n").replace(/\n/,"\r\n"), privatekey);
+		var result = {text: messagetext.replace(/\r\n/g,"\n").replace(/\n/,"\r\n"), openpgp: sig.openpgp, hash: sig.hash};
+		return openpgp_encoding_armor(2,result, null, null)
+	}
+	
+	/**
+	 * generates a new key pair for openpgp. Beta stage. Currently only 
+	 * supports RSA keys, and no subkeys.
+	 * @param {Integer} keyType to indicate what type of key to make. 
+	 * RSA is 1. Follows algorithms outlined in OpenPGP.
+	 * @param {Integer} numBits number of bits for the key creation. (should 
+	 * be 1024+, generally)
+	 * @param {String} userId assumes already in form of "User Name 
+	 * <username@email.com>"
+	 * @return {Object} {privateKey: [openpgp_msg_privatekey], 
+	 * privateKeyArmored: [string], publicKeyArmored: [string]}
+	 */
+	function generate_key_pair(keyType, numBits, userId, passphrase){
+		var userIdPacket = new openpgp_packet_userid();
+		var userIdString = userIdPacket.write_packet(userId);
+		
+		var keyPair = openpgp_crypto_generateKeyPair(keyType,numBits, passphrase, openpgp.config.config.prefer_hash_algorithm, 3);
+		var privKeyString = keyPair.privateKey;
+		var privKeyPacket = new openpgp_packet_keymaterial().read_priv_key(privKeyString.string,3,privKeyString.string.length);
+		if(!privKeyPacket.decryptSecretMPIs(passphrase))
+		    util.print_error('Issue creating key. Unable to read resulting private key');
+		var privKey = new openpgp_msg_privatekey();
+		privKey.privateKeyPacket = privKeyPacket;
+		privKey.getPreferredSignatureHashAlgorithm = function(){return openpgp.config.config.prefer_hash_algorithm};//need to override this to solve catch 22 to generate signature. 8 is value for SHA256
+		
+		var publicKeyString = privKey.privateKeyPacket.publicKey.data;
+		var hashData = String.fromCharCode(0x99)+ String.fromCharCode(((publicKeyString.length) >> 8) & 0xFF) 
+			+ String.fromCharCode((publicKeyString.length) & 0xFF) +publicKeyString+String.fromCharCode(0xB4) +
+			String.fromCharCode((userId.length) >> 24) +String.fromCharCode(((userId.length) >> 16) & 0xFF) 
+			+ String.fromCharCode(((userId.length) >> 8) & 0xFF) + String.fromCharCode((userId.length) & 0xFF) + userId
+		var signature = new openpgp_packet_signature();
+		signature = signature.write_message_signature(16,hashData, privKey);
+		var publicArmored = openpgp_encoding_armor(4, keyPair.publicKey.string + userIdString + signature.openpgp );
+
+		var privArmored = openpgp_encoding_armor(5,privKeyString.string+userIdString+signature.openpgp);
+		
+		return {privateKey : privKey, privateKeyArmored: privArmored, publicKeyArmored: publicArmored}
+	}
+	
+	this.generate_key_pair = generate_key_pair;
+	this.write_signed_message = write_signed_message; 
+	this.write_signed_and_encrypted_message = write_signed_and_encrypted_message;
+	this.write_encrypted_message = write_encrypted_message;
+	this.read_message = read_message;
+	this.read_messages_dearmored = read_messages_dearmored;
+	this.read_publicKey = read_publicKey;
+	this.read_privateKey = read_privateKey;
+	this.init = init;
+}
+
+var openpgp = new _openpgp();
+
+
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.keyring.js.html b/doc/openpgp.keyring.js.html new file mode 100644 index 00000000..166dd126 --- /dev/null +++ b/doc/openpgp.keyring.js.html @@ -0,0 +1,313 @@ + + + + + JSDoc: Source: openpgp.keyring.js + + + + + + + + + + +
+ +

Source: openpgp.keyring.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * @class
+ * @classdesc The class that deals with storage of the keyring. Currently the only option is to use HTML5 local storage.
+ */
+function openpgp_keyring() {
+		
+	/**
+	 * Initialization routine for the keyring. This method reads the 
+	 * keyring from HTML5 local storage and initializes this instance.
+	 * This method is called by openpgp.init().
+	 */
+	function init() {
+		var sprivatekeys = JSON.parse(window.localStorage.getItem("privatekeys"));
+		var spublickeys = JSON.parse(window.localStorage.getItem("publickeys"));
+		if (sprivatekeys == null || sprivatekeys.length == 0) {
+			sprivatekeys = new Array();
+		}
+
+		if (spublickeys == null || spublickeys.length == 0) {
+			spublickeys = new Array();
+		}
+		this.publicKeys = new Array();
+		this.privateKeys = new Array();
+		var k = 0;
+		for (var i =0; i < sprivatekeys.length; i++) {
+			var r = openpgp.read_privateKey(sprivatekeys[i]);
+			this.privateKeys[k] = { armored: sprivatekeys[i], obj: r[0], keyId: r[0].getKeyId()};
+			k++;
+		}
+		k = 0;
+		for (var i =0; i < spublickeys.length; i++) {
+			var r = openpgp.read_publicKey(spublickeys[i]);
+			if (r[0] != null) {
+				this.publicKeys[k] = { armored: spublickeys[i], obj: r[0], keyId: r[0].getKeyId()};
+				k++;
+			}
+		}
+	}
+	this.init = init;
+
+	/**
+	 * Checks if at least one private key is in the keyring
+	 * @return {Boolean} True if there are private keys, else false.
+	 */
+	function hasPrivateKey() {
+		return this.privateKeys.length > 0;
+	}
+	this.hasPrivateKey = hasPrivateKey;
+
+	/**
+	 * Saves the current state of the keyring to HTML5 local storage.
+	 * The privateKeys array and publicKeys array gets Stringified using JSON
+	 */
+	function store() { 
+		var priv = new Array();
+		for (var i = 0; i < this.privateKeys.length; i++) {
+			priv[i] = this.privateKeys[i].armored;
+		}
+		var pub = new Array();
+		for (var i = 0; i < this.publicKeys.length; i++) {
+			pub[i] = this.publicKeys[i].armored;
+		}
+		window.localStorage.setItem("privatekeys",JSON.stringify(priv));
+		window.localStorage.setItem("publickeys",JSON.stringify(pub));
+	}
+	this.store = store;
+	/**
+	 * searches all public keys in the keyring matching the address or address part of the user ids
+	 * @param {String} email_address
+	 * @return {openpgp_msg_publickey[]} The public keys associated with provided email address.
+	 */
+	function getPublicKeyForAddress(email_address) {
+		var results = new Array();
+		var spl = email_address.split("<");
+		var email = "";
+		if (spl.length > 1) {
+			email = spl[1].split(">")[0];
+		} else {
+			email = email_address.trim();
+		}
+		email = email.toLowerCase();
+		if(!util.emailRegEx.test(email)){
+		    return results;
+		}
+		for (var i =0; i < this.publicKeys.length; i++) {
+			for (var j = 0; j < this.publicKeys[i].obj.userIds.length; j++) {
+				if (this.publicKeys[i].obj.userIds[j].text.toLowerCase().indexOf(email) >= 0)
+					results[results.length] = this.publicKeys[i];
+			}
+		}
+		return results;
+	}
+	this.getPublicKeyForAddress = getPublicKeyForAddress;
+
+	/**
+	 * Searches the keyring for a private key containing the specified email address
+	 * @param {String} email_address email address to search for
+	 * @return {openpgp_msg_privatekey[]} private keys found
+	 */
+	function getPrivateKeyForAddress(email_address) {
+		var results = new Array();
+		var spl = email_address.split("<");
+		var email = "";
+		if (spl.length > 1) {
+			email = spl[1].split(">")[0];
+		} else {
+			email = email_address.trim();
+		}
+		email = email.toLowerCase();
+		if(!util.emailRegEx.test(email)){
+		    return results;
+		}
+		for (var i =0; i < this.privateKeys.length; i++) {
+			for (var j = 0; j < this.privateKeys[i].obj.userIds.length; j++) {
+				if (this.privateKeys[i].obj.userIds[j].text.toLowerCase().indexOf(email) >= 0)
+					results[results.length] = this.privateKeys[i];
+			}
+		}
+		return results;
+	}
+
+	this.getPrivateKeyForAddress = getPrivateKeyForAddress;
+	/**
+	 * Searches the keyring for public keys having the specified key id
+	 * @param {String} keyId provided as string of hex number (lowercase)
+	 * @return {openpgp_msg_privatekey[]} public keys found
+	 */
+	function getPublicKeysForKeyId(keyId) {
+		var result = new Array();
+		for (var i=0; i < this.publicKeys.length; i++) {
+			var key = this.publicKeys[i];
+			if (keyId == key.obj.getKeyId())
+				result[result.length] = key;
+			else if (key.obj.subKeys != null) {
+				for (var j=0; j < key.obj.subKeys.length; j++) {
+					var subkey = key.obj.subKeys[j];
+					if (keyId == subkey.getKeyId()) {
+						result[result.length] = {
+								obj: key.obj.getSubKeyAsKey(j),
+								keyId: subkey.getKeyId()
+						}
+					}
+				}
+			}
+		}
+		return result;
+	}
+	this.getPublicKeysForKeyId = getPublicKeysForKeyId;
+	
+	/**
+	 * Searches the keyring for private keys having the specified key id
+	 * @param {String} keyId 8 bytes as string containing the key id to look for
+	 * @return {openpgp_msg_privatekey[]} private keys found
+	 */
+	function getPrivateKeyForKeyId(keyId) {
+		var result = new Array();
+		for (var i=0; i < this.privateKeys.length; i++) {
+			if (keyId == this.privateKeys[i].obj.getKeyId()) {
+				result[result.length] = { key: this.privateKeys[i], keymaterial: this.privateKeys[i].obj.privateKeyPacket};
+			}
+			if (this.privateKeys[i].obj.subKeys != null) {
+				var subkeyids = this.privateKeys[i].obj.getSubKeyIds();
+				for (var j=0; j < subkeyids.length; j++)
+					if (keyId == util.hexstrdump(subkeyids[j])) {
+						result[result.length] = { key: this.privateKeys[i], keymaterial: this.privateKeys[i].obj.subKeys[j]};
+					}
+			}
+		}
+		return result;
+	}
+	this.getPrivateKeyForKeyId = getPrivateKeyForKeyId;
+	
+	/**
+	 * Imports a public key from an exported ascii armored message 
+	 * @param {String} armored_text PUBLIC KEY BLOCK message to read the public key from
+	 */
+	function importPublicKey (armored_text) {
+		var result = openpgp.read_publicKey(armored_text);
+		for (var i = 0; i < result.length; i++) {
+			this.publicKeys[this.publicKeys.length] = {armored: armored_text, obj: result[i], keyId: result[i].getKeyId()};
+		}
+		return true;
+	}
+
+	/**
+	 * Imports a private key from an exported ascii armored message 
+	 * @param {String} armored_text PRIVATE KEY BLOCK message to read the private key from
+	 */
+	function importPrivateKey (armored_text, password) {
+		var result = openpgp.read_privateKey(armored_text);
+		if(!result[0].decryptSecretMPIs(password))
+		    return false;
+		for (var i = 0; i < result.length; i++) {
+			this.privateKeys[this.privateKeys.length] = {armored: armored_text, obj: result[i], keyId: result[i].getKeyId()};
+		}
+		return true;
+	}
+
+	this.importPublicKey = importPublicKey;
+	this.importPrivateKey = importPrivateKey;
+	
+	/**
+	 * returns the openpgp_msg_privatekey representation of the public key at public key ring index  
+	 * @param {Integer} index the index of the public key within the publicKeys array
+	 * @return {openpgp_msg_privatekey} the public key object
+	 */
+	function exportPublicKey(index) {
+		return this.publicKey[index];
+	}
+	this.exportPublicKey = exportPublicKey;
+		
+	
+	/**
+	 * Removes a public key from the public key keyring at the specified index 
+	 * @param {Integer} index the index of the public key within the publicKeys array
+	 * @return {openpgp_msg_privatekey} The public key object which has been removed
+	 */
+	function removePublicKey(index) {
+		var removed = this.publicKeys.splice(index,1);
+		this.store();
+		return removed;
+	}
+	this.removePublicKey = removePublicKey;
+
+	/**
+	 * returns the openpgp_msg_privatekey representation of the private key at private key ring index  
+	 * @param {Integer} index the index of the private key within the privateKeys array
+	 * @return {openpgp_msg_privatekey} the private key object
+	 */	
+	function exportPrivateKey(index) {
+		return this.privateKeys[index];
+	}
+	this.exportPrivateKey = exportPrivateKey;
+
+	/**
+	 * Removes a private key from the private key keyring at the specified index 
+	 * @param {Integer} index the index of the private key within the privateKeys array
+	 * @return {openpgp_msg_privatekey} The private key object which has been removed
+	 */
+	function removePrivateKey(index) {
+		var removed = this.privateKeys.splice(index,1);
+		this.store();
+		return removed;
+	}
+	this.removePrivateKey = removePrivateKey;
+
+}
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.msg.message.js.html b/doc/openpgp.msg.message.js.html new file mode 100644 index 00000000..b7cd857a --- /dev/null +++ b/doc/openpgp.msg.message.js.html @@ -0,0 +1,185 @@ + + + + + JSDoc: Source: openpgp.msg.message.js + + + + + + + + + + +
+ +

Source: openpgp.msg.message.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * @protected
+ * @class
+ * @classdesc Top-level message object. Contains information from one or more packets
+ */
+
+function openpgp_msg_message() {
+	
+	// -1 = no valid passphrase submitted
+	// -2 = no private key found
+	// -3 = decryption error
+	// text = valid decryption
+	this.text = "";
+	this.messagePacket = null;
+	this.type = null;
+	
+	/**
+	 * Decrypts a message and generates user interface message out of the found.
+	 * MDC will be verified as well as message signatures
+	 * @param {openpgp_msg_privatekey} private_key the private the message is encrypted with (corresponding to the session key)
+	 * @param {openpgp_packet_encryptedsessionkey} sessionkey the session key to be used to decrypt the message
+	 * @return {String} plaintext of the message or null on error
+	 */
+	function decrypt(private_key, sessionkey) {
+        return this.decryptAndVerifySignature(private_key, sessionkey).text;
+	}
+
+	/**
+	 * Decrypts a message and generates user interface message out of the found.
+	 * MDC will be verified as well as message signatures
+	 * @param {openpgp_msg_privatekey} private_key the private the message is encrypted with (corresponding to the session key)
+	 * @param {openpgp_packet_encryptedsessionkey} sessionkey the session key to be used to decrypt the message
+	 * @param {openpgp_msg_publickey} pubkey Array of public keys to check signature against. If not provided, checks local keystore.
+	 * @return {String} plaintext of the message or null on error
+	 */
+	function decryptAndVerifySignature(private_key, sessionkey, pubkey) {
+		if (private_key == null || sessionkey == null || sessionkey == "")
+			return null;
+		var decrypted = sessionkey.decrypt(this, private_key.keymaterial);
+		if (decrypted == null)
+			return null;
+		var packet;
+		var position = 0;
+		var len = decrypted.length;
+		var validSignatures = new Array();
+		util.print_debug_hexstr_dump("openpgp.msg.messge decrypt:\n",decrypted);
+		
+		var messages = openpgp.read_messages_dearmored({text: decrypted, openpgp: decrypted});
+		for(var m in messages){
+			if(messages[m].data){
+				this.text = messages[m].data;
+			}
+			if(messages[m].signature){
+			    validSignatures.push(messages[m].verifySignature(pubkey));
+			}
+		}
+		return {text:this.text, validSignatures:validSignatures};
+	}
+	
+	/**
+	 * Verifies a message signature. This function can be called after read_message if the message was signed only.
+	 * @param {openpgp_msg_publickey} pubkey Array of public keys to check signature against. If not provided, checks local keystore.
+	 * @return {boolean} true if the signature was correct; otherwise false
+	 */
+	function verifySignature(pubkey) {
+		var result = false;
+		if (this.signature.tagType == 2) {
+		    if(!pubkey || pubkey.length == 0){
+			    var pubkey;
+			    if (this.signature.version == 4) {
+				    pubkey = openpgp.keyring.getPublicKeysForKeyId(this.signature.issuerKeyId);
+			    } else if (this.signature.version == 3) {
+				    pubkey = openpgp.keyring.getPublicKeysForKeyId(this.signature.keyId);
+			    } else {
+				    util.print_error("unknown signature type on message!");
+				    return false;
+			    }
+			}
+			if (pubkey.length == 0)
+				util.print_warning("Unable to verify signature of issuer: "+util.hexstrdump(this.signature.issuerKeyId)+". Public key not found in keyring.");
+			else {
+				for (var i = 0 ; i < pubkey.length; i++) {
+					var tohash = this.text.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n");
+					if (this.signature.verify(tohash, pubkey[i])) {
+						util.print_info("Found Good Signature from "+pubkey[i].obj.userIds[0].text+" (0x"+util.hexstrdump(pubkey[i].obj.getKeyId()).substring(8)+")");
+						result = true;
+					} else {
+						util.print_error("Signature verification failed: Bad Signature from "+pubkey[i].obj.userIds[0].text+" (0x"+util.hexstrdump(pubkey[0].obj.getKeyId()).substring(8)+")");
+					}
+				}
+			}
+		}
+		return result;
+	}
+	
+	function toString() {
+		var result = "Session Keys:\n";
+		if (this.sessionKeys !=null)
+		for (var i = 0; i < this.sessionKeys.length; i++) {
+			result += this.sessionKeys[i].toString();
+		}
+		result += "\n\n EncryptedData:\n";
+		if(this.encryptedData != null)
+		result += this.encryptedData.toString();
+		
+		result += "\n\n Signature:\n";
+		if(this.signature != null)
+		result += this.signature.toString();
+		
+		result += "\n\n Text:\n"
+		if(this.signature != null)
+			result += this.text;
+		return result;
+	}
+	this.decrypt = decrypt;
+	this.decryptAndVerifySignature = decryptAndVerifySignature;
+	this.verifySignature = verifySignature;
+	this.toString = toString;
+}
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.msg.privatekey.js.html b/doc/openpgp.msg.privatekey.js.html new file mode 100644 index 00000000..508fe737 --- /dev/null +++ b/doc/openpgp.msg.privatekey.js.html @@ -0,0 +1,240 @@ + + + + + JSDoc: Source: openpgp.msg.privatekey.js + + + + + + + + + + +
+ +

Source: openpgp.msg.privatekey.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * @class
+ * @classdesc Class that represents a decoded private key for internal openpgp.js use
+ */
+
+function openpgp_msg_privatekey() {
+	this.subKeys = new Array();
+	this.privateKeyPacket = null;
+	this.userIds = new Array();
+	this.userAttributes = new Array();
+	this.revocationSignatures = new Array();
+	this.subKeys = new Array();
+
+	/**
+	 * 
+	 * @return last position
+	 */
+	function read_nodes(parent_node, input, position, len) {
+		this.privateKeyPacket = parent_node;
+		
+		var pos = position;
+		while (input.length > pos) {
+			var result = openpgp_packet.read_packet(input, pos, input.length - pos);
+			if (result == null) {
+				util.print_error("openpgp.msg.messge decrypt:\n"+'[pub/priv_key]parsing ends here @:' + pos + " l:" + len);
+				break;
+			} else {
+				switch (result.tagType) {
+				case 2: // public key revocation signature
+					if (result.signatureType == 32)
+						this.revocationSignatures[this.revocationSignatures.length] = result;
+					else if (result.signatureType > 15 && result.signatureType < 20) {
+						if (this.certificationsignatures == null)
+							this.certificationSignatures = new Array();
+						this.certificationSignatures[this.certificationSignatures.length] = result;
+					} else
+						util.print_error("openpgp.msg.messge decrypt:\n"+"unknown signature type directly on key "+result.signatureType+" @"+pos);
+					pos += result.packetLength + result.headerLength;
+					break;
+				case 7: // PrivateSubkey Packet
+					this.subKeys[this.subKeys.length] = result;
+					pos += result.packetLength + result.headerLength;
+					pos += result.read_nodes(this.privateKeyPacket,input, pos, input.length - pos);
+					break;
+				case 17: // User Attribute Packet
+					this.userAttributes[this.userAttributes.length] = result;
+					pos += result.packetLength + result.headerLength;
+					pos += result.read_nodes(this.privateKeyPacket,input, pos, input.length - pos);
+					break;
+				case 13: // User ID Packet
+					this.userIds[this.userIds.length] = result;
+					pos += result.packetLength + result.headerLength;
+					pos += result.read_nodes(this.privateKeyPacket, input, pos, input.length - pos);
+					break;
+				default:
+					this.position = position - this.privateKeyPacket.packetLength - this.privateKeyPacket.headerLength;
+					this.len = pos - position;
+					return this.len;
+				}
+			}
+		}
+		this.position = position - this.privateKeyPacket.packetLength - this.privateKeyPacket.headerLength;
+		this.len = pos - position;
+		
+		return this.len;
+	}
+	
+	function getKeyId() {
+		return this.privateKeyPacket.publicKey.getKeyId();
+	}
+	
+	
+	function getSubKeyIds() {
+		if (this.privateKeyPacket.publicKey.version == 4) // V3 keys MUST NOT have subkeys.
+		var result = new Array();
+		for (var i = 0; i < this.subKeys.length; i++) {
+			result[i] = str_sha1(this.subKeys[i].publicKey.header+this.subKeys[i].publicKey.data).substring(12,20);
+		}
+		return result;
+	}
+	
+	
+	function getSigningKey() {
+		if ((this.privateKeyPacket.publicKey.publicKeyAlgorithm == 17 ||
+			 this.privateKeyPacket.publicKey.publicKeyAlgorithm != 2)
+			&& this.privateKeyPacket.publicKey.verifyKey() == 3)
+			return this.privateKeyPacket;
+		else if (this.privateKeyPacket.publicKey.version == 4) // V3 keys MUST NOT have subkeys.
+			for (var j = 0; j < this.privateKeyPacket.subKeys.length; j++) {
+				if ((this.privateKeyPacket.subKeys[j].publicKey.publicKeyAlgorithm == 17 ||
+					 this.privateKeyPacket.subKeys[j].publicKey.publicKeyAlgorithm != 2) &&
+					 this.privateKeyPacket.subKeys[j].publicKey.verifyKey() == 3)
+					return this.privateKeyPacket.subKeys[j];
+			}
+		return null;
+	}
+	
+	function getPreferredSignatureHashAlgorithm() {
+		var pkey = this.getSigningKey();
+		if (pkey == null) {
+			util.print_error("private key is for encryption only! Cannot create a signature.")
+			return null;
+		}
+		if (pkey.publicKey.publicKeyAlgorithm == 17) {
+			var dsa = new DSA();
+			return dsa.select_hash_algorithm(pkey.publicKey.MPIs[1].toBigInteger()); // q
+		}
+		return openpgp.config.config.prefer_hash_algorithm;
+			
+	}
+
+	function decryptSecretMPIs(str_passphrase) {
+		return this.privateKeyPacket.decryptSecretMPIs(str_passphrase);
+	}
+	
+	function getFingerprint() {
+		return this.privateKeyPacket.publicKey.getFingerprint();
+	}
+
+	// TODO need to implement this
+	function revoke() {
+		
+	}
+
+	/**
+	 * extracts the public key part
+	 * @return {String} OpenPGP armored text containing the public key
+	 *                  returns null if no sufficient data to extract public key
+	 */
+	function extractPublicKey() {
+		// add public key
+		var key = this.privateKeyPacket.publicKey.header + this.privateKeyPacket.publicKey.data;
+		for (var i = 0; i < this.userIds.length; i++) {
+			// verify userids
+			if (this.userIds[i].certificationSignatures.length === 0) {
+				util.print_error("extractPublicKey - missing certification signatures");
+				return null;
+			}
+			var userIdPacket = new openpgp_packet_userid();
+			// add userids
+			key += userIdPacket.write_packet(this.userIds[i].text);
+			for (var j = 0; j < this.userIds[i].certificationSignatures.length; j++) {
+				var certSig = this.userIds[i].certificationSignatures[j];
+				// add signatures
+				key += openpgp_packet.write_packet_header(2, certSig.data.length) + certSig.data;
+			}
+		}
+		for (var k = 0; k < this.subKeys.length; k++) {
+			var pubSubKey = this.subKeys[k].publicKey;
+			// add public subkey package
+			key += openpgp_packet.write_old_packet_header(14, pubSubKey.data.length) + pubSubKey.data;
+			var subKeySig = this.subKeys[k].subKeySignature;
+			if (subKeySig !== null) {
+				// add subkey signature
+				key += openpgp_packet.write_packet_header(2, subKeySig.data.length) + subKeySig.data;
+			} else {
+				util.print_error("extractPublicKey - missing subkey signature");
+				return null;
+			}
+		}
+		var publicArmored = openpgp_encoding_armor(4, key);
+		return publicArmored;
+	}
+
+	this.extractPublicKey = extractPublicKey;
+	this.getSigningKey = getSigningKey;
+	this.getFingerprint = getFingerprint;
+	this.getPreferredSignatureHashAlgorithm = getPreferredSignatureHashAlgorithm;
+	this.read_nodes = read_nodes;
+	this.decryptSecretMPIs = decryptSecretMPIs;
+	this.getSubKeyIds = getSubKeyIds;
+	this.getKeyId = getKeyId;
+	
+}
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.msg.publickey.js.html b/doc/openpgp.msg.publickey.js.html new file mode 100644 index 00000000..9417250f --- /dev/null +++ b/doc/openpgp.msg.publickey.js.html @@ -0,0 +1,317 @@ + + + + + JSDoc: Source: openpgp.msg.publickey.js + + + + + + + + + + +
+ +

Source: openpgp.msg.publickey.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * @class
+ * @classdesc Decoded public key object for internal openpgp.js use
+ */
+function openpgp_msg_publickey() {
+	this.data;
+	this.position;
+	this.len;
+	this.tostring = "OPENPGP PUBLIC KEY\n";
+	this.bindingSignature = null;
+	this.publicKeyPacket = null;
+	this.userIds = new Array();
+	this.userAttributes = new Array();
+	this.revocationSignatures = new Array();
+	this.subKeys = new Array();
+	this.arbitraryPacket = new Array();
+	this.directSignatures = new Array();
+	/**
+	 * 
+	 * @return last position
+	 */
+	function read_nodes(parent_node, input, position, len) {
+		this.publicKeyPacket = parent_node;
+		var exit = false;
+		var pos = position;
+		var l = len;
+		while (input.length != pos) {
+			var result = openpgp_packet.read_packet(input, pos, input.length - pos);
+			if (result == null) {
+				util.print_error("openpgp.msg.publickey read_nodes:\n"+'[pub_key]parsing ends here @:' + pos + " l:" + l);
+				break;
+			} else {
+				switch (result.tagType) {
+				case 2: // public key revocation signature
+					if (result.signatureType == 32)
+						this.revocationSignatures[this.revocationSignatures.length] = result;
+					else if (result.signatureType == 16 || result.signatureType == 17 || result.signatureType == 18  || result.signatureType == 19)
+						this.certificationSignature = result;
+					else if (result.signatureType == 25) {
+						this.bindingSignature = result;
+					} else if (result.signatureType == 31) {
+						this.directSignatures[this.directSignatures.length] = result;
+					} else
+						util.print_error("openpgp.msg.publickey read_nodes:\n"+"unknown signature type directly on key "+result.signatureType);
+					pos += result.packetLength + result.headerLength;
+					break;
+				case 14: // Public-Subkey Packet
+					this.subKeys[this.subKeys.length] = result;
+					pos += result.packetLength + result.headerLength;
+					pos += result.read_nodes(this.publicKeyPacket,input, pos, input.length - pos);
+					break;
+				case 17: // User Attribute Packet
+					this.userAttributes[this.userAttributes.length] = result;
+					pos += result.packetLength + result.headerLength;
+					pos += result.read_nodes(this.publicKeyPacket,input, pos, input.length - pos);
+					break;
+				case 13: // User ID Packet
+					this.userIds[this.userIds.length] = result;
+					pos += result.packetLength + result.headerLength;
+					pos += result.read_nodes(this.publicKeyPacket, input, pos, input.length - pos);
+					break;
+				default:
+					this.data = input;
+					this.position = position - this.publicKeyPacket.packetLength - this.publicKeyPacket.headerLength;
+					this.len = pos - position;
+					return this.len;
+				}
+			}
+		}
+		this.data = input;
+		this.position = position - (this.publicKeyPacket.packetLength - this.publicKeyPacket.headerLength);
+		this.len = pos - position;
+		return this.len;
+	}
+
+	function write() {
+
+	}
+
+	function getKeyId() {
+		return this.publicKeyPacket.getKeyId();
+	}
+	
+	function getFingerprint() {
+		return this.publicKeyPacket.getFingerprint();
+	}
+
+
+	
+	function validate() {
+		// check revocation keys
+		for (var i = 0; i < this.revocationSignatures.length; i++) {
+			var tohash = this.publicKeyPacket.header+this.publicKeyPacket.data;
+			if (this.revocationSignatures[i].verify(tohash, this.publicKeyPacket))
+				return false;
+		}
+		
+		if (this.subKeys.length != 0) {
+			// search for a valid subkey
+			var found = false;
+			for (var i = 0; i < this.subKeys.length; i++)
+				if (this.subKeys[i].verifyKey() == 3) {
+					found = true;
+					break;
+				}
+			if (!found)
+				return false;
+		}
+		// search for one valid userid
+		found = false;
+		for (var i = 0; i < this.userIds.length; i++)
+			if (this.userIds[i].verify(this.publicKeyPacket) == 0) {
+				found = true;
+				break;
+			}
+		if (!found)
+			return false;
+		return true;
+	}
+	
+	/**
+	 * verifies all signatures
+	 * @return a 2 dimensional array. the first dimension corresponds to the userids available
+	 */
+	function verifyCertificationSignatures() {
+		var result = new Array();
+		for (var i = 0; i < this.userIds.length; i++) {
+			result[i] = this.userIds[i].verifyCertificationSignatures(this.publicKeyPacket);
+		}
+		return result;
+	}
+	this.verifyCertificationSignatures = verifyCertificationSignatures;
+	
+	/**
+	 * verifies:
+	 *  - revocation certificates directly on key
+	 *  - self signatures
+	 *  - subkey binding and revocation certificates
+	 *  
+	 *  This is useful for validating the key
+	 *  @returns {Boolean} true if the basic signatures are all valid
+	 */
+	function verifyBasicSignatures() {
+		for (var i = 0; i < this.revocationSignatures.length; i++) {
+			var tohash = this.publicKeyPacket.header+this.publicKeyPacket.data;
+			if (this.revocationSignatures[i].verify(tohash, this.publicKeyPacket))
+				return false;
+		}
+		
+		if (this.subKeys.length != 0) {
+			// search for a valid subkey
+			var found = false;
+			for (var i = 0; i < this.subKeys.length; i++) {
+				if (this.subKeys[i] == null)
+					continue;
+				var result = this.subKeys[i].verifyKey();
+				if (result == 3) {
+					found = true;
+					break;
+				} 
+			}
+			if (!found)
+				return false;
+		}
+		var keyId = this.getKeyId();
+		for (var i = 0; i < this.userIds.length; i++) {
+			for (var j = 0; j < this.userIds[i].certificationRevocationSignatures.length; j++) {
+				if (this.userIds[i].certificationSignatures[j].getIssuer == keyId &&
+					this.userIds[i].certificationSignatures[j].verifyBasic(this.publicKeyPacket) != 4)
+					return false;
+			}
+		}
+		return true;
+	}
+	
+	function toString() {
+		var result = " OPENPGP Public Key\n    length: "+this.len+"\n";
+		result += "    Revocation Signatures:\n"
+		for (var i=0; i < this.revocationSignatures.length; i++) {
+			result += "    "+this.revocationSignatures[i].toString(); 
+		}
+		result += "    User Ids:\n";
+		for (var i=0; i < this.userIds.length; i++) {
+			result += "    "+this.userIds[i].toString(); 
+		}
+		result += "    User Attributes:\n";
+		for (var i=0; i < this.userAttributes.length; i++) {
+			result += "    "+this.userAttributes[i].toString(); 
+		}
+		result += "    Public Key SubKeys:\n";
+		for (var i=0; i < this.subKeys.length; i++) {
+			result += "    "+this.subKeys[i].toString(); 
+		}
+		return result;
+	}
+	
+	/**
+	 * finds an encryption key for this public key
+	 * @returns null if no encryption key has been found
+	 */
+	function getEncryptionKey() {
+		// V4: by convention subkeys are prefered for encryption service
+		// V3: keys MUST NOT have subkeys
+		for (var j = 0; j < this.subKeys.length; j++)
+				if (this.subKeys[j].publicKeyAlgorithm != 17 &&
+						this.subKeys[j].publicKeyAlgorithm != 3 &&
+						this.subKeys[j].verifyKey()) {
+					return this.subKeys[j];
+				}
+		// if no valid subkey for encryption, use primary key
+		if (this.publicKeyPacket.publicKeyAlgorithm != 17 && this.publicKeyPacket.publicKeyAlgorithm != 3
+			&& this.publicKeyPacket.verifyKey()) {
+			return this.publicKeyPacket;	
+		}
+		return null;
+	}
+	
+	function getSigningKey() {
+		if ((this.publicKeyPacket.publicKeyAlgorithm == 17 ||
+			 this.publicKeyPacket.publicKeyAlgorithm != 2))
+			return this.publicKeyPacket;
+		else if (this.publicKeyPacket.version == 4) // V3 keys MUST NOT have subkeys.
+			for (var j = 0; j < this.subKeys.length; j++) {
+				if ((this.subKeys[j].publicKeyAlgorithm == 17 ||
+					 this.subKeys[j].publicKeyAlgorithm != 2) &&
+					 this.subKeys[j].verifyKey())
+					return this.subKeys[j];
+			}
+		return null;
+	}
+
+        /* Returns the i-th subKey as a openpgp_msg_publickey object */
+	function getSubKeyAsKey(i) {
+		var ret = new openpgp_msg_publickey();
+		ret.userIds = this.userIds;
+		ret.userAttributes = this.userAttributes;
+		ret.publicKeyPacket = this.subKeys[i];
+		return ret;
+	}
+
+	this.getEncryptionKey = getEncryptionKey;
+	this.getSigningKey = getSigningKey;
+	this.read_nodes = read_nodes;
+	this.write = write;
+	this.toString = toString;
+	this.validate = validate;
+	this.getFingerprint = getFingerprint;
+	this.getKeyId = getKeyId;
+	this.verifyBasicSignatures = verifyBasicSignatures;
+	this.getSubKeyAsKey = getSubKeyAsKey;
+}
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.packet.compressed.js.html b/doc/openpgp.packet.compressed.js.html new file mode 100644 index 00000000..618e9812 --- /dev/null +++ b/doc/openpgp.packet.compressed.js.html @@ -0,0 +1,213 @@ + + + + + JSDoc: Source: packet/openpgp.packet.compressed.js + + + + + + + + + + +
+ +

Source: packet/openpgp.packet.compressed.js

+ + + + + +
+
+
// 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 Compressed Data Packet (Tag 8)
+ * 
+ * RFC4880 5.6:
+ * The Compressed Data packet contains compressed data.  Typically, this
+ * packet is found as the contents of an encrypted packet, or following
+ * a Signature or One-Pass Signature packet, and contains a literal data
+ * packet.
+ */   
+function openpgp_packet_compressed() {
+	this.tagType = 8;
+	this.decompressedData = null;
+	
+	/**
+	 * Parsing function for the packet.
+	 * @param {String} input Payload of a tag 8 packet
+	 * @param {Integer} position Position to start reading from the input string
+	 * @param {Integer} len Length of the packet or the remaining length of 
+	 * input at position
+	 * @return {openpgp_packet_compressed} Object representation
+	 */
+	function read_packet (input, position, len) {
+		this.packetLength = len;
+		var mypos = position;
+		// One octet that gives the algorithm used to compress the packet.
+		this.type = input.charCodeAt(mypos++);
+		// Compressed data, which makes up the remainder of the packet.
+		this.compressedData = input.substring(position+1, position+len);
+		return this;
+	}
+	/**
+	 * Decompression method for decompressing the compressed data
+	 * read by read_packet
+	 * @return {String} The decompressed data
+	 */
+	function decompress() {
+		if (this.decompressedData != null)
+			return this.decompressedData;
+
+		if (this.type == null)
+			return null;
+
+		switch (this.type) {
+		case 0: // - Uncompressed
+			this.decompressedData = this.compressedData;
+			break;
+		case 1: // - ZIP [RFC1951]
+			util.print_info('Decompressed packet [Type 1-ZIP]: ' + this.toString());
+			var compData = this.compressedData;
+			var radix = s2r(compData).replace(/\n/g,"");
+			// no header in this case, directly call deflate
+			var jxg_obj = new JXG.Util.Unzip(JXG.Util.Base64.decodeAsArray(radix));
+			this.decompressedData = unescape(jxg_obj.deflate()[0][0]);
+			break;
+		case 2: // - ZLIB [RFC1950]
+			util.print_info('Decompressed packet [Type 2-ZLIB]: ' + this.toString());
+			var compressionMethod = this.compressedData.charCodeAt(0) % 0x10; //RFC 1950. Bits 0-3 Compression Method
+			//Bits 4-7 RFC 1950 are LZ77 Window. Generally this value is 7 == 32k window size.
+			//2nd Byte in RFC 1950 is for "FLAGs" Allows for a Dictionary (how is this defined). Basic checksum, and compression level.
+			if (compressionMethod == 8) { //CM 8 is for DEFLATE, RFC 1951
+				// remove 4 bytes ADLER32 checksum from the end
+				var compData = this.compressedData.substring(0, this.compressedData.length - 4);
+				var radix = s2r(compData).replace(/\n/g,"");
+				//TODO check ADLER32 checksum
+				this.decompressedData = JXG.decompress(radix);
+				break;
+			} else {
+				util.print_error("Compression algorithm ZLIB only supports DEFLATE compression method.");
+			}
+			break;
+		case 3: //  - BZip2 [BZ2]
+			// TODO: need to implement this
+			util.print_error("Compression algorithm BZip2 [BZ2] is not implemented.");
+			break;
+		default:
+			util.print_error("Compression algorithm unknown :"+this.type);
+			break;
+		}
+		util.print_debug("decompressed:"+util.hexstrdump(this.decompressedData));
+		return this.decompressedData; 
+	}
+
+	/**
+	 * Compress the packet data (member decompressedData)
+	 * @param {Integer} type Algorithm to be used // See RFC 4880 9.3
+	 * @param {String} data Data to be compressed
+	 * @return {String} The compressed data stored in attribute compressedData
+	 */
+	function compress(type, data) {
+		this.type = type;
+		this.decompressedData = data;
+		switch (this.type) {
+		case 0: // - Uncompressed
+			this.compressedData = this.decompressedData;
+			break;
+		case 1: // - ZIP [RFC1951]
+			util.print_error("Compression algorithm ZIP [RFC1951] is not implemented.");
+			break;
+		case 2: // - ZLIB [RFC1950]
+			// TODO: need to implement this
+			util.print_error("Compression algorithm ZLIB [RFC1950] is not implemented.");
+			break;
+		case 3: //  - BZip2 [BZ2]
+			// TODO: need to implement this
+			util.print_error("Compression algorithm BZip2 [BZ2] is not implemented.");
+			break;
+		default:
+			util.print_error("Compression algorithm unknown :"+this.type);
+			break;
+		}
+		this.packetLength = this.compressedData.length +1;
+		return this.compressedData; 
+	}
+	
+	/**
+	 * Creates a string representation of the packet
+	 * @param {Integer} algorithm Algorithm to be used // See RFC 4880 9.3
+	 * @param {String} data Data to be compressed
+	 * @return {String} String-representation of the packet
+	 */
+	function write_packet(algorithm, data) {
+		this.decompressedData = data;
+		if (algorithm == null) {
+			this.type = 1;
+		}
+		var result = String.fromCharCode(this.type)+this.compress(this.type);
+		return openpgp_packet.write_packet_header(8, result.length)+result;
+	}
+	
+	/**
+	 * Pretty printing the packet (useful for debug purposes)
+	 * @return {String}
+	 */
+	function toString() {
+		return '5.6.  Compressed Data Packet (Tag 8)\n'+
+		   '    length:  '+this.packetLength+'\n'+
+			   '    Compression Algorithm = '+this.type+'\n'+
+		       '    Compressed Data: Byte ['+util.hexstrdump(this.compressedData)+']\n';
+	}
+	
+	this.read_packet = read_packet;
+	this.toString = toString;
+	this.compress = compress;
+	this.decompress = decompress;
+	this.write_packet = write_packet;
+};
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.packet.encrypteddata.js.html b/doc/openpgp.packet.encrypteddata.js.html new file mode 100644 index 00000000..4041b4d6 --- /dev/null +++ b/doc/openpgp.packet.encrypteddata.js.html @@ -0,0 +1,148 @@ + + + + + JSDoc: Source: packet/openpgp.packet.encrypteddata.js + + + + + + + + + + +
+ +

Source: packet/openpgp.packet.encrypteddata.js

+ + + + + +
+
+
// 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 Symmetrically Encrypted Data Packet (Tag 9)
+ * 
+ * RFC4880 5.7: The Symmetrically Encrypted Data packet contains data encrypted
+ * with a symmetric-key algorithm. When it has been decrypted, it contains other
+ * packets (usually a literal data packet or compressed data packet, but in
+ * theory other Symmetrically Encrypted Data packets or sequences of packets
+ * that form whole OpenPGP messages).
+ */
+
+function openpgp_packet_encrypteddata() {
+	this.tagType = 9;
+	this.packetLength = null;
+	this.encryptedData = null;
+	this.decryptedData = null;
+
+	/**
+	 * Parsing function for the packet.
+	 * 
+	 * @param {String} input Payload of a tag 9 packet
+	 * @param {Integer} position Position to start reading from the input string
+	 * @param {Integer} len Length of the packet or the remaining length of
+	 *            input at position
+	 * @return {openpgp_packet_encrypteddata} Object representation
+	 */
+	function read_packet(input, position, len) {
+		var mypos = position;
+		this.packetLength = len;
+		// - Encrypted data, the output of the selected symmetric-key cipher
+		// operating in OpenPGP's variant of Cipher Feedback (CFB) mode.
+		this.encryptedData = input.substring(position, position + len);
+		return this;
+	}
+
+	/**
+	 * Symmetrically decrypt the packet data
+	 * 
+	 * @param {Integer} symmetric_algorithm_type
+	 *             Symmetric key algorithm to use // See RFC4880 9.2
+	 * @param {String} key
+	 *             Key as string with the corresponding length to the
+	 *            algorithm
+	 * @return The decrypted data;
+	 */
+	function decrypt_sym(symmetric_algorithm_type, key) {
+		this.decryptedData = openpgp_crypto_symmetricDecrypt(
+				symmetric_algorithm_type, key, this.encryptedData, true);
+		util.print_debug("openpgp.packet.encryptedintegrityprotecteddata.js\n"+
+				"data: "+util.hexstrdump(this.decryptedData));
+		return this.decryptedData;
+	}
+
+	/**
+	 * Creates a string representation of the packet
+	 * 
+	 * @param {Integer} algo Symmetric key algorithm to use // See RFC4880 9.2
+	 * @param {String} key Key as string with the corresponding length to the
+	 *            algorithm
+	 * @param {String} data Data to be
+	 * @return {String} String-representation of the packet
+	 */
+	function write_packet(algo, key, data) {
+		var result = "";
+		result += openpgp_crypto_symmetricEncrypt(
+				openpgp_crypto_getPrefixRandom(algo), algo, key, data, true);
+		result = openpgp_packet.write_packet_header(9, result.length) + result;
+		return result;
+	}
+
+	function toString() {
+		return '5.7.  Symmetrically Encrypted Data Packet (Tag 9)\n'
+				+ '    length:  ' + this.packetLength + '\n'
+				+ '    Used symmetric algorithm: ' + this.algorithmType + '\n'
+				+ '    encrypted data: Bytes ['
+				+ util.hexstrdump(this.encryptedData) + ']\n';
+	}
+	this.decrypt_sym = decrypt_sym;
+	this.toString = toString;
+	this.read_packet = read_packet;
+	this.write_packet = write_packet;
+};
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.packet.encryptedintegrityprotecteddata.js.html b/doc/openpgp.packet.encryptedintegrityprotecteddata.js.html new file mode 100644 index 00000000..e994f548 --- /dev/null +++ b/doc/openpgp.packet.encryptedintegrityprotecteddata.js.html @@ -0,0 +1,204 @@ + + + + + JSDoc: Source: packet/openpgp.packet.encryptedintegrityprotecteddata.js + + + + + + + + + + +
+ +

Source: packet/openpgp.packet.encryptedintegrityprotecteddata.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * @class
+ * @classdesc Implementation of the Sym. Encrypted Integrity Protected Data 
+ * Packet (Tag 18)
+ * 
+ * RFC4880 5.13: The Symmetrically Encrypted Integrity Protected Data packet is
+ * a variant of the Symmetrically Encrypted Data packet. It is a new feature
+ * created for OpenPGP that addresses the problem of detecting a modification to
+ * encrypted data. It is used in combination with a Modification Detection Code
+ * packet.
+ */
+
+function openpgp_packet_encryptedintegrityprotecteddata() {
+	this.tagType = 18;
+	this.version = null; // integer == 1
+	this.packetLength = null; // integer
+	this.encryptedData = null; // string
+	this.decrytpedData = null; // string
+	this.hash = null; // string
+	/**
+	 * Parsing function for the packet.
+	 * 
+	 * @param {String} input Payload of a tag 18 packet
+	 * @param {Integer} position
+	 *             position to start reading from the input string
+	 * @param {Integer} len Length of the packet or the remaining length of
+	 *            input at position
+	 * @return {openpgp_packet_encryptedintegrityprotecteddata} object
+	 *         representation
+	 */
+	function read_packet(input, position, len) {
+		this.packetLength = len;
+		// - A one-octet version number. The only currently defined value is
+		// 1.
+		this.version = input[position].charCodeAt();
+		if (this.version != 1) {
+			util
+					.print_error('openpgp.packet.encryptedintegrityprotecteddata.js\nunknown encrypted integrity protected data packet version: '
+							+ this.version
+							+ " , @ "
+							+ position
+							+ "hex:"
+							+ util.hexstrdump(input));
+			return null;
+		}
+		// - Encrypted data, the output of the selected symmetric-key cipher
+		//   operating in Cipher Feedback mode with shift amount equal to the
+		//   block size of the cipher (CFB-n where n is the block size).
+		this.encryptedData = input.substring(position + 1, position + 1 + len);
+		util.print_debug("openpgp.packet.encryptedintegrityprotecteddata.js\n"
+				+ this.toString());
+		return this;
+	}
+
+	/**
+	 * Creates a string representation of a Sym. Encrypted Integrity Protected
+	 * Data Packet (tag 18) (see RFC4880 5.13)
+	 * 
+	 * @param {Integer} symmetric_algorithm
+	 *            The selected symmetric encryption algorithm to be used
+	 * @param {String} key The key of cipher blocksize length to be used
+	 * @param {String} data
+	 *            Plaintext data to be encrypted within the packet
+	 * @return {String} A string representation of the packet
+	 */
+	function write_packet(symmetric_algorithm, key, data) {
+
+		var prefixrandom = openpgp_crypto_getPrefixRandom(symmetric_algorithm);
+		var prefix = prefixrandom
+				+ prefixrandom.charAt(prefixrandom.length - 2)
+				+ prefixrandom.charAt(prefixrandom.length - 1);
+		var tohash = data;
+		tohash += String.fromCharCode(0xD3);
+		tohash += String.fromCharCode(0x14);
+		util.print_debug_hexstr_dump("data to be hashed:"
+				, prefix + tohash);
+		tohash += str_sha1(prefix + tohash);
+		util.print_debug_hexstr_dump("hash:"
+				, tohash.substring(tohash.length - 20,
+						tohash.length));
+		var result = openpgp_crypto_symmetricEncrypt(prefixrandom,
+				symmetric_algorithm, key, tohash, false).substring(0,
+				prefix.length + tohash.length);
+		var header = openpgp_packet.write_packet_header(18, result.length + 1)
+				+ String.fromCharCode(1);
+		this.encryptedData = result;
+		return header + result;
+	}
+
+	/**
+	 * Decrypts the encrypted data contained in this object read_packet must
+	 * have been called before
+	 * 
+	 * @param {Integer} symmetric_algorithm_type
+	 *            The selected symmetric encryption algorithm to be used
+	 * @param {String} key The key of cipher blocksize length to be used
+	 * @return {String} The decrypted data of this packet
+	 */
+	function decrypt(symmetric_algorithm_type, key) {
+		this.decryptedData = openpgp_crypto_symmetricDecrypt(
+				symmetric_algorithm_type, key, this.encryptedData, false);
+		// there must be a modification detection code packet as the
+		// last packet and everything gets hashed except the hash itself
+		this.hash = str_sha1(openpgp_crypto_MDCSystemBytes(
+				symmetric_algorithm_type, key, this.encryptedData)
+				+ this.decryptedData.substring(0,
+						this.decryptedData.length - 20));
+		util.print_debug_hexstr_dump("calc hash = ", this.hash);
+		if (this.hash == this.decryptedData.substring(
+				this.decryptedData.length - 20, this.decryptedData.length))
+			return this.decryptedData;
+		else
+			util
+					.print_error("Decryption stopped: discovered a modification of encrypted data.");
+		return null;
+	}
+
+	function toString() {
+	    var data = '';
+	    if(openpgp.config.debug)
+	        data = '    data: Bytes ['
+				+ util.hexstrdump(this.encryptedData) + ']';
+	    
+		return '5.13.  Sym. Encrypted Integrity Protected Data Packet (Tag 18)\n'
+				+ '    length:  '
+				+ this.packetLength
+				+ '\n'
+				+ '    version: '
+				+ this.version
+				+ '\n'
+				+ data;
+	}
+
+	this.write_packet = write_packet;
+	this.read_packet = read_packet;
+	this.toString = toString;
+	this.decrypt = decrypt;
+};
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.packet.encryptedsessionkey.js.html b/doc/openpgp.packet.encryptedsessionkey.js.html new file mode 100644 index 00000000..38d36d77 --- /dev/null +++ b/doc/openpgp.packet.encryptedsessionkey.js.html @@ -0,0 +1,275 @@ + + + + + JSDoc: Source: packet/openpgp.packet.encryptedsessionkey.js + + + + + + + + + + +
+ +

Source: packet/openpgp.packet.encryptedsessionkey.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * @class
+ * @classdesc Public-Key Encrypted Session Key Packets (Tag 1)
+ * 
+ * RFC4880 5.1: A Public-Key Encrypted Session Key packet holds the session key
+ * used to encrypt a message. Zero or more Public-Key Encrypted Session Key
+ * packets and/or Symmetric-Key Encrypted Session Key packets may precede a
+ * Symmetrically Encrypted Data Packet, which holds an encrypted message. The
+ * message is encrypted with the session key, and the session key is itself
+ * encrypted and stored in the Encrypted Session Key packet(s). The
+ * Symmetrically Encrypted Data Packet is preceded by one Public-Key Encrypted
+ * Session Key packet for each OpenPGP key to which the message is encrypted.
+ * The recipient of the message finds a session key that is encrypted to their
+ * public key, decrypts the session key, and then uses the session key to
+ * decrypt the message.
+ */
+function openpgp_packet_encryptedsessionkey() {
+
+	/**
+	 * Parsing function for a publickey encrypted session key packet (tag 1).
+	 * 
+	 * @param {String} input Payload of a tag 1 packet
+	 * @param {Integer} position Position to start reading from the input string
+	 * @param {Integer} len Length of the packet or the remaining length of
+	 *            input at position
+	 * @return {openpgp_packet_encrypteddata} Object representation
+	 */
+	function read_pub_key_packet(input, position, len) {
+		this.tagType = 1;
+		this.packetLength = len;
+		var mypos = position;
+		if (len < 10) {
+			util
+					.print_error("openpgp.packet.encryptedsessionkey.js\n" + 'invalid length');
+			return null;
+		}
+
+		this.version = input[mypos++].charCodeAt();
+		this.keyId = new openpgp_type_keyid();
+		this.keyId.read_packet(input, mypos);
+		mypos += 8;
+		this.publicKeyAlgorithmUsed = input[mypos++].charCodeAt();
+
+		switch (this.publicKeyAlgorithmUsed) {
+		case 1:
+		case 2: // RSA
+			this.MPIs = new Array();
+			this.MPIs[0] = new openpgp_type_mpi();
+			this.MPIs[0].read(input, mypos, mypos - position);
+			break;
+		case 16: // Elgamal
+			this.MPIs = new Array();
+			this.MPIs[0] = new openpgp_type_mpi();
+			this.MPIs[0].read(input, mypos, mypos - position);
+			mypos += this.MPIs[0].packetLength;
+			this.MPIs[1] = new openpgp_type_mpi();
+			this.MPIs[1].read(input, mypos, mypos - position);
+			break;
+		default:
+			util.print_error("openpgp.packet.encryptedsessionkey.js\n"
+					+ "unknown public key packet algorithm type "
+					+ this.publicKeyAlgorithmType);
+			break;
+		}
+		return this;
+	}
+
+	/**
+	 * Create a string representation of a tag 1 packet
+	 * 
+	 * @param {String} publicKeyId
+	 *             The public key id corresponding to publicMPIs key as string
+	 * @param {openpgp_type_mpi[]} publicMPIs
+	 *            Multiprecision integer objects describing the public key
+	 * @param {Integer} pubalgo
+	 *            The corresponding public key algorithm // See RFC4880 9.1
+	 * @param {Integer} symmalgo
+	 *            The symmetric cipher algorithm used to encrypt the data 
+	 *            within an encrypteddatapacket or encryptedintegrity-
+	 *            protecteddatapacket 
+	 *            following this packet //See RFC4880 9.2
+	 * @param {String} sessionkey
+	 *            A string of randombytes representing the session key
+	 * @return {String} The string representation
+	 */
+	function write_pub_key_packet(publicKeyId, publicMPIs, pubalgo, symmalgo,
+			sessionkey) {
+		var result = String.fromCharCode(3);
+		var data = String.fromCharCode(symmalgo);
+		data += sessionkey;
+		var checksum = util.calc_checksum(sessionkey);
+		data += String.fromCharCode((checksum >> 8) & 0xFF);
+		data += String.fromCharCode((checksum) & 0xFF);
+		result += publicKeyId;
+		result += String.fromCharCode(pubalgo);
+		var mpi = new openpgp_type_mpi();
+		var mpiresult = openpgp_crypto_asymetricEncrypt(pubalgo, publicMPIs,
+				mpi.create(openpgp_encoding_eme_pkcs1_encode(data,
+						publicMPIs[0].mpiByteLength)));
+		for ( var i = 0; i < mpiresult.length; i++) {
+			result += mpiresult[i];
+		}
+		result = openpgp_packet.write_packet_header(1, result.length) + result;
+		return result;
+	}
+
+	/**
+	 * Parsing function for a symmetric encrypted session key packet (tag 3).
+	 * 
+	 * @param {String} input Payload of a tag 1 packet
+	 * @param {Integer} position Position to start reading from the input string
+	 * @param {Integer} len
+	 *            Length of the packet or the remaining length of
+	 *            input at position
+	 * @return {openpgp_packet_encrypteddata} Object representation
+	 */
+	function read_symmetric_key_packet(input, position, len) {
+		this.tagType = 3;
+		var mypos = position;
+		// A one-octet version number. The only currently defined version is 4.
+		this.version = input[mypos++];
+
+		// A one-octet number describing the symmetric algorithm used.
+		this.symmetricKeyAlgorithmUsed = input[mypos++];
+		// A string-to-key (S2K) specifier, length as defined above.
+		this.s2k = new openpgp_type_s2k();
+		this.s2k.read(input, mypos);
+
+		// Optionally, the encrypted session key itself, which is decrypted
+		// with the string-to-key object.
+		if ((s2k.s2kLength + mypos) < len) {
+			this.encryptedSessionKey = new Array();
+			for ( var i = (mypos - position); i < len; i++) {
+				this.encryptedSessionKey[i] = input[mypos++];
+			}
+		}
+		return this;
+	}
+	/**
+	 * Decrypts the session key (only for public key encrypted session key
+	 * packets (tag 1)
+	 * 
+	 * @param {openpgp_msg_message} msg
+	 *            The message object (with member encryptedData
+	 * @param {openpgp_msg_privatekey} key
+	 *            Private key with secMPIs unlocked
+	 * @return {String} The unencrypted session key
+	 */
+	function decrypt(msg, key) {
+		if (this.tagType == 1) {
+			var result = openpgp_crypto_asymetricDecrypt(
+					this.publicKeyAlgorithmUsed, key.publicKey.MPIs,
+					key.secMPIs, this.MPIs).toMPI();
+			var checksum = ((result.charCodeAt(result.length - 2) << 8) + result
+					.charCodeAt(result.length - 1));
+			var decoded = openpgp_encoding_eme_pkcs1_decode(result.substring(2, result.length - 2), key.publicKey.MPIs[0].getByteLength());
+			var sesskey = decoded.substring(1);
+			var algo = decoded.charCodeAt(0);
+			if (msg.encryptedData.tagType == 18)
+				return msg.encryptedData.decrypt(algo, sesskey);
+			else
+				return msg.encryptedData.decrypt_sym(algo, sesskey);
+		} else if (this.tagType == 3) {
+			util
+					.print_error("Symmetric encrypted sessionkey is not supported!");
+			return null;
+		}
+	}
+
+	/**
+	 * Creates a string representation of this object (useful for debug
+	 * purposes)
+	 * 
+	 * @return {String} The string containing a openpgp description
+	 */
+	function toString() {
+		if (this.tagType == 1) {
+			var result = '5.1.  Public-Key Encrypted Session Key Packets (Tag 1)\n'
+					+ '    KeyId:  '
+					+ this.keyId.toString()
+					+ '\n'
+					+ '    length: '
+					+ this.packetLength
+					+ '\n'
+					+ '    version:'
+					+ this.version
+					+ '\n'
+					+ '    pubAlgUs:'
+					+ this.publicKeyAlgorithmUsed + '\n';
+			for ( var i = 0; i < this.MPIs.length; i++) {
+				result += this.MPIs[i].toString();
+			}
+			return result;
+		} else
+			return '5.3 Symmetric-Key Encrypted Session Key Packets (Tag 3)\n'
+					+ '    KeyId:  ' + this.keyId.toString() + '\n'
+					+ '    length: ' + this.packetLength + '\n'
+					+ '    version:' + this.version + '\n' + '    symKeyA:'
+					+ this.symmetricKeyAlgorithmUsed + '\n' + '    s2k:    '
+					+ this.s2k + '\n';
+	}
+
+	this.read_pub_key_packet = read_pub_key_packet;
+	this.read_symmetric_key_packet = read_symmetric_key_packet;
+	this.write_pub_key_packet = write_pub_key_packet;
+	this.toString = toString;
+	this.decrypt = decrypt;
+};
+
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.packet.js.html b/doc/openpgp.packet.js.html new file mode 100644 index 00000000..e72d44f0 --- /dev/null +++ b/doc/openpgp.packet.js.html @@ -0,0 +1,456 @@ + + + + + JSDoc: Source: packet/openpgp.packet.js + + + + + + + + + + +
+ +

Source: packet/openpgp.packet.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * @class
+ * @classdesc Parent openpgp packet class. Operations focus on determining 
+ * packet types and packet header.
+ */
+function _openpgp_packet() {
+	/**
+	 * Encodes a given integer of length to the openpgp length specifier to a
+	 * string
+	 * 
+	 * @param {Integer} length The length to encode
+	 * @return {String} String with openpgp length representation
+	 */
+	function encode_length(length) {
+		result = "";
+		if (length < 192) {
+			result += String.fromCharCode(length);
+		} else if (length > 191 && length < 8384) {
+			/*
+			 * let a = (total data packet length) - 192 let bc = two octet
+			 * representation of a let d = b + 192
+			 */
+			result += String.fromCharCode(((length - 192) >> 8) + 192);
+			result += String.fromCharCode((length - 192) & 0xFF);
+		} else {
+			result += String.fromCharCode(255);
+			result += String.fromCharCode((length >> 24) & 0xFF);
+			result += String.fromCharCode((length >> 16) & 0xFF);
+			result += String.fromCharCode((length >> 8) & 0xFF);
+			result += String.fromCharCode(length & 0xFF);
+		}
+		return result;
+	}
+	this.encode_length = encode_length;
+
+	/**
+	 * Writes a packet header version 4 with the given tag_type and length to a
+	 * string
+	 * 
+	 * @param {Integer} tag_type Tag type
+	 * @param {Integer} length Length of the payload
+	 * @return {String} String of the header
+	 */
+	function write_packet_header(tag_type, length) {
+		/* we're only generating v4 packet headers here */
+		var result = "";
+		result += String.fromCharCode(0xC0 | tag_type);
+		result += encode_length(length);
+		return result;
+	}
+
+	/**
+	 * Writes a packet header Version 3 with the given tag_type and length to a
+	 * string
+	 * 
+	 * @param {Integer} tag_type Tag type
+	 * @param {Integer} length Length of the payload
+	 * @return {String} String of the header
+	 */
+	function write_old_packet_header(tag_type, length) {
+		var result = "";
+		if (length < 256) {
+			result += String.fromCharCode(0x80 | (tag_type << 2));
+			result += String.fromCharCode(length);
+		} else if (length < 65536) {
+			result += String.fromCharCode(0x80 | (tag_type << 2) | 1);
+			result += String.fromCharCode(length >> 8);
+			result += String.fromCharCode(length & 0xFF);
+		} else {
+			result += String.fromCharCode(0x80 | (tag_type << 2) | 2);
+			result += String.fromCharCode((length >> 24) & 0xFF);
+			result += String.fromCharCode((length >> 16) & 0xFF);
+			result += String.fromCharCode((length >> 8) & 0xFF);
+			result += String.fromCharCode(length & 0xFF);
+		}
+		return result;
+	}
+	this.write_old_packet_header = write_old_packet_header;
+	this.write_packet_header = write_packet_header;
+	/**
+	 * Generic static Packet Parser function
+	 * 
+	 * @param {String} input Input stream as string
+	 * @param {integer} position Position to start parsing
+	 * @param {integer} len Length of the input from position on
+	 * @return {Object} Returns a parsed openpgp_packet
+	 */
+	function read_packet(input, position, len) {
+		// some sanity checks
+		if (input == null || input.length <= position
+				|| input.substring(position).length < 2
+				|| (input[position].charCodeAt() & 0x80) == 0) {
+			util
+					.print_error("Error during parsing. This message / key is probably not containing a valid OpenPGP format.");
+			return null;
+		}
+		var mypos = position;
+		var tag = -1;
+		var format = -1;
+
+		format = 0; // 0 = old format; 1 = new format
+		if ((input[mypos].charCodeAt() & 0x40) != 0) {
+			format = 1;
+		}
+
+		var packet_length_type;
+		if (format) {
+			// new format header
+			tag = input[mypos].charCodeAt() & 0x3F; // bit 5-0
+		} else {
+			// old format header
+			tag = (input[mypos].charCodeAt() & 0x3F) >> 2; // bit 5-2
+			packet_length_type = input[mypos].charCodeAt() & 0x03; // bit 1-0
+		}
+
+		// header octet parsing done
+		mypos++;
+
+		// parsed length from length field
+		var bodydata = null;
+
+		// used for partial body lengths
+		var real_packet_length = -1;
+		if (!format) {
+			// 4.2.1. Old Format Packet Lengths
+			switch (packet_length_type) {
+			case 0: // The packet has a one-octet length. The header is 2 octets
+				// long.
+				packet_length = input[mypos++].charCodeAt();
+				break;
+			case 1: // The packet has a two-octet length. The header is 3 octets
+				// long.
+				packet_length = (input[mypos++].charCodeAt() << 8)
+						| input[mypos++].charCodeAt();
+				break;
+			case 2: // The packet has a four-octet length. The header is 5
+				// octets long.
+				packet_length = (input[mypos++].charCodeAt() << 24)
+						| (input[mypos++].charCodeAt() << 16)
+						| (input[mypos++].charCodeAt() << 8)
+						| input[mypos++].charCodeAt();
+				break;
+			default:
+				// 3 - The packet is of indeterminate length. The header is 1
+				// octet long, and the implementation must determine how long
+				// the packet is. If the packet is in a file, this means that
+				// the packet extends until the end of the file. In general, 
+				// an implementation SHOULD NOT use indeterminate-length 
+				// packets except where the end of the data will be clear 
+				// from the context, and even then it is better to use a 
+				// definite length, or a new format header. The new format 
+				// headers described below have a mechanism for precisely
+				// encoding data of indeterminate length.
+				packet_length = len;
+				break;
+			}
+
+		} else // 4.2.2. New Format Packet Lengths
+		{
+
+			// 4.2.2.1. One-Octet Lengths
+			if (input[mypos].charCodeAt() < 192) {
+				packet_length = input[mypos++].charCodeAt();
+				util.print_debug("1 byte length:" + packet_length);
+				// 4.2.2.2. Two-Octet Lengths
+			} else if (input[mypos].charCodeAt() >= 192
+					&& input[mypos].charCodeAt() < 224) {
+				packet_length = ((input[mypos++].charCodeAt() - 192) << 8)
+						+ (input[mypos++].charCodeAt()) + 192;
+				util.print_debug("2 byte length:" + packet_length);
+				// 4.2.2.4. Partial Body Lengths
+			} else if (input[mypos].charCodeAt() > 223
+					&& input[mypos].charCodeAt() < 255) {
+				packet_length = 1 << (input[mypos++].charCodeAt() & 0x1F);
+				util.print_debug("4 byte length:" + packet_length);
+				// EEEK, we're reading the full data here...
+				var mypos2 = mypos + packet_length;
+				bodydata = input.substring(mypos, mypos + packet_length);
+				while (true) {
+					if (input[mypos2].charCodeAt() < 192) {
+						var tmplen = input[mypos2++].charCodeAt();
+						packet_length += tmplen;
+						bodydata += input.substring(mypos2, mypos2 + tmplen);
+						mypos2 += tmplen;
+						break;
+					} else if (input[mypos2].charCodeAt() >= 192
+							&& input[mypos2].charCodeAt() < 224) {
+						var tmplen = ((input[mypos2++].charCodeAt() - 192) << 8)
+								+ (input[mypos2++].charCodeAt()) + 192;
+						packet_length += tmplen;
+						bodydata += input.substring(mypos2, mypos2 + tmplen);
+						mypos2 += tmplen;
+						break;
+					} else if (input[mypos2].charCodeAt() > 223
+							&& input[mypos2].charCodeAt() < 255) {
+						var tmplen = 1 << (input[mypos2++].charCodeAt() & 0x1F);
+						packet_length += tmplen;
+						bodydata += input.substring(mypos2, mypos2 + tmplen);
+						mypos2 += tmplen;
+					} else {
+						mypos2++;
+						var tmplen = (input[mypos2++].charCodeAt() << 24)
+								| (input[mypos2++].charCodeAt() << 16)
+								| (input[mypos2++].charCodeAt() << 8)
+								| input[mypos2++].charCodeAt();
+						bodydata += input.substring(mypos2, mypos2 + tmplen);
+						packet_length += tmplen;
+						mypos2 += tmplen;
+						break;
+					}
+				}
+				real_packet_length = mypos2;
+				// 4.2.2.3. Five-Octet Lengths
+			} else {
+				mypos++;
+				packet_length = (input[mypos++].charCodeAt() << 24)
+						| (input[mypos++].charCodeAt() << 16)
+						| (input[mypos++].charCodeAt() << 8)
+						| input[mypos++].charCodeAt();
+			}
+		}
+
+		// if there was'nt a partial body length: use the specified
+		// packet_length
+		if (real_packet_length == -1) {
+			real_packet_length = packet_length;
+		}
+
+		if (bodydata == null) {
+			bodydata = input.substring(mypos, mypos + real_packet_length);
+		}
+
+		// alert('tag type: '+this.tag+' length: '+packet_length);
+		var version = 1; // (old format; 2= new format)
+		// if (input[mypos++].charCodeAt() > 15)
+		// version = 2;
+
+		switch (tag) {
+		case 0: // Reserved - a packet tag MUST NOT have this value
+			break;
+		case 1: // Public-Key Encrypted Session Key Packet
+			var result = new openpgp_packet_encryptedsessionkey();
+			if (result.read_pub_key_packet(bodydata, 0, packet_length) != null) {
+				result.headerLength = mypos - position;
+				result.packetLength = real_packet_length;
+				return result;
+			}
+			break;
+		case 2: // Signature Packet
+			var result = new openpgp_packet_signature();
+			if (result.read_packet(bodydata, 0, packet_length) != null) {
+				result.headerLength = mypos - position;
+				result.packetLength = real_packet_length;
+				return result;
+			}
+			break;
+		case 3: // Symmetric-Key Encrypted Session Key Packet
+			var result = new openpgp_packet_encryptedsessionkey();
+			if (result.read_symmetric_key_packet(bodydata, 0, packet_length) != null) {
+				result.headerLength = mypos - position;
+				result.packetLength = real_packet_length;
+				return result;
+			}
+			break;
+		case 4: // One-Pass Signature Packet
+			var result = new openpgp_packet_onepasssignature();
+			if (result.read_packet(bodydata, 0, packet_length)) {
+				result.headerLength = mypos - position;
+				result.packetLength = real_packet_length;
+				return result;
+			}
+			break;
+		case 5: // Secret-Key Packet
+			var result = new openpgp_packet_keymaterial();
+			result.header = input.substring(position, mypos);
+			if (result.read_tag5(bodydata, 0, packet_length) != null) {
+				result.headerLength = mypos - position;
+				result.packetLength = real_packet_length;
+				return result;
+			}
+			break;
+		case 6: // Public-Key Packet
+			var result = new openpgp_packet_keymaterial();
+			result.header = input.substring(position, mypos);
+			if (result.read_tag6(bodydata, 0, packet_length) != null) {
+				result.headerLength = mypos - position;
+				result.packetLength = real_packet_length;
+				return result;
+			}
+			break;
+		case 7: // Secret-Subkey Packet
+			var result = new openpgp_packet_keymaterial();
+			if (result.read_tag7(bodydata, 0, packet_length) != null) {
+				result.headerLength = mypos - position;
+				result.packetLength = real_packet_length;
+				return result;
+			}
+			break;
+		case 8: // Compressed Data Packet
+			var result = new openpgp_packet_compressed();
+			if (result.read_packet(bodydata, 0, packet_length) != null) {
+				result.headerLength = mypos - position;
+				result.packetLength = real_packet_length;
+				return result;
+			}
+			break;
+		case 9: // Symmetrically Encrypted Data Packet
+			var result = new openpgp_packet_encrypteddata();
+			if (result.read_packet(bodydata, 0, packet_length) != null) {
+				result.headerLength = mypos - position;
+				result.packetLength = real_packet_length;
+				return result;
+			}
+			break;
+		case 10: // Marker Packet = PGP (0x50, 0x47, 0x50)
+			var result = new openpgp_packet_marker();
+			if (result.read_packet(bodydata, 0, packet_length) != null) {
+				result.headerLength = mypos - position;
+				result.packetLength = real_packet_length;
+				return result;
+			}
+			break;
+		case 11: // Literal Data Packet
+			var result = new openpgp_packet_literaldata();
+			if (result.read_packet(bodydata, 0, packet_length) != null) {
+				result.headerLength = mypos - position;
+				result.header = input.substring(position, mypos);
+				result.packetLength = real_packet_length;
+				return result;
+			}
+			break;
+		case 12: // Trust Packet
+			// TODO: to be implemented
+			break;
+		case 13: // User ID Packet
+			var result = new openpgp_packet_userid();
+			if (result.read_packet(bodydata, 0, packet_length) != null) {
+				result.headerLength = mypos - position;
+				result.packetLength = real_packet_length;
+				return result;
+			}
+			break;
+		case 14: // Public-Subkey Packet
+			var result = new openpgp_packet_keymaterial();
+			result.header = input.substring(position, mypos);
+			if (result.read_tag14(bodydata, 0, packet_length) != null) {
+				result.headerLength = mypos - position;
+				result.packetLength = real_packet_length;
+				return result;
+			}
+			break;
+		case 17: // User Attribute Packet
+			var result = new openpgp_packet_userattribute();
+			if (result.read_packet(bodydata, 0, packet_length) != null) {
+				result.headerLength = mypos - position;
+				result.packetLength = real_packet_length;
+				return result;
+			}
+			break;
+		case 18: // Sym. Encrypted and Integrity Protected Data Packet
+			var result = new openpgp_packet_encryptedintegrityprotecteddata();
+			if (result.read_packet(bodydata, 0, packet_length) != null) {
+				result.headerLength = mypos - position;
+				result.packetLength = real_packet_length;
+				return result;
+			}
+			break;
+		case 19: // Modification Detection Code Packet
+			var result = new openpgp_packet_modificationdetectioncode();
+			if (result.read_packet(bodydata, 0, packet_length) != null) {
+				result.headerLength = mypos - position;
+				result.packetLength = real_packet_length;
+				return result;
+			}
+			break;
+		default:
+			util.print_error("openpgp.packet.js\n"
+					+ "[ERROR] openpgp_packet: failed to parse packet @:"
+					+ mypos + "\nchar:'"
+					+ util.hexstrdump(input.substring(mypos)) + "'\ninput:"
+					+ util.hexstrdump(input));
+			return null;
+			break;
+		}
+	}
+
+	this.read_packet = read_packet;
+}
+
+var openpgp_packet = new _openpgp_packet();
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.packet.keymaterial.js.html b/doc/openpgp.packet.keymaterial.js.html new file mode 100644 index 00000000..9c0e6e5a --- /dev/null +++ b/doc/openpgp.packet.keymaterial.js.html @@ -0,0 +1,868 @@ + + + + + JSDoc: Source: packet/openpgp.packet.keymaterial.js + + + + + + + + + + +
+ +

Source: packet/openpgp.packet.keymaterial.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * @class
+ * @classdesc Implementation of the Key Material Packet (Tag 5,6,7,14)
+ *   
+ * RFC4480 5.5:
+ * A key material packet contains all the information about a public or
+ * private key.  There are four variants of this packet type, and two
+ * major versions.  Consequently, this section is complex.
+ */
+function openpgp_packet_keymaterial() {
+	// members:
+	this.publicKeyAlgorithm = null;
+	this.tagType = null;
+	this.creationTime = null;
+	this.version = null;
+	this.expiration  = null;// V3
+	this.MPIs = null;
+	this.secMPIs = null;
+	this.publicKey = null;
+	this.symmetricEncryptionAlgorithm = null;
+	this.s2kUsageConventions = null;
+	this.IVLength  = null;
+    this.encryptedMPIData = null;
+    this.hasUnencryptedSecretKeyData = null;
+    this.checksum = null;
+    this.parentNode = null;
+	this.subKeySignature = null;
+	this.subKeyRevocationSignature = null;
+
+	// 5.5.1. Key Packet Variants
+	
+	// 5.5.1.3. Secret-Key Packet (Tag 5)
+	/**
+	 * This function reads the payload of a secret key packet (Tag 5)
+	 * and initializes the openpgp_packet_keymaterial
+	 * @param {String} input Input string to read the packet from
+	 * @param {Integer} position Start position for the parser
+	 * @param {Intefer} len Length of the packet or remaining length of input
+	 * @return {openpgp_packet_keymaterial}
+	 */
+	function read_tag5(input, position, len) {
+		this.tagType = 5;
+		this.read_priv_key(input, position, len);
+		return this;
+	}
+
+	// 5.5.1.1. Public-Key Packet (Tag 6)
+	/**
+	 * This function reads the payload of a public key packet (Tag 6)
+	 * and initializes the openpgp_packet_keymaterial
+	 * @param {String} input Input string to read the packet from
+	 * @param {Integer} position Start position for the parser
+	 * @param {Integer} len Length of the packet or remaining length of input
+	 * @return {openpgp_packet_keymaterial}
+	 */
+	function read_tag6(input, position, len) {
+		// A Public-Key packet starts a series of packets that forms an OpenPGP
+		// key (sometimes called an OpenPGP certificate).
+		this.tagType = 6;
+		this.packetLength = len;
+		this.read_pub_key(input, position,len);
+		
+		return this;
+	}
+
+	// 5.5.1.4. Secret-Subkey Packet (Tag 7)
+	/**
+	 * This function reads the payload of a secret key sub packet (Tag 7)
+	 * and initializes the openpgp_packet_keymaterial
+	 * @param {String} input Input string to read the packet from
+	 * @param {Integer} position Start position for the parser
+	 * @param {Integer} len Length of the packet or remaining length of input
+	 * @return {openpgp_packet_keymaterial}
+	 */
+	function read_tag7(input, position, len) {
+		this.tagType = 7;
+		this.packetLength = len;
+		return this.read_priv_key(input, position, len);
+	}
+
+	// 5.5.1.2. Public-Subkey Packet (Tag 14)
+	/**
+	 * This function reads the payload of a public key sub packet (Tag 14)
+	 * and initializes the openpgp_packet_keymaterial
+	 * @param {String} input Input string to read the packet from
+	 * @param {Integer} position Start position for the parser
+	 * @param {Integer} len Length of the packet or remaining length of input
+	 * @return {openpgp_packet_keymaterial}
+	 */
+	function read_tag14(input, position, len) {
+		this.subKeySignature = null;
+		this.subKeyRevocationSignature = new Array();
+		this.tagType = 14;
+		this.packetLength = len;
+		this.read_pub_key(input, position,len);
+		return this;
+	}
+	
+	/**
+	 * Internal Parser for public keys as specified in RFC 4880 section 
+	 * 5.5.2 Public-Key Packet Formats
+	 * called by read_tag<num>
+	 * @param {String} input Input string to read the packet from
+	 * @param {Integer} position Start position for the parser
+	 * @param {Integer} len Length of the packet or remaining length of input
+	 * @return {Object} This object with attributes set by the parser
+	 */  
+	function read_pub_key(input, position, len) {
+		var mypos = position;
+		// A one-octet version number (3 or 4).
+		this.version = input[mypos++].charCodeAt();
+		if (this.version == 3) {
+			// A four-octet number denoting the time that the key was created.
+			this.creationTime = new Date(((input[mypos++].charCodeAt() << 24) |
+				(input[mypos++].charCodeAt() << 16) |
+				(input[mypos++].charCodeAt() <<  8) |
+				(input[mypos++].charCodeAt()))*1000);
+			
+		    // - A two-octet number denoting the time in days that this key is
+		    //   valid.  If this number is zero, then it does not expire.
+			this.expiration = (input[mypos++].charCodeAt() << 8) & input[mypos++].charCodeAt();
+	
+		    // - A one-octet number denoting the public-key algorithm of this key.
+			this.publicKeyAlgorithm = input[mypos++].charCodeAt();
+			var mpicount = 0;
+		    // - A series of multiprecision integers comprising the key material:
+			//   Algorithm-Specific Fields for RSA public keys:
+		    //       - a multiprecision integer (MPI) of RSA public modulus n;
+		    //       - an MPI of RSA public encryption exponent e.
+			if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4)
+				mpicount = 2;
+			//   Algorithm-Specific Fields for Elgamal public keys:
+			//     - MPI of Elgamal prime p;
+			//     - MPI of Elgamal group generator g;
+			//     - MPI of Elgamal public key value y (= g**x mod p where x  is secret).
+
+			else if (this.publicKeyAlgorithm == 16)
+				mpicount = 3;
+			//   Algorithm-Specific Fields for DSA public keys:
+			//       - MPI of DSA prime p;
+			//       - MPI of DSA group order q (q is a prime divisor of p-1);
+			//       - MPI of DSA group generator g;
+			//       - MPI of DSA public-key value y (= g**x mod p where x  is secret).
+			else if (this.publicKeyAlgorithm == 17)
+				mpicount = 4;
+
+			this.MPIs = new Array();
+			for (var i = 0; i < mpicount; i++) {
+				this.MPIs[i] = new openpgp_type_mpi();
+				if (this.MPIs[i].read(input, mypos, (mypos-position)) != null && 
+						!this.packetLength < (mypos-position)) {
+					mypos += this.MPIs[i].packetLength;
+				} else {
+					util.print_error("openpgp.packet.keymaterial.js\n"+'error reading MPI @:'+mypos);
+				}
+			}
+			this.packetLength = mypos-position;
+		} else if (this.version == 4) {
+			// - A four-octet number denoting the time that the key was created.
+			this.creationTime = new Date(((input[mypos++].charCodeAt() << 24) |
+			(input[mypos++].charCodeAt() << 16) |
+			(input[mypos++].charCodeAt() <<  8) |
+			(input[mypos++].charCodeAt()))*1000);
+			
+			// - A one-octet number denoting the public-key algorithm of this key.
+			this.publicKeyAlgorithm = input[mypos++].charCodeAt();
+			var mpicount = 0;
+		    // - A series of multiprecision integers comprising the key material:
+			//   Algorithm-Specific Fields for RSA public keys:
+		    //       - a multiprecision integer (MPI) of RSA public modulus n;
+		    //       - an MPI of RSA public encryption exponent e.
+			if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4)
+					mpicount = 2;
+			//   Algorithm-Specific Fields for Elgamal public keys:
+			//     - MPI of Elgamal prime p;
+			//     - MPI of Elgamal group generator g;
+			//     - MPI of Elgamal public key value y (= g**x mod p where x  is secret).
+			else if (this.publicKeyAlgorithm == 16)
+				mpicount = 3;
+
+			//   Algorithm-Specific Fields for DSA public keys:
+			//       - MPI of DSA prime p;
+			//       - MPI of DSA group order q (q is a prime divisor of p-1);
+			//       - MPI of DSA group generator g;
+			//       - MPI of DSA public-key value y (= g**x mod p where x  is secret).
+			else if (this.publicKeyAlgorithm == 17)
+				mpicount = 4;
+
+			this.MPIs = new Array();
+			var i = 0;
+			for (var i = 0; i < mpicount; i++) {
+				this.MPIs[i] = new openpgp_type_mpi();
+				if (this.MPIs[i].read(input, mypos, (mypos-position)) != null &&
+						!this.packetLength < (mypos-position)) {
+					mypos += this.MPIs[i].packetLength;
+				} else {
+					util.print_error("openpgp.packet.keymaterial.js\n"+'error reading MPI @:'+mypos);
+				}
+			}
+			this.packetLength = mypos-position;
+		} else {
+			return null;
+		}
+		this.data = input.substring(position, mypos);
+		this.packetdata = input.substring(position, mypos);
+		return this;
+	}
+	
+	// 5.5.3.  Secret-Key Packet Formats
+	
+	/**
+	 * Internal parser for private keys as specified in RFC 4880 section 5.5.3
+	 * @param {String} input Input string to read the packet from
+	 * @param {Integer} position Start position for the parser
+	 * @param {Integer} len Length of the packet or remaining length of input
+	 * @return {Object} This object with attributes set by the parser
+	 */
+	function read_priv_key(input,position, len) {
+	    // - A Public-Key or Public-Subkey packet, as described above.
+	    this.publicKey = new openpgp_packet_keymaterial();
+		if (this.publicKey.read_pub_key(input,position, len) == null) {
+			util.print_error("openpgp.packet.keymaterial.js\n"+"Failed reading public key portion of a private key: "+input[position].charCodeAt()+" "+position+" "+len+"\n Aborting here...");
+			return null;
+		}
+		this.publicKey.header = openpgp_packet.write_old_packet_header(6,this.publicKey.packetLength);
+		// this.publicKey.header = String.fromCharCode(0x99) + String.fromCharCode(this.publicKey.packetLength >> 8 & 0xFF)+String.fromCharCode(this.publicKey.packetLength & 0xFF);
+		var mypos = position + this.publicKey.data.length;
+		this.packetLength = len;
+		
+	    // - One octet indicating string-to-key usage conventions.  Zero
+	    //   indicates that the secret-key data is not encrypted.  255 or 254
+	    //   indicates that a string-to-key specifier is being given.  Any
+	    //   other value is a symmetric-key encryption algorithm identifier.
+	    this.s2kUsageConventions = input[mypos++].charCodeAt();
+	    
+	    if (this.s2kUsageConventions == 0)
+	    	this.hasUnencryptedSecretKeyData = true;
+	   
+	    // - [Optional] If string-to-key usage octet was 255 or 254, a one-
+	    //   octet symmetric encryption algorithm.
+	    if (this.s2kUsageConventions == 255 || this.s2kUsageConventions == 254) {
+	    	this.symmetricEncryptionAlgorithm = input[mypos++].charCodeAt();
+	    }
+	     
+	    // - [Optional] If string-to-key usage octet was 255 or 254, a
+	    //   string-to-key specifier.  The length of the string-to-key
+	    //   specifier is implied by its type, as described above.
+	    if (this.s2kUsageConventions == 255 || this.s2kUsageConventions == 254) {
+	    	this.s2k = new openpgp_type_s2k();
+	    	this.s2k.read(input, mypos);
+	    	mypos +=this.s2k.s2kLength;
+	    }
+	    
+	    // - [Optional] If secret data is encrypted (string-to-key usage octet
+	    //   not zero), an Initial Vector (IV) of the same length as the
+	    //   cipher's block size.
+	    this.symkeylength = 0;
+	    if (this.s2kUsageConventions != 0 && this.s2kUsageConventions != 255 &&
+	    		this.s2kUsageConventions != 254) {
+	    	this.symmetricEncryptionAlgorithm = this.s2kUsageConventions;
+	    }
+	    if (this.s2kUsageConventions != 0 && this.s2k.type != 1001) {
+	    	this.hasIV = true;
+	    	switch (this.symmetricEncryptionAlgorithm) {
+		    case  1: // - IDEA [IDEA]
+		    	util.print_error("openpgp.packet.keymaterial.js\n"+"symmetric encrytryption algorithim: IDEA is not implemented");
+		    	return null;
+	    	case  2: // - TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
+	    	case  3: // - CAST5 (128 bit key, as per [RFC2144])
+	    		this.IVLength = 8;
+		    	break;
+		    case  4: // - Blowfish (128 bit key, 16 rounds) [BLOWFISH]
+		    case  7: // - AES with 128-bit key [AES]
+	    	case  8: // - AES with 192-bit key
+	    	case  9: // - AES with 256-bit key
+	    		this.IVLength = 16;
+		    	break;
+	    	case 10: // - Twofish with 256-bit key [TWOFISH]
+	    		this.IVLength = 32;	    		
+		    	break;
+	    	case  5: // - Reserved
+	    	case  6: // - Reserved
+	    	default:
+	    		util.print_error("openpgp.packet.keymaterial.js\n"+"unknown encryption algorithm for secret key :"+this.symmetricEncryptionAlgorithm);
+	    		return null;
+	    	}
+	    	mypos++; 
+	    	this.IV = input.substring(mypos, mypos+this.IVLength);
+	    	mypos += this.IVLength;
+	    }
+	    // - Plain or encrypted multiprecision integers comprising the secret
+	    //   key data.  These algorithm-specific fields are as described
+	    //   below.
+
+      // s2k type 1001 corresponds to GPG specific extension without primary key secrets
+      // http://www.gnupg.org/faq/GnuPG-FAQ.html#how-can-i-use-gnupg-in-an-automated-environment
+	    if (this.s2kUsageConventions != 0 && this.s2k.type == 1001) {
+	    	this.secMPIs = null;
+	    	this.encryptedMPIData = null;
+	    } else if (!this.hasUnencryptedSecretKeyData) {
+	    	this.encryptedMPIData = input.substring(mypos, len);
+	    	mypos += this.encryptedMPIData.length;
+	    } else {
+	    	if (this.publicKey.publicKeyAlgorithm > 0 && this.publicKey.publicKeyAlgorithm < 4) {
+	    		//   Algorithm-Specific Fields for RSA secret keys:
+	    		//   - multiprecision integer (MPI) of RSA secret exponent d.
+	    		//   - MPI of RSA secret prime value p.
+	    		//   - MPI of RSA secret prime value q (p < q).
+	    		//   - MPI of u, the multiplicative inverse of p, mod q.
+	    		this.secMPIs = new Array();
+	    		this.secMPIs[0] = new openpgp_type_mpi();
+	    		this.secMPIs[0].read(input, mypos, len-2- (mypos - position));
+	    		mypos += this.secMPIs[0].packetLength;
+	    		this.secMPIs[1] = new openpgp_type_mpi();
+	    		this.secMPIs[1].read(input, mypos, len-2- (mypos - position));
+	    		mypos += this.secMPIs[1].packetLength;
+	    		this.secMPIs[2] = new openpgp_type_mpi();
+	    		this.secMPIs[2].read(input, mypos, len-2- (mypos - position));
+	    		mypos += this.secMPIs[2].packetLength;
+	    		this.secMPIs[3] = new openpgp_type_mpi();
+	    		this.secMPIs[3].read(input, mypos, len-2- (mypos - position));
+	    		mypos += this.secMPIs[3].packetLength;
+	    	} else if (this.publicKey.publicKeyAlgorithm == 16) {
+	    		// Algorithm-Specific Fields for Elgamal secret keys:
+	    		//   - MPI of Elgamal secret exponent x.
+	    		this.secMPIs = new Array();
+	    		this.secMPIs[0] = new openpgp_type_mpi();
+	    		this.secMPIs[0].read(input, mypos, len-2- (mypos - position));
+	    		mypos += this.secMPIs[0].packetLength;
+	    	} else if (this.publicKey.publicKeyAlgorithm == 17) {
+	    		// Algorithm-Specific Fields for DSA secret keys:
+	    		//   - MPI of DSA secret exponent x.
+	    		this.secMPIs = new Array();
+	    		this.secMPIs[0] = new openpgp_type_mpi();
+	    		this.secMPIs[0].read(input, mypos, len-2- (mypos - position));
+	    		mypos += this.secMPIs[0].packetLength;
+	    	}
+	    	// checksum because s2k usage convention is 0
+	        this.checksum = new Array(); 
+		    this.checksum[0] = input[mypos++].charCodeAt();
+		    this.checksum[1] = input[mypos++].charCodeAt();
+	    }
+	    return this;
+	}
+	
+
+	/**
+	 * Decrypts the private key MPIs which are needed to use the key.
+	 * openpgp_packet_keymaterial.hasUnencryptedSecretKeyData should be 
+	 * false otherwise
+	 * a call to this function is not needed
+	 * 
+	 * @param {String} str_passphrase The passphrase for this private key 
+	 * as string
+	 * @return {Boolean} True if the passphrase was correct; false if not
+	 */
+	function decryptSecretMPIs(str_passphrase) {
+		if (this.hasUnencryptedSecretKeyData)
+			return this.secMPIs;
+		// creating a key out of the passphrase
+		var key = this.s2k.produce_key(str_passphrase);
+		var cleartextMPIs = "";
+    	switch (this.symmetricEncryptionAlgorithm) {
+	    case  1: // - IDEA [IDEA]
+	    	util.print_error("openpgp.packet.keymaterial.js\n"+"symmetric encryption algorithim: IDEA is not implemented");
+	    	return false;
+    	case  2: // - TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
+    		cleartextMPIs = normal_cfb_decrypt(function(block, key) {
+    			return des(key, block,1,null,0);
+    		}, this.IVLength, key, this.encryptedMPIData, this.IV);
+    		break;
+    	case  3: // - CAST5 (128 bit key, as per [RFC2144])
+    		cleartextMPIs = normal_cfb_decrypt(function(block, key) {
+        		var cast5 = new openpgp_symenc_cast5();
+        		cast5.setKey(key);
+        		return cast5.encrypt(util.str2bin(block)); 
+    		}, this.IVLength, util.str2bin(key.substring(0,16)), this.encryptedMPIData, this.IV);
+    		break;
+	    case  4: // - Blowfish (128 bit key, 16 rounds) [BLOWFISH]
+	    	cleartextMPIs = normal_cfb_decrypt(function(block, key) {
+    			var blowfish = new Blowfish(key);
+        		return blowfish.encrypt(block); 
+    		}, this.IVLength, key, this.encryptedMPIData, this.IV);
+    		break;
+	    case  7: // - AES with 128-bit key [AES]
+    	case  8: // - AES with 192-bit key
+    	case  9: // - AES with 256-bit key
+    	    var numBytes = 16;
+            //This is a weird way to achieve this. If's within a switch is probably not ideal.
+    	    if(this.symmetricEncryptionAlgorithm == 8){
+    	        numBytes = 24;
+    	        key = this.s2k.produce_key(str_passphrase,numBytes);
+    	    }
+    	    if(this.symmetricEncryptionAlgorithm == 9){
+    	        numBytes = 32;
+    	        key = this.s2k.produce_key(str_passphrase,numBytes);
+    	    }
+    		cleartextMPIs = normal_cfb_decrypt(function(block,key){
+    		    return AESencrypt(util.str2bin(block),key);
+    		},
+    				this.IVLength, keyExpansion(key.substring(0,numBytes)), this.encryptedMPIData, this.IV);
+	    	break;
+    	case 10: // - Twofish with 256-bit key [TWOFISH]
+    		util.print_error("openpgp.packet.keymaterial.js\n"+"Key material is encrypted with twofish: not implemented");   		
+	    	return false;
+    	case  5: // - Reserved
+    	case  6: // - Reserved
+    	default:
+    		util.print_error("openpgp.packet.keymaterial.js\n"+"unknown encryption algorithm for secret key :"+this.symmetricEncryptionAlgorithm);
+    		return false;
+    	}
+    	
+    	if (cleartextMPIs == null) {
+    		util.print_error("openpgp.packet.keymaterial.js\n"+"cleartextMPIs was null");
+    		return false;
+    	}
+    	
+    	var cleartextMPIslength = cleartextMPIs.length;
+
+    	if (this.s2kUsageConventions == 254 &&
+    			str_sha1(cleartextMPIs.substring(0,cleartextMPIs.length - 20)) == 
+    				cleartextMPIs.substring(cleartextMPIs.length - 20)) {
+    		cleartextMPIslength -= 20;
+    	} else if (this.s2kUsageConventions != 254 && util.calc_checksum(cleartextMPIs.substring(0,cleartextMPIs.length - 2)) == 
+    			(cleartextMPIs.charCodeAt(cleartextMPIs.length -2) << 8 | cleartextMPIs.charCodeAt(cleartextMPIs.length -1))) {
+    		cleartextMPIslength -= 2;
+    	} else {
+    		return false;
+    	}
+
+    	if (this.publicKey.publicKeyAlgorithm > 0 && this.publicKey.publicKeyAlgorithm < 4) {
+    		//   Algorithm-Specific Fields for RSA secret keys:
+    		//   - multiprecision integer (MPI) of RSA secret exponent d.
+    		//   - MPI of RSA secret prime value p.
+    		//   - MPI of RSA secret prime value q (p < q).
+    		//   - MPI of u, the multiplicative inverse of p, mod q.
+    		var mypos = 0;
+    		this.secMPIs = new Array();
+    		this.secMPIs[0] = new openpgp_type_mpi();
+    		this.secMPIs[0].read(cleartextMPIs, 0, cleartextMPIslength);
+    		mypos += this.secMPIs[0].packetLength;
+    		this.secMPIs[1] = new openpgp_type_mpi();
+    		this.secMPIs[1].read(cleartextMPIs, mypos, cleartextMPIslength-mypos);
+    		mypos += this.secMPIs[1].packetLength;
+    		this.secMPIs[2] = new openpgp_type_mpi();
+    		this.secMPIs[2].read(cleartextMPIs, mypos, cleartextMPIslength-mypos);
+    		mypos += this.secMPIs[2].packetLength;
+    		this.secMPIs[3] = new openpgp_type_mpi();
+    		this.secMPIs[3].read(cleartextMPIs, mypos, cleartextMPIslength-mypos);
+    		mypos += this.secMPIs[3].packetLength;
+    	} else if (this.publicKey.publicKeyAlgorithm == 16) {
+    		// Algorithm-Specific Fields for Elgamal secret keys:
+    		//   - MPI of Elgamal secret exponent x.
+    		this.secMPIs = new Array();
+    		this.secMPIs[0] = new openpgp_type_mpi();
+    		this.secMPIs[0].read(cleartextMPIs, 0, cleartextMPIs);
+    	} else if (this.publicKey.publicKeyAlgorithm == 17) {
+    		// Algorithm-Specific Fields for DSA secret keys:
+    		//   - MPI of DSA secret exponent x.
+    		this.secMPIs = new Array();
+    		this.secMPIs[0] = new openpgp_type_mpi();
+    		this.secMPIs[0].read(cleartextMPIs, 0, cleartextMPIslength);
+    	}
+    	return true;
+	}
+	
+	/**
+	 * Generates Debug output
+	 * @return String which gives some information about the keymaterial
+	 */
+	function toString() {
+		var result = "";
+		switch (this.tagType) {
+		case 6:
+			 result += '5.5.1.1. Public-Key Packet (Tag 6)\n'+
+			   '    length:             '+this.packetLength+'\n'+
+			   '    version:            '+this.version+'\n'+
+			   '    creation time:      '+this.creationTime+'\n'+
+			   '    expiration time:    '+this.expiration+'\n'+
+			   '    publicKeyAlgorithm: '+this.publicKeyAlgorithm+'\n';
+			break;
+		case 14:
+			result += '5.5.1.2. Public-Subkey Packet (Tag 14)\n'+
+			   '    length:             '+this.packetLength+'\n'+
+			   '    version:            '+this.version+'\n'+
+			   '    creation time:      '+this.creationTime+'\n'+
+			   '    expiration time:    '+this.expiration+'\n'+
+			   '    publicKeyAlgorithm: '+this.publicKeyAlgorithm+'\n';
+			break;
+		case 5:
+			result +='5.5.1.3. Secret-Key Packet (Tag 5)\n'+
+			   '    length:             '+this.packetLength+'\n'+
+			   '    version:            '+this.publicKey.version+'\n'+
+			   '    creation time:      '+this.publicKey.creationTime+'\n'+
+			   '    expiration time:    '+this.publicKey.expiration+'\n'+
+			   '    publicKeyAlgorithm: '+this.publicKey.publicKeyAlgorithm+'\n';
+			break;
+		case 7:
+			result += '5.5.1.4. Secret-Subkey Packet (Tag 7)\n'+
+			   '    length:             '+this.packetLength+'\n'+
+			   '    version[1]:         '+(this.version == 4)+'\n'+
+			   '    creationtime[4]:    '+this.creationTime+'\n'+
+			   '    expiration[2]:      '+this.expiration+'\n'+
+			   '    publicKeyAlgorithm: '+this.publicKeyAlgorithm+'\n';
+			break;
+		default:
+			result += 'unknown key material packet\n';
+		}
+		if (this.MPIs != null) {
+			result += "Public Key MPIs:\n";
+			for (var i = 0; i < this.MPIs.length; i++) {
+      	  	result += this.MPIs[i].toString();
+        	}
+		}
+		if (this.publicKey != null && this.publicKey.MPIs != null) {
+			result += "Public Key MPIs:\n";
+			for (var i = 0; i < this.publicKey.MPIs.length; i++) {
+	      	  	result += this.publicKey.MPIs[i].toString();
+        	}
+		}
+		if (this.secMPIs != null) {
+			result += "Secret Key MPIs:\n";
+			for (var i = 0; i < this.secMPIs.length; i++) {
+		      	  result += this.secMPIs[i].toString();
+		        }
+		}
+		
+		if (this.subKeySignature != null)
+			result += "subKey Signature:\n"+this.subKeySignature.toString();
+		
+		if (this.subKeyRevocationSignature != null )
+			result += "subKey Revocation Signature:\n"+this.subKeyRevocationSignature.toString();
+        return result;
+	}
+	
+	/**
+	 * Continue parsing packets belonging to the key material such as signatures
+	 * @param {Object} parent_node The parent object
+	 * @param {String} input Input string to read the packet(s) from
+	 * @param {Integer} position Start position for the parser
+	 * @param {Integer} len Length of the packet(s) or remaining length of input
+	 * @return {Integer} Length of nodes read
+	 */
+	function read_nodes(parent_node, input, position, len) {
+		this.parentNode = parent_node;
+		if (this.tagType == 14) { // public sub-key packet
+			var pos = position;
+			var result = null;
+			while (input.length != pos) {
+				var l = input.length - pos;
+				result = openpgp_packet.read_packet(input, pos, l);
+				if (result == null) {
+					util.print_error("openpgp.packet.keymaterial.js\n"+'[user_keymat_pub]parsing ends here @:' + pos + " l:" + l);
+					break;
+				} else {
+					
+					switch (result.tagType) {
+					case 2: // Signature Packet certification signature
+						if (result.signatureType == 24)  { // subkey binding signature
+							this.subKeySignature = result;
+							pos += result.packetLength + result.headerLength;
+							break;
+						} else if (result.signatureType == 40) { // subkey revocation signature
+							this.subKeyRevocationSignature[this.subKeyRevocationSignature.length] = result;
+							pos += result.packetLength + result.headerLength;
+							break;
+						} else {
+							util.print_error("openpgp.packet.keymaterial.js\nunknown signature:"+result.toString());
+						}
+						
+					default:
+						this.data = input;
+						this.position = position - this.parentNode.packetLength;
+						this.len = pos - position;
+						return this.len;
+						break;
+					}
+				}
+			}
+			this.data = input;
+			this.position = position - this.parentNode.packetLength;
+			this.len = pos - position;
+			return this.len;
+		} else if (this.tagType == 7) { // private sub-key packet
+			var pos = position;
+			while (input.length != pos) {
+				var result = openpgp_packet.read_packet(input, pos, len - (pos - position));
+				if (result == null) {
+					util.print_error("openpgp.packet.keymaterial.js\n"+'[user_keymat_priv] parsing ends here @:' + pos);
+					break;
+				} else {
+					switch (result.tagType) {
+					case 2: // Signature Packet certification signature
+						if (result.signatureType == 24) // subkey embedded signature
+							this.subKeySignature = result; 
+						else if (result.signatureType == 40) // subkey revocation signature
+							this.subKeyRevocationSignature[this.subKeyRevocationSignature.length] = result;
+						pos += result.packetLength + result.headerLength;
+						break;
+					default:
+						this.data = input;
+						this.position = position - this.parentNode.packetLength;
+						this.len = pos - position;
+						return this.len;
+					}
+				}
+			}
+			this.data = input;
+			this.position = position - this.parentNode.packetLength;
+			this.len = pos - position;
+			return this.len;
+		} else {
+			util.print_error("openpgp.packet.keymaterial.js\n"+"unknown parent node for a key material packet "+parent_node.tagType);
+		}
+	}
+
+	/**
+	 * Checks the validity for usage of this (sub)key
+	 * @return {Integer} 0 = bad key, 1 = expired, 2 = revoked, 3 = valid
+	 */
+	function verifyKey() {
+		if (this.tagType == 14) {
+			if (this.subKeySignature == null) {
+				return 0;
+			}
+			if (this.subKeySignature.version == 4 &&
+				this.subKeySignature.keyNeverExpires != null &&
+				!this.subKeySignature.keyNeverExpires &&
+				new Date((this.subKeySignature.keyExpirationTime*1000)+ this.creationTime.getTime()) < new Date()) {
+				    return 1;
+				}
+			var hashdata = String.fromCharCode(0x99)+this.parentNode.header.substring(1)+this.parentNode.data+
+			String.fromCharCode(0x99)+this.header.substring(1)+this.packetdata;
+			if (!this.subKeySignature.verify(hashdata,this.parentNode)) {
+				return 0;
+			}
+			for (var i = 0; i < this.subKeyRevocationSignature.length; i++) {
+			    if (this.getKeyId() == this.subKeyRevocationSignature[i].keyId){
+			        return 2;
+			    }
+			}
+		}
+		return 3;
+	}
+
+	/**
+	 * Calculates the key id of they key 
+	 * @return {String} A 8 byte key id
+	 */
+	function getKeyId() {
+		if (this.version == 4) {
+			var f = this.getFingerprint();
+			return f.substring(12,20);
+		} else if (this.version == 3 && this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4) {
+			var key_id = this.MPIs[0].substring((this.MPIs[0].mpiByteLength-8));
+			util.print_debug("openpgp.msg.publickey read_nodes:\n"+"V3 key ID: "+key_id);
+			return key_id;
+		}
+	}
+	
+	/**
+	 * Calculates the fingerprint of the key
+	 * @return {String} A string containing the fingerprint
+	 */
+	function getFingerprint() {
+		if (this.version == 4) {
+			tohash = String.fromCharCode(0x99)+ String.fromCharCode(((this.packetdata.length) >> 8) & 0xFF) 
+				+ String.fromCharCode((this.packetdata.length) & 0xFF)+this.packetdata;
+			util.print_debug("openpgp.msg.publickey creating subkey fingerprint by hashing:"+util.hexstrdump(tohash)+"\npublickeyalgorithm: "+this.publicKeyAlgorithm);
+			return str_sha1(tohash, tohash.length);
+		} else if (this.version == 3 && this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4) {
+			return MD5(this.MPIs[0].MPI);
+		}
+	}
+	
+	/*
+     * Creates an OpenPGP key packet for the given key. much 
+	 * TODO in regards to s2k, subkeys.
+     * @param {Integer} keyType Follows the OpenPGP algorithm standard, 
+	 * IE 1 corresponds to RSA.
+     * @param {RSA.keyObject} key
+     * @param password
+     * @param s2kHash
+     * @param symmetricEncryptionAlgorithm
+     * @param timePacket
+     * @return {Object} {body: [string]OpenPGP packet body contents, 
+		header: [string] OpenPGP packet header, string: [string] header+body}
+     */
+    function write_private_key(keyType, key, password, s2kHash, symmetricEncryptionAlgorithm, timePacket){
+        this.symmetricEncryptionAlgorithm = symmetricEncryptionAlgorithm;
+		var tag = 5;
+		var body = String.fromCharCode(4);
+		body += timePacket;
+		switch(keyType){
+		case 1:
+		    body += String.fromCharCode(keyType);//public key algo
+		    body += key.n.toMPI();
+		    body += key.ee.toMPI();
+		    var algorithmStart = body.length;
+		    //below shows ske/s2k
+		    if(password){
+		        body += String.fromCharCode(254); //octet of 254 indicates s2k with SHA1
+		        //if s2k == 255,254 then 1 octet symmetric encryption algo
+		        body += String.fromCharCode(this.symmetricEncryptionAlgorithm);
+		        //if s2k == 255,254 then s2k specifier
+		        body += String.fromCharCode(3); //s2k salt+iter
+		        body += String.fromCharCode(s2kHash);
+		        //8 octet salt value
+		        //1 octet count
+		        var cleartextMPIs = key.d.toMPI() + key.p.toMPI() + key.q.toMPI() + key.u.toMPI();
+		        var sha1Hash = str_sha1(cleartextMPIs);
+   		        util.print_debug_hexstr_dump('write_private_key sha1: ',sha1Hash);
+		        var salt = openpgp_crypto_getRandomBytes(8);
+		        util.print_debug_hexstr_dump('write_private_key Salt: ',salt);
+		        body += salt;
+		        var c = 96; //c of 96 translates to count of 65536
+		        body += String.fromCharCode(c);
+		        util.print_debug('write_private_key c: '+ c);
+		        var s2k = new openpgp_type_s2k();
+		        var hashKey = s2k.write(3, s2kHash, password, salt, c);
+		        //if s2k, IV of same length as cipher's block
+		        switch(this.symmetricEncryptionAlgorithm){
+		        case 3:
+		            this.IVLength = 8;
+		            this.IV = openpgp_crypto_getRandomBytes(this.IVLength);
+            		ciphertextMPIs = normal_cfb_encrypt(function(block, key) {
+                		var cast5 = new openpgp_symenc_cast5();
+                		cast5.setKey(key);
+                		return cast5.encrypt(util.str2bin(block)); 
+            		}, this.IVLength, util.str2bin(hashKey.substring(0,16)), cleartextMPIs + sha1Hash, this.IV);
+            		body += this.IV + ciphertextMPIs;
+		            break;
+		        case 7:
+		        case 8:
+		        case 9:
+		            this.IVLength = 16;
+		            this.IV = openpgp_crypto_getRandomBytes(this.IVLength);
+		            ciphertextMPIs = normal_cfb_encrypt(AESencrypt,
+            				this.IVLength, hashKey, cleartextMPIs + sha1Hash, this.IV);
+            		body += this.IV + ciphertextMPIs;
+	            	break;
+		        }
+		    }
+		    else{
+		        body += String.fromCharCode(0);//1 octet -- s2k, 0 for no s2k
+		        body += key.d.toMPI() + key.p.toMPI() + key.q.toMPI() + key.u.toMPI();
+		        var checksum = util.calc_checksum(key.d.toMPI() + key.p.toMPI() + key.q.toMPI() + key.u.toMPI());
+        		body += String.fromCharCode(checksum/0x100) + String.fromCharCode(checksum%0x100);//DEPRECATED:s2k == 0, 255: 2 octet checksum, sum all octets%65536
+        		util.print_debug_hexstr_dump('write_private_key basic checksum: '+ checksum);
+		    }
+		    break;
+		default :
+			body = "";
+			util.print_error("openpgp.packet.keymaterial.js\n"+'error writing private key, unknown type :'+keyType);
+        }
+		var header = openpgp_packet.write_packet_header(tag,body.length);
+		return {string: header+body , header: header, body: body};
+    }
+	
+	/*
+     * Same as write_private_key, but has less information because of 
+	 * public key.
+     * @param {Integer} keyType Follows the OpenPGP algorithm standard, 
+	 * IE 1 corresponds to RSA.
+     * @param {RSA.keyObject} key
+     * @param timePacket
+     * @return {Object} {body: [string]OpenPGP packet body contents, 
+	 * header: [string] OpenPGP packet header, string: [string] header+body}
+     */
+    function write_public_key(keyType, key, timePacket){
+        var tag = 6;
+        var body = String.fromCharCode(4);
+        body += timePacket;
+		switch(keyType){
+		case 1:
+		    body += String.fromCharCode(1);//public key algo
+		    body += key.n.toMPI();
+		    body += key.ee.toMPI();
+		    break;
+	    default:
+	    	util.print_error("openpgp.packet.keymaterial.js\n"+'error writing private key, unknown type :'+keyType);
+	    }
+        var header = openpgp_packet.write_packet_header(tag,body.length);
+        return {string: header+body , header: header, body: body};
+        }
+
+	
+	this.read_tag5 = read_tag5;
+	this.read_tag6 = read_tag6;
+	this.read_tag7 = read_tag7;
+	this.read_tag14 = read_tag14;
+	this.toString = toString;
+	this.read_pub_key = read_pub_key;
+	this.read_priv_key = read_priv_key;
+	this.decryptSecretMPIs = decryptSecretMPIs;
+	this.read_nodes = read_nodes;
+	this.verifyKey = verifyKey;
+	this.getKeyId = getKeyId;
+	this.getFingerprint = getFingerprint;
+	this.write_private_key = write_private_key;
+	this.write_public_key = write_public_key;
+}
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.packet.literaldata.js.html b/doc/openpgp.packet.literaldata.js.html new file mode 100644 index 00000000..01f9a199 --- /dev/null +++ b/doc/openpgp.packet.literaldata.js.html @@ -0,0 +1,147 @@ + + + + + JSDoc: Source: packet/openpgp.packet.literaldata.js + + + + + + + + + + +
+ +

Source: packet/openpgp.packet.literaldata.js

+ + + + + +
+
+
// 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 Literal Data Packet (Tag 11)
+ * 
+ * RFC4880 5.9: A Literal Data packet contains the body of a message; data that
+ * is not to be further interpreted.
+ */
+function openpgp_packet_literaldata() {
+	this.tagType = 11;
+
+	/**
+	 * Parsing function for a literal data packet (tag 11).
+	 * 
+	 * @param {String} input Payload of a tag 11 packet
+	 * @param {Integer} position
+	 *            Position to start reading from the input string
+	 * @param {Integer} len
+	 *            Length of the packet or the remaining length of
+	 *            input at position
+	 * @return {openpgp_packet_encrypteddata} object representation
+	 */
+	function read_packet(input, position, len) {
+		this.packetLength = len;
+		// - A one-octet field that describes how the data is formatted.
+
+		this.format = input[position];
+		this.filename = input.substr(position + 2, input
+				.charCodeAt(position + 1));
+		this.date = new Date(parseInt(input.substr(position + 2
+				+ input.charCodeAt(position + 1), 4)) * 1000);
+		this.data = input.substring(position + 6
+				+ input.charCodeAt(position + 1));
+		return this;
+	}
+
+	/**
+	 * Creates a string representation of the packet
+	 * 
+	 * @param {String} data The data to be inserted as body
+	 * @return {String} string-representation of the packet
+	 */
+	function write_packet(data) {
+		data = data.replace(/\r\n/g, "\n").replace(/\n/g, "\r\n");
+		this.filename = "msg.txt";
+		this.date = new Date();
+		this.format = 't';
+		var result = openpgp_packet.write_packet_header(11, data.length + 6
+				+ this.filename.length);
+		result += this.format;
+		result += String.fromCharCode(this.filename.length);
+		result += this.filename;
+		result += String
+				.fromCharCode((Math.round(this.date.getTime() / 1000) >> 24) & 0xFF);
+		result += String
+				.fromCharCode((Math.round(this.date.getTime() / 1000) >> 16) & 0xFF);
+		result += String
+				.fromCharCode((Math.round(this.date.getTime() / 1000) >> 8) & 0xFF);
+		result += String
+				.fromCharCode(Math.round(this.date.getTime() / 1000) & 0xFF);
+		result += data;
+		this.data = data;
+		return result;
+	}
+
+	/**
+	 * Generates debug output (pretty print)
+	 * 
+	 * @return {String} String which gives some information about the keymaterial
+	 */
+	function toString() {
+		return '5.9.  Literal Data Packet (Tag 11)\n' + '    length: '
+				+ this.packetLength + '\n' + '    format: ' + this.format
+				+ '\n' + '    filename:' + this.filename + '\n'
+				+ '    date:   ' + this.date + '\n' + '    data:  |'
+				+ this.data + '|\n' + '    rdata: |' + this.real_data + '|\n';
+	}
+
+	this.read_packet = read_packet;
+	this.toString = toString;
+	this.write_packet = write_packet;
+}
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.packet.marker.js.html b/doc/openpgp.packet.marker.js.html new file mode 100644 index 00000000..532e5f43 --- /dev/null +++ b/doc/openpgp.packet.marker.js.html @@ -0,0 +1,114 @@ + + + + + JSDoc: Source: packet/openpgp.packet.marker.js + + + + + + + + + + +
+ +

Source: packet/openpgp.packet.marker.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * @class
+ * @classdesc Implementation of the strange "Marker packet" (Tag 10)
+ * 
+ * RFC4880 5.8: An experimental version of PGP used this packet as the Literal
+ * packet, but no released version of PGP generated Literal packets with this
+ * tag. With PGP 5.x, this packet has been reassigned and is reserved for use as
+ * the Marker packet.
+ * 
+ * Such a packet MUST be ignored when received.
+ */
+function openpgp_packet_marker() {
+	this.tagType = 10;
+	/**
+	 * Parsing function for a literal data packet (tag 10).
+	 * 
+	 * @param {String} input Payload of a tag 10 packet
+	 * @param {Integer} position
+	 *            Position to start reading from the input string
+	 * @param {Integer} len
+	 *            Length of the packet or the remaining length of
+	 *            input at position
+	 * @return {openpgp_packet_encrypteddata} Object representation
+	 */
+	function read_packet(input, position, len) {
+		this.packetLength = 3;
+		if (input[position].charCodeAt() == 0x50 && // P
+				input[position + 1].charCodeAt() == 0x47 && // G
+				input[position + 2].charCodeAt() == 0x50) // P
+			return this;
+		// marker packet does not contain "PGP"
+		return null;
+	}
+
+	/**
+	 * Generates Debug output
+	 * 
+	 * @return {String} String which gives some information about the 
+	 * keymaterial
+	 */
+	function toString() {
+		return "5.8.  Marker Packet (Obsolete Literal Packet) (Tag 10)\n"
+				+ "     packet reads: \"PGP\"\n";
+	}
+
+	this.read_packet = read_packet;
+	this.toString = toString;
+}
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.packet.modificationdetectioncode.js.html b/doc/openpgp.packet.modificationdetectioncode.js.html new file mode 100644 index 00000000..7704a34e --- /dev/null +++ b/doc/openpgp.packet.modificationdetectioncode.js.html @@ -0,0 +1,128 @@ + + + + + JSDoc: Source: packet/openpgp.packet.modificationdetectioncode.js + + + + + + + + + + +
+ +

Source: packet/openpgp.packet.modificationdetectioncode.js

+ + + + + +
+
+
// 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 Modification Detection Code Packet (Tag 19)
+ * 
+ * RFC4880 5.14: The Modification Detection Code packet contains a SHA-1 hash of
+ * plaintext data, which is used to detect message modification. It is only used
+ * with a Symmetrically Encrypted Integrity Protected Data packet. The
+ * Modification Detection Code packet MUST be the last packet in the plaintext
+ * data that is encrypted in the Symmetrically Encrypted Integrity Protected
+ * Data packet, and MUST appear in no other place.
+ */
+
+function openpgp_packet_modificationdetectioncode() {
+	this.tagType = 19;
+	this.hash = null;
+	/**
+	 * parsing function for a modification detection code packet (tag 19).
+	 * 
+	 * @param {String} input payload of a tag 19 packet
+	 * @param {Integer} position
+	 *            position to start reading from the input string
+	 * @param {Integer} len
+	 *            length of the packet or the remaining length of
+	 *            input at position
+	 * @return {openpgp_packet_encrypteddata} object representation
+	 */
+	function read_packet(input, position, len) {
+		this.packetLength = len;
+
+		if (len != 20) {
+			util
+					.print_error("openpgp.packet.modificationdetectioncode.js\n"
+							+ 'invalid length for a modification detection code packet!'
+							+ len);
+			return null;
+		}
+		// - A 20-octet SHA-1 hash of the preceding plaintext data of the
+		// Symmetrically Encrypted Integrity Protected Data packet,
+		// including prefix data, the tag octet, and length octet of the
+		// Modification Detection Code packet.
+		this.hash = input.substring(position, position + 20);
+		return this;
+	}
+
+	/*
+	 * this packet is created within the encryptedintegrityprotected packet
+	 * function write_packet(data) { }
+	 */
+
+	/**
+	 * generates debug output (pretty print)
+	 * 
+	 * @return {String} String which gives some information about the 
+	 * modification detection code
+	 */
+	function toString() {
+		return '5.14 Modification detection code packet\n' + '    bytes ('
+				+ this.hash.length + '): [' + util.hexstrdump(this.hash) + ']';
+	}
+	this.read_packet = read_packet;
+	this.toString = toString;
+};
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.packet.onepasssignature.js.html b/doc/openpgp.packet.onepasssignature.js.html new file mode 100644 index 00000000..0a0a6e80 --- /dev/null +++ b/doc/openpgp.packet.onepasssignature.js.html @@ -0,0 +1,168 @@ + + + + + JSDoc: Source: packet/openpgp.packet.onepasssignature.js + + + + + + + + + + +
+ +

Source: packet/openpgp.packet.onepasssignature.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * @class
+ * @classdesc Implementation of the One-Pass Signature Packets (Tag 4)
+ * 
+ * RFC4880 5.4:
+ * The One-Pass Signature packet precedes the signed data and contains
+ * enough information to allow the receiver to begin calculating any
+ * hashes needed to verify the signature.  It allows the Signature
+ * packet to be placed at the end of the message, so that the signer
+ * can compute the entire signed message in one pass.
+ */
+function openpgp_packet_onepasssignature() {
+	this.tagType = 4;
+	this.version = null; // A one-octet version number.  The current version is 3.
+	this.type = null; 	 // A one-octet signature type.  Signature types are described in RFC4880 Section 5.2.1.
+	this.hashAlgorithm = null; 	   // A one-octet number describing the hash algorithm used. (See RFC4880 9.4)
+	this.publicKeyAlgorithm = null;	     // A one-octet number describing the public-key algorithm used. (See RFC4880 9.1)
+	this.signingKeyId = null; // An eight-octet number holding the Key ID of the signing key.
+	this.flags = null; 	//  A one-octet number holding a flag showing whether the signature is nested.  A zero value indicates that the next packet is another One-Pass Signature packet that describes another signature to be applied to the same message data.
+
+	/**
+	 * parsing function for a one-pass signature packet (tag 4).
+	 * @param {String} input payload of a tag 4 packet
+	 * @param {Integer} position position to start reading from the input string
+	 * @param {Integer} len length of the packet or the remaining length of input at position
+	 * @return {openpgp_packet_encrypteddata} object representation
+	 */
+	function read_packet(input, position, len) {
+		this.packetLength = len;
+		var mypos = position;
+		// A one-octet version number.  The current version is 3.
+		this.version = input.charCodeAt(mypos++);
+
+	     // A one-octet signature type.  Signature types are described in
+	     //   Section 5.2.1.
+		this.type = input.charCodeAt(mypos++);
+
+	     // A one-octet number describing the hash algorithm used.
+		this.hashAlgorithm = input.charCodeAt(mypos++);
+
+	     // A one-octet number describing the public-key algorithm used.
+		this.publicKeyAlgorithm = input.charCodeAt(mypos++);
+	     // An eight-octet number holding the Key ID of the signing key.
+		this.signingKeyId = new openpgp_type_keyid();
+		this.signingKeyId.read_packet(input,mypos);
+		mypos += 8;
+		
+	     // A one-octet number holding a flag showing whether the signature
+	     //   is nested.  A zero value indicates that the next packet is
+	     //   another One-Pass Signature packet that describes another
+	     //   signature to be applied to the same message data.
+		this.flags = input.charCodeAt(mypos++);
+		return this;
+	}
+
+	/**
+	 * creates a string representation of a one-pass signature packet
+	 * @param {Integer} type Signature types as described in RFC4880 Section 5.2.1.
+	 * @param {Integer} hashalgorithm the hash algorithm used within the signature
+	 * @param {openpgp_msg_privatekey} privatekey the private key used to generate the signature
+	 * @param {Integer} length length of data to be signed
+	 * @param {boolean} nested boolean showing whether the signature is nested. 
+	 *  "true" indicates that the next packet is another One-Pass Signature packet
+	 *   that describes another signature to be applied to the same message data. 
+	 * @return {String} a string representation of a one-pass signature packet
+	 */
+	function write_packet(type, hashalgorithm, privatekey,length, nested) {
+		var result =""; 
+		
+		result += openpgp_packet.write_packet_header(4,13);
+		result += String.fromCharCode(3);
+		result += String.fromCharCode(type);
+		result += String.fromCharCode(hashalgorithm);
+		result += String.fromCharCode(privatekey.privateKeyPacket.publicKey.publicKeyAlgorithm);
+		result += privatekey.getKeyId();
+		if (nested)
+			result += String.fromCharCode(0);
+		else
+			result += String.fromCharCode(1);
+		
+		return result;
+	}
+	
+	/**
+	 * generates debug output (pretty print)
+	 * @return {String} String which gives some information about the one-pass signature packet
+	 */
+	function toString() {
+		return '5.4.  One-Pass Signature Packets (Tag 4)\n'+
+			   '    length: '+this.packetLength+'\n'+
+			   '    type:   '+this.type+'\n'+
+			   '    keyID:  '+this.signingKeyId.toString()+'\n'+
+			   '    hashA:  '+this.hashAlgorithm+'\n'+
+			   '    pubKeyA:'+this.publicKeyAlgorithm+'\n'+
+			   '    flags:  '+this.flags+'\n'+
+			   '    version:'+this.version+'\n';
+	}
+	
+	this.read_packet = read_packet;
+	this.toString = toString;
+	this.write_packet = write_packet;
+};
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.packet.signature.js.html b/doc/openpgp.packet.signature.js.html new file mode 100644 index 00000000..1eb3d54a --- /dev/null +++ b/doc/openpgp.packet.signature.js.html @@ -0,0 +1,778 @@ + + + + + JSDoc: Source: packet/openpgp.packet.signature.js + + + + + + + + + + +
+ +

Source: packet/openpgp.packet.signature.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * @class
+ * @classdesc Implementation of the Signature Packet (Tag 2)
+ * 
+ * RFC4480 5.2:
+ * A Signature packet describes a binding between some public key and
+ * some data.  The most common signatures are a signature of a file or a
+ * block of text, and a signature that is a certification of a User ID.
+ */
+function openpgp_packet_signature() {
+	this.tagType = 2;
+	this.signatureType = null;
+	this.creationTime = null;
+	this.keyId = null;
+	this.signatureData = null;
+	this.signatureExpirationTime = null;
+	this.signatureNeverExpires = null;
+	this.signedHashValue = null;
+	this.MPIs = null;
+	this.publicKeyAlgorithm = null; 
+	this.hashAlgorithm = null;
+	this.exportable = null;
+	this.trustLevel = null;
+	this.trustAmount = null;
+	this.regular_expression = null;
+	this.revocable = null;
+	this.keyExpirationTime = null;
+	this.keyNeverExpires = null;
+	this.preferredSymmetricAlgorithms = null;
+	this.revocationKeyClass = null;
+	this.revocationKeyAlgorithm = null;
+	this.revocationKeyFingerprint = null;
+	this.issuerKeyId = null;
+	this.notationFlags = null; 
+	this.notationName = null;
+	this.notationValue = null;
+	this.preferredHashAlgorithms = null;
+	this.preferredCompressionAlgorithms = null;
+	this.keyServerPreferences = null;
+	this.preferredKeyServer = null;
+	this.isPrimaryUserID = null;
+	this.policyURI = null;
+	this.keyFlags = null;
+	this.signersUserId = null;
+	this.reasonForRevocationFlag = null;
+	this.reasonForRevocationString = null;
+	this.signatureTargetPublicKeyAlgorithm = null;
+	this.signatureTargetHashAlgorithm = null;
+	this.signatureTargetHash = null;
+	this.embeddedSignature = null;
+	this.verified = false;
+	
+
+	/**
+	 * parsing function for a signature packet (tag 2).
+	 * @param {String} input payload of a tag 2 packet
+	 * @param {Integer} position position to start reading from the input string
+	 * @param {Integer} len length of the packet or the remaining length of input at position
+	 * @return {openpgp_packet_encrypteddata} object representation
+	 */
+	function read_packet(input, position, len) {
+		this.data = input.substring	(position, position+len);
+		if (len < 0) {
+			util.print_debug("openpgp.packet.signature.js\n"+"openpgp_packet_signature read_packet length < 0 @:"+position);
+			return null;
+		}
+		var mypos = position;
+		this.packetLength = len;
+		// alert('starting parsing signature: '+position+' '+this.packetLength);
+		this.version = input[mypos++].charCodeAt();
+		// switch on version (3 and 4)
+		switch (this.version) {
+		case 3:
+			// One-octet length of following hashed material. MUST be 5.
+			if (input[mypos++].charCodeAt() != 5)
+				util.print_debug("openpgp.packet.signature.js\n"+'invalid One-octet length of following hashed material.  MUST be 5. @:'+(mypos-1));
+			var sigpos = mypos;
+			// One-octet signature type.
+			this.signatureType = input[mypos++].charCodeAt();
+
+			// Four-octet creation time.
+			this.creationTime = new Date(((input[mypos++].charCodeAt()) << 24 |
+					(input[mypos++].charCodeAt() << 16) | (input[mypos++].charCodeAt() << 8) |
+					input[mypos++].charCodeAt())* 1000);
+			
+			// storing data appended to data which gets verified
+			this.signatureData = input.substring(position, mypos);
+			
+			// Eight-octet Key ID of signer.
+			this.keyId = input.substring(mypos, mypos +8);
+			mypos += 8;
+
+			// One-octet public-key algorithm.
+			this.publicKeyAlgorithm = input[mypos++].charCodeAt();
+
+			// One-octet hash algorithm.
+			this.hashAlgorithm = input[mypos++].charCodeAt();
+
+			// Two-octet field holding left 16 bits of signed hash value.
+			this.signedHashValue = (input[mypos++].charCodeAt() << 8) | input[mypos++].charCodeAt();
+			var mpicount = 0;
+			// Algorithm-Specific Fields for RSA signatures:
+			// 	    - multiprecision integer (MPI) of RSA signature value m**d mod n.
+			if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4)
+				mpicount = 1;
+			//    Algorithm-Specific Fields for DSA signatures:
+			//      - MPI of DSA value r.
+			//      - MPI of DSA value s.
+			else if (this.publicKeyAlgorithm == 17)
+				mpicount = 2;
+			
+			this.MPIs = new Array();
+			for (var i = 0; i < mpicount; i++) {
+				this.MPIs[i] = new openpgp_type_mpi();
+				if (this.MPIs[i].read(input, mypos, (mypos-position)) != null && 
+						!this.packetLength < (mypos-position)) {
+					mypos += this.MPIs[i].packetLength;
+				} else {
+			 		util.print_error('signature contains invalid MPI @:'+mypos);
+				}
+			}
+		break;
+		case 4:
+			this.signatureType = input[mypos++].charCodeAt();
+			this.publicKeyAlgorithm = input[mypos++].charCodeAt();
+			this.hashAlgorithm = input[mypos++].charCodeAt();
+
+			// Two-octet scalar octet count for following hashed subpacket
+			// data.
+			var hashed_subpacket_count = (input[mypos++].charCodeAt() << 8) + input[mypos++].charCodeAt();
+
+			// Hashed subpacket data set (zero or more subpackets)
+			var subpacket_length = 0;
+			while (hashed_subpacket_count != subpacket_length) {
+				if (hashed_subpacket_count < subpacket_length) {
+					util.print_debug("openpgp.packet.signature.js\n"+"hashed missed something: "+mypos+" c:"+hashed_subpacket_count+" l:"+subpacket_length);
+				}
+
+				subpacket_length += this._raw_read_signature_sub_packet(input,
+						mypos + subpacket_length, hashed_subpacket_count
+								- subpacket_length);
+			}
+			
+			mypos += hashed_subpacket_count;
+			this.signatureData = input.substring(position, mypos);
+
+			// alert("signatureData: "+util.hexstrdump(this.signatureData));
+			
+			// Two-octet scalar octet count for the following unhashed subpacket
+			var subpacket_count = (input[mypos++].charCodeAt() << 8) + input[mypos++].charCodeAt();
+				
+			// Unhashed subpacket data set (zero or more subpackets).
+			subpacket_length = 0;
+			while (subpacket_count != subpacket_length) {
+				if (subpacket_count < subpacket_length) {
+					util.print_debug("openpgp.packet.signature.js\n"+"missed something: "+subpacket_length+" c:"+subpacket_count+" "+" l:"+subpacket_length);
+				}
+				subpacket_length += this._raw_read_signature_sub_packet(input,
+						mypos + subpacket_length, subpacket_count
+								- subpacket_length);
+
+			}
+			mypos += subpacket_count;
+			// Two-octet field holding the left 16 bits of the signed hash
+			// value.
+			this.signedHashValue = (input[mypos++].charCodeAt() << 8) | input[mypos++].charCodeAt();
+			// One or more multiprecision integers comprising the signature.
+			// This portion is algorithm specific, as described above.
+			var mpicount = 0;
+			if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4)
+				mpicount = 1;
+			else if (this.publicKeyAlgorithm == 17)
+				mpicount = 2;
+			
+			this.MPIs = new Array();
+			for (var i = 0; i < mpicount; i++) {
+				this.MPIs[i] = new openpgp_type_mpi();
+				if (this.MPIs[i].read(input, mypos, (mypos-position)) != null && 
+						!this.packetLength < (mypos-position)) {
+					mypos += this.MPIs[i].packetLength;
+				} else {
+			 		util.print_error('signature contains invalid MPI @:'+mypos);
+				}
+			}
+			break;
+		default:
+			util.print_error("openpgp.packet.signature.js\n"+'unknown signature packet version'+this.version);
+			break;
+		}
+		// util.print_message("openpgp.packet.signature.js\n"+"end signature: l: "+this.packetLength+"m: "+mypos+" m-p: "+(mypos-position));
+		return this;
+	}
+	/**
+	 * creates a string representation of a message signature packet (tag 2).
+	 * This can be only used on text data
+	 * @param {Integer} signature_type should be 1 (one) 
+	 * @param {String} data data to be signed
+	 * @param {openpgp_msg_privatekey} privatekey private key used to sign the message. (secMPIs MUST be unlocked)
+	 * @return {String} string representation of a signature packet
+	 */
+	function write_message_signature(signature_type, data, privatekey) {
+		var publickey = privatekey.privateKeyPacket.publicKey;
+		var hash_algo = privatekey.getPreferredSignatureHashAlgorithm();
+		var result = String.fromCharCode(4); 
+		result += String.fromCharCode(signature_type);
+		result += String.fromCharCode(publickey.publicKeyAlgorithm);
+		result += String.fromCharCode(hash_algo);
+		var d = Math.round(new Date().getTime() / 1000);
+		var datesubpacket = write_sub_signature_packet(2,""+
+				String.fromCharCode((d >> 24) & 0xFF) + 
+				String.fromCharCode((d >> 16) & 0xFF) +
+				String.fromCharCode((d >> 8) & 0xFF) + 
+				String.fromCharCode(d & 0xFF));
+		var issuersubpacket = write_sub_signature_packet(16, privatekey.getKeyId());
+		result += String.fromCharCode(((datesubpacket.length + issuersubpacket.length) >> 8) & 0xFF);
+		result += String.fromCharCode ((datesubpacket.length + issuersubpacket.length) & 0xFF);
+		result += datesubpacket;
+		result += issuersubpacket;
+		var trailer = '';
+		
+		trailer += String.fromCharCode(4);
+		trailer += String.fromCharCode(0xFF);
+		trailer += String.fromCharCode((result.length) >> 24);
+		trailer += String.fromCharCode(((result.length) >> 16) & 0xFF);
+		trailer += String.fromCharCode(((result.length) >> 8) & 0xFF);
+		trailer += String.fromCharCode((result.length) & 0xFF);
+		var result2 = String.fromCharCode(0);
+		result2 += String.fromCharCode(0);
+		var hash = openpgp_crypto_hashData(hash_algo, data+result+trailer);
+		util.print_debug("DSA Signature is calculated with:|"+data+result+trailer+"|\n"+util.hexstrdump(data+result+trailer)+"\n hash:"+util.hexstrdump(hash));
+		result2 += hash.charAt(0);
+		result2 += hash.charAt(1);
+		result2 += openpgp_crypto_signData(hash_algo,privatekey.privateKeyPacket.publicKey.publicKeyAlgorithm,
+				publickey.MPIs,
+				privatekey.privateKeyPacket.secMPIs,
+				data+result+trailer);
+		return {openpgp: (openpgp_packet.write_packet_header(2, (result+result2).length)+result + result2), 
+				hash: util.get_hashAlgorithmString(hash_algo)};
+	}
+	/**
+	 * creates a string representation of a sub signature packet (See RFC 4880 5.2.3.1)
+	 * @param {Integer} type subpacket signature type. Signature types as described in RFC4880 Section 5.2.3.2
+	 * @param {String} data data to be included
+	 * @return {String} a string-representation of a sub signature packet (See RFC 4880 5.2.3.1)
+	 */
+	function write_sub_signature_packet(type, data) {
+		var result = "";
+		result += openpgp_packet.encode_length(data.length+1);
+		result += String.fromCharCode(type);
+		result += data;
+		return result;
+	}
+	
+	// V4 signature sub packets
+	
+	this._raw_read_signature_sub_packet = function(input, position, len) {
+		if (len < 0)
+			util.print_debug("openpgp.packet.signature.js\n"+"_raw_read_signature_sub_packet length < 0 @:"+position);
+		var mypos = position;
+		var subplen = 0;
+		// alert('starting signature subpackage read at position:'+position+' length:'+len);
+		if (input[mypos].charCodeAt() < 192) {
+			subplen = input[mypos++].charCodeAt();
+		} else if (input[mypos].charCodeAt() >= 192 && input[mypos].charCodeAt() < 224) {
+			subplen = ((input[mypos++].charCodeAt() - 192) << 8) + (input[mypos++].charCodeAt()) + 192;
+		} else if (input[mypos].charCodeAt() > 223 && input[mypos].charCodeAt() < 255) {
+			subplen = 1 << (input[mypos++].charCodeAt() & 0x1F);
+		} else if (input[mypos].charCodeAt() < 255) {
+			mypos++;
+			subplen = (input[mypos++].charCodeAt() << 24) | (input[mypos++].charCodeAt() << 16)
+					|  (input[mypos++].charCodeAt() << 8) |  input[mypos++].charCodeAt();
+		}
+		
+		var type = input[mypos++].charCodeAt() & 0x7F;
+		// alert('signature subpacket type '+type+" with length: "+subplen);
+		// subpacket type
+		switch (type) {
+		case 2: // Signature Creation Time
+			this.creationTime = new Date(((input[mypos++].charCodeAt() << 24) | (input[mypos++].charCodeAt() << 16)
+					| (input[mypos++].charCodeAt() << 8) | input[mypos++].charCodeAt())*1000);
+			break;
+		case 3: // Signature Expiration Time
+			this.signatureExpirationTime =  (input[mypos++].charCodeAt() << 24)
+					| (input[mypos++].charCodeAt() << 16) | (input[mypos++].charCodeAt() << 8)
+					| input[mypos++].charCodeAt();
+			this.signatureNeverExpires = (this.signature_expiration_time == 0);
+			
+			break;
+		case 4: // Exportable Certification
+			this.exportable = input[mypos++].charCodeAt() == 1;
+			break;
+		case 5: // Trust Signature
+			this.trustLevel = input[mypos++].charCodeAt();
+			this.trustAmount = input[mypos++].charCodeAt();
+			break;
+		case 6: // Regular Expression
+			this.regular_expression = new String();
+			for (var i = 0; i < subplen - 1; i++)
+				this.regular_expression += (input[mypos++]);
+			break;
+		case 7: // Revocable
+			this.revocable = input[mypos++].charCodeAt() == 1;
+			break;
+		case 9: // Key Expiration Time
+			this.keyExpirationTime = (input[mypos++].charCodeAt() << 24)
+					| (input[mypos++].charCodeAt() << 16) | (input[mypos++].charCodeAt() << 8)
+					| input[mypos++].charCodeAt();
+			this.keyNeverExpires = (this.keyExpirationTime == 0);
+			break;
+		case 11: // Preferred Symmetric Algorithms
+			this.preferredSymmetricAlgorithms = new Array();
+			for (var i = 0; i < subplen-1; i++) {
+				this.preferredSymmetricAlgorithms = input[mypos++].charCodeAt();
+			}
+			break;
+		case 12: // Revocation Key
+			// (1 octet of class, 1 octet of public-key algorithm ID, 20
+			// octets of
+			// fingerprint)
+			this.revocationKeyClass = input[mypos++].charCodeAt();
+			this.revocationKeyAlgorithm = input[mypos++].charCodeAt();
+			this.revocationKeyFingerprint = new Array();
+			for ( var i = 0; i < 20; i++) {
+				this.revocationKeyFingerprint = input[mypos++].charCodeAt();
+			}
+			break;
+		case 16: // Issuer
+			this.issuerKeyId = input.substring(mypos,mypos+8);
+			mypos += 8;
+			break;
+		case 20: // Notation Data
+			this.notationFlags = (input[mypos++].charCodeAt() << 24) | 
+								 (input[mypos++].charCodeAt() << 16) |
+								 (input[mypos++].charCodeAt() <<  8) | 
+								 (input[mypos++].charCodeAt());
+			var nameLength = (input[mypos++].charCodeAt() <<  8) | (input[mypos++].charCodeAt());
+			var valueLength = (input[mypos++].charCodeAt() <<  8) | (input[mypos++].charCodeAt());
+			this.notationName = "";
+			for (var i = 0; i < nameLength; i++) {
+				this.notationName += input[mypos++];
+			}
+			this.notationValue = "";
+			for (var i = 0; i < valueLength; i++) {
+				this.notationValue += input[mypos++];
+			}
+			break;
+		case 21: // Preferred Hash Algorithms
+			this.preferredHashAlgorithms = new Array();
+			for (var i = 0; i < subplen-1; i++) {
+				this.preferredHashAlgorithms = input[mypos++].charCodeAt();
+			}
+			break;
+		case 22: // Preferred Compression Algorithms
+			this.preferredCompressionAlgorithms = new Array();
+			for ( var i = 0; i < subplen-1; i++) {
+				this.preferredCompressionAlgorithms = input[mypos++].charCodeAt();
+			}
+			break;
+		case 23: // Key Server Preferences
+			this.keyServerPreferences = new Array();
+			for ( var i = 0; i < subplen-1; i++) {
+				this.keyServerPreferences = input[mypos++].charCodeAt();
+			}
+			break;
+		case 24: // Preferred Key Server
+			this.preferredKeyServer = new String();
+			for ( var i = 0; i < subplen-1; i++) {
+				this.preferredKeyServer += input[mypos++];
+			}
+			break;
+		case 25: // Primary User ID
+			this.isPrimaryUserID = input[mypos++] != 0;
+			break;
+		case 26: // Policy URI
+			this.policyURI = new String();
+			for ( var i = 0; i < subplen-1; i++) {
+				this.policyURI += input[mypos++];
+			}
+			break;
+		case 27: // Key Flags
+			this.keyFlags = new Array();
+			for ( var i = 0; i < subplen-1; i++) {
+				this.keyFlags = input[mypos++].charCodeAt();
+			}
+			break;
+		case 28: // Signer's User ID
+			this.signersUserId = new String();
+			for ( var i = 0; i < subplen-1; i++) {
+				this.signersUserId += input[mypos++];
+			}
+			break;
+		case 29: // Reason for Revocation
+			this.reasonForRevocationFlag = input[mypos++].charCodeAt();
+			this.reasonForRevocationString = new String();
+			for ( var i = 0; i < subplen -2; i++) {
+				this.reasonForRevocationString += input[mypos++];
+			}
+			break;
+		case 30: // Features
+			// TODO: to be implemented
+			return subplen+1;
+		case 31: // Signature Target
+			// (1 octet public-key algorithm, 1 octet hash algorithm, N octets hash)
+			this.signatureTargetPublicKeyAlgorithm = input[mypos++].charCodeAt();
+			this.signatureTargetHashAlgorithm = input[mypos++].charCodeAt();
+			var signatureTargetHashAlgorithmLength = 0;
+			switch(this.signatureTargetHashAlgorithm) {
+			case  1: // - MD5 [HAC]                             "MD5"
+			case  2: // - SHA-1 [FIPS180]                       "SHA1"
+				signatureTargetHashAlgorithmLength = 20;
+				break;
+			case  3: // - RIPE-MD/160 [HAC]                     "RIPEMD160"
+			case  8: // - SHA256 [FIPS180]                      "SHA256"
+			case  9: // - SHA384 [FIPS180]                      "SHA384"
+			case 10: // - SHA512 [FIPS180]                      "SHA512"
+			case 11: // - SHA224 [FIPS180]                      "SHA224"
+				break;
+			// 100 to 110 - Private/Experimental algorithm
+	    	default:
+	    		util.print_error("openpgp.packet.signature.js\n"+"unknown signature target hash algorithm:"+this.signatureTargetHashAlgorithm);
+	    		return null;
+			}
+			this.signatureTargetHash = new Array();
+			for (var i = 0; i < signatureTargetHashAlgorithmLength; i++) {
+				this.signatureTargetHash[i] = input[mypos++]; 
+			}
+		case 32: // Embedded Signature
+			this.embeddedSignature = new openpgp_packet_signature();
+			this.embeddedSignature.read_packet(input, mypos, len -(mypos-position));
+			return ((mypos+ this.embeddedSignature.packetLength) - position);
+			break;
+		case 100: // Private or experimental
+		case 101: // Private or experimental
+		case 102: // Private or experimental
+		case 103: // Private or experimental
+		case 104: // Private or experimental
+		case 105: // Private or experimental
+		case 106: // Private or experimental
+		case 107: // Private or experimental
+		case 108: // Private or experimental
+		case 109: // Private or experimental
+		case 110: // Private or experimental
+			util.print_error("openpgp.packet.signature.js\n"+'private or experimental signature subpacket type '+type+" @:"+mypos+" subplen:"+subplen+" len:"+len);
+			return subplen+1;
+			break;	
+		case 0: // Reserved
+		case 1: // Reserved
+		case 8: // Reserved
+		case 10: // Placeholder for backward compatibility
+		case 13: // Reserved
+		case 14: // Reserved
+		case 15: // Reserved
+		case 17: // Reserved
+		case 18: // Reserved
+		case 19: // Reserved
+		default:
+			util.print_error("openpgp.packet.signature.js\n"+'unknown signature subpacket type '+type+" @:"+mypos+" subplen:"+subplen+" len:"+len);
+			return subplen+1;
+			break;
+		}
+		return mypos -position;
+	};
+	/**
+	 * verifys the signature packet. Note: not signature types are implemented
+	 * @param {String} data data which on the signature applies
+	 * @param {openpgp_msg_privatekey} key the public key to verify the signature
+	 * @return {boolean} True if message is verified, else false.
+	 */
+	function verify(data, key) {
+		// calculating the trailer
+		var trailer = '';
+		trailer += String.fromCharCode(this.version);
+		trailer += String.fromCharCode(0xFF);
+		trailer += String.fromCharCode(this.signatureData.length >> 24);
+		trailer += String.fromCharCode((this.signatureData.length >> 16) &0xFF);
+		trailer += String.fromCharCode((this.signatureData.length >> 8) &0xFF);
+		trailer += String.fromCharCode(this.signatureData.length & 0xFF);
+		switch(this.signatureType) {
+		case 0: // 0x00: Signature of a binary document.
+			if (this.version == 4) {
+				this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm, 
+					this.MPIs, key.obj.publicKeyPacket.MPIs, data+this.signatureData+trailer);
+			}
+			break;
+
+		case 1: // 0x01: Signature of a canonical text document.
+			if (this.version == 4) {
+				this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm, 
+					this.MPIs, key.obj.publicKeyPacket.MPIs, data+this.signatureData+trailer);
+				return this.verified;
+			}
+			break;
+				
+		case 2: // 0x02: Standalone signature.
+			// This signature is a signature of only its own subpacket contents.
+			// It is calculated identically to a signature over a zero-length
+			// binary document.  Note that it doesn't make sense to have a V3
+			// standalone signature.
+			if (this.version == 3) {
+				this.verified = false;
+				break;
+				}
+			
+			this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm, 
+					this.MPIs, key.obj.publicKeyPacket.MPIs, this.signatureData+trailer);
+			break;
+		case 16:			
+			// 0x10: Generic certification of a User ID and Public-Key packet.
+			// The issuer of this certification does not make any particular
+			// assertion as to how well the certifier has checked that the owner
+			// of the key is in fact the person described by the User ID.
+		case 17:
+			// 0x11: Persona certification of a User ID and Public-Key packet.
+			// The issuer of this certification has not done any verification of
+			// the claim that the owner of this key is the User ID specified.
+		case 18:
+			// 0x12: Casual certification of a User ID and Public-Key packet.
+			// The issuer of this certification has done some casual
+			// verification of the claim of identity.
+		case 19:
+			// 0x13: Positive certification of a User ID and Public-Key packet.
+			// The issuer of this certification has done substantial
+			// verification of the claim of identity.
+			// 
+			// Most OpenPGP implementations make their "key signatures" as 0x10
+			// certifications.  Some implementations can issue 0x11-0x13
+			// certifications, but few differentiate between the types.
+		case 48:
+			// 0x30: Certification revocation signature
+			// This signature revokes an earlier User ID certification signature
+			// (signature class 0x10 through 0x13) or direct-key signature
+			// (0x1F).  It should be issued by the same key that issued the
+			// revoked signature or an authorized revocation key.  The signature
+			// is computed over the same data as the certificate that it
+			// revokes, and should have a later creation date than that
+			// certificate.
+
+			this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm, 
+					this.MPIs, key.MPIs, data+this.signatureData+trailer);
+			break;
+						
+		case 24:
+			// 0x18: Subkey Binding Signature
+			// This signature is a statement by the top-level signing key that
+			// indicates that it owns the subkey.  This signature is calculated
+			// directly on the primary key and subkey, and not on any User ID or
+			// other packets.  A signature that binds a signing subkey MUST have
+			// an Embedded Signature subpacket in this binding signature that
+			// contains a 0x19 signature made by the signing subkey on the
+			// primary key and subkey.
+			if (this.version == 3) {
+				this.verified = false;
+				break;
+			}
+			
+			this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm, 
+					this.MPIs, key.MPIs, data+this.signatureData+trailer);
+			break;
+		case 25:
+			// 0x19: Primary Key Binding Signature
+			// This signature is a statement by a signing subkey, indicating
+			// that it is owned by the primary key and subkey.  This signature
+			// is calculated the same way as a 0x18 signature: directly on the
+			// primary key and subkey, and not on any User ID or other packets.
+			
+			// When a signature is made over a key, the hash data starts with the
+			// octet 0x99, followed by a two-octet length of the key, and then body
+			// of the key packet.  (Note that this is an old-style packet header for
+			// a key packet with two-octet length.)  A subkey binding signature
+			// (type 0x18) or primary key binding signature (type 0x19) then hashes
+			// the subkey using the same format as the main key (also using 0x99 as
+			// the first octet).
+		case 31:
+			// 0x1F: Signature directly on a key
+			// This signature is calculated directly on a key.  It binds the
+			// information in the Signature subpackets to the key, and is
+			// appropriate to be used for subpackets that provide information
+			// about the key, such as the Revocation Key subpacket.  It is also
+			// appropriate for statements that non-self certifiers want to make
+			// about the key itself, rather than the binding between a key and a
+			// name.
+		case 32:
+			// 0x20: Key revocation signature
+			// The signature is calculated directly on the key being revoked.  A
+			// revoked key is not to be used.  Only revocation signatures by the
+			// key being revoked, or by an authorized revocation key, should be
+			// considered valid revocation signatures.
+		case 40:
+			// 0x28: Subkey revocation signature
+			// The signature is calculated directly on the subkey being revoked.
+			// A revoked subkey is not to be used.  Only revocation signatures
+			// by the top-level signature key that is bound to this subkey, or
+			// by an authorized revocation key, should be considered valid
+			// revocation signatures.
+			this.verified = openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm, 
+					this.MPIs, key.MPIs, data+this.signatureData+trailer);
+			break;
+			
+			// Key revocation signatures (types 0x20 and 0x28)
+			// hash only the key being revoked.
+		case 64:
+			// 0x40: Timestamp signature.
+			// This signature is only meaningful for the timestamp contained in
+			// it.
+		case 80:
+			//    0x50: Third-Party Confirmation signature.
+			// This signature is a signature over some other OpenPGP Signature
+			// packet(s).  It is analogous to a notary seal on the signed data.
+			// A third-party signature SHOULD include Signature Target
+			// subpacket(s) to give easy identification.  Note that we really do
+			// mean SHOULD.  There are plausible uses for this (such as a blind
+			// party that only sees the signature, not the key or source
+			// document) that cannot include a target subpacket.
+		default:
+			util.print_error("openpgp.packet.signature.js\n"+"signature verification for type"+ this.signatureType+" not implemented");
+			break;
+		}
+		return this.verified;
+	}
+	/**
+	 * generates debug output (pretty print)
+	 * @return {String} String which gives some information about the signature packet
+	 */
+
+	function toString () {
+		if (this.version == 3) {
+			var result = '5.2. Signature Packet (Tag 2)\n'+
+	          "Packet Length:                     :"+this.packetLength+'\n'+
+	          "Packet version:                    :"+this.version+'\n'+
+	          "One-octet signature type           :"+this.signatureType+'\n'+
+	          "Four-octet creation time.          :"+this.creationTime+'\n'+
+	         "Eight-octet Key ID of signer.       :"+util.hexidump(this.keyId)+'\n'+
+	          "One-octet public-key algorithm.    :"+this.publicKeyAlgorithm+'\n'+
+	          "One-octet hash algorithm.          :"+this.hashAlgorithm+'\n'+
+	          "Two-octet field holding left\n" +
+	          " 16 bits of signed hash value.     :"+this.signedHashValue+'\n';
+		} else {
+          var result = '5.2. Signature Packet (Tag 2)\n'+
+          "Packet Length:                     :"+this.packetLength+'\n'+
+          "Packet version:                    :"+this.version+'\n'+
+          "One-octet signature type           :"+this.signatureType+'\n'+
+          "One-octet public-key algorithm.    :"+this.publicKeyAlgorithm+'\n'+
+          "One-octet hash algorithm.          :"+this.hashAlgorithm+'\n'+
+          "Two-octet field holding left\n" +
+          " 16 bits of signed hash value.     :"+this.signedHashValue+'\n'+
+          "Signature Creation Time            :"+this.creationTime+'\n'+
+          "Signature Expiration Time          :"+this.signatureExpirationTime+'\n'+
+          "Signature Never Expires            :"+this.signatureNeverExpires+'\n'+
+          "Exportable Certification           :"+this.exportable+'\n'+
+          "Trust Signature level:             :"+this.trustLevel+' amount'+this.trustAmount+'\n'+
+          "Regular Expression                 :"+this.regular_expression+'\n'+
+          "Revocable                          :"+this.revocable+'\n'+
+          "Key Expiration Time                :"+this.keyExpirationTime+" "+this.keyNeverExpires+'\n'+
+          "Preferred Symmetric Algorithms     :"+this.preferredSymmetricAlgorithms+'\n'+
+          "Revocation Key"+'\n'+
+          "   ( 1 octet of class,             :"+this.revocationKeyClass +'\n'+
+          "     1 octet of public-key ID,     :" +this.revocationKeyAlgorithm+'\n'+
+          "    20 octets of fingerprint)      :"+this.revocationKeyFingerprint+'\n'+
+          "Issuer                             :"+util.hexstrdump(this.issuerKeyId)+'\n'+
+          "Preferred Hash Algorithms          :"+this.preferredHashAlgorithms+'\n'+
+          "Preferred Compression Alg.         :"+this.preferredCompressionAlgorithms+'\n'+
+          "Key Server Preferences             :"+this.keyServerPreferences+'\n'+
+          "Preferred Key Server               :"+this.preferredKeyServer+'\n'+
+          "Primary User ID                    :"+this.isPrimaryUserID+'\n'+
+          "Policy URI                         :"+this.policyURI+'\n'+
+          "Key Flags                          :"+this.keyFlags+'\n'+
+          "Signer's User ID                   :"+this.signersUserId+'\n'+
+          "Notation                           :"+this.notationName+" = "+this.notationValue+"\n"+
+          "Reason for Revocation\n"+
+          "      Flag                         :"+this.reasonForRevocationFlag+'\n'+
+          "      Reason                       :"+this.reasonForRevocationString+'\nMPI:\n';
+		}
+          for (var i = 0; i < this.MPIs.length; i++) {
+        	  result += this.MPIs[i].toString();
+          }
+          return result;
+     }
+
+	/**
+	 * gets the issuer key id of this signature
+	 * @return {String} issuer key id as string (8bytes)
+	 */
+	function getIssuer() {
+		 if (this.version == 4)
+			 return this.issuerKeyId;
+		 if (this.verions == 4)
+			 return this.keyId;
+		 return null;
+	}
+
+	/**
+	 * Tries to get the corresponding public key out of the public keyring for the issuer created this signature
+	 * @return {Object} {obj: [openpgp_msg_publickey], text: [String]} if found the public key will be returned. null otherwise
+	 */
+	function getIssuerKey() {
+		 var result = null;
+		 if (this.version == 4) {
+			 result = openpgp.keyring.getPublicKeysForKeyId(this.issuerKeyId);
+		 } else if (this.version == 3) {
+			 result = openpgp.keyring.getPublicKeysForKeyId(this.keyId);
+		 } else return null;
+		 if (result.length == 0)
+			 return null;
+		 return result[0];
+	}
+	this.getIssuerKey = getIssuerKey;
+	this.getIssuer = getIssuer;	 
+	this.write_message_signature = write_message_signature;
+	this.verify = verify;
+    this.read_packet = read_packet;
+    this.toString = toString;
+}
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.packet.userattribute.js.html b/doc/openpgp.packet.userattribute.js.html new file mode 100644 index 00000000..7f9cc23d --- /dev/null +++ b/doc/openpgp.packet.userattribute.js.html @@ -0,0 +1,204 @@ + + + + + JSDoc: Source: packet/openpgp.packet.userattribute.js + + + + + + + + + + +
+ +

Source: packet/openpgp.packet.userattribute.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/** 
+ * @class
+ * @classdesc Implementation of the User Attribute Packet (Tag 17)
+ *  The User Attribute packet is a variation of the User ID packet.  It
+ *  is capable of storing more types of data than the User ID packet,
+ *  which is limited to text.  Like the User ID packet, a User Attribute
+ *  packet may be certified by the key owner ("self-signed") or any other
+ *  key owner who cares to certify it.  Except as noted, a User Attribute
+ *  packet may be used anywhere that a User ID packet may be used.
+ *
+ *  While User Attribute packets are not a required part of the OpenPGP
+ *  standard, implementations SHOULD provide at least enough
+ *  compatibility to properly handle a certification signature on the
+ *  User Attribute packet.  A simple way to do this is by treating the
+ *  User Attribute packet as a User ID packet with opaque contents, but
+ *  an implementation may use any method desired.
+ */
+function openpgp_packet_userattribute() {
+	this.tagType = 17;
+	this.certificationSignatures = new Array();
+	this.certificationRevocationSignatures = new Array();
+	this.revocationSignatures = new Array();
+	this.parentNode = null;
+
+	/**
+	 * parsing function for a user attribute packet (tag 17).
+	 * @param {String} input payload of a tag 17 packet
+	 * @param {Integer} position position to start reading from the input string
+	 * @param {Integer} len length of the packet or the remaining length of input at position
+	 * @return {openpgp_packet_encrypteddata} object representation
+	 */
+	function read_packet (input, position, len) {
+		var total_len = 0;
+		this.packetLength = len;
+		this.userattributes = new Array();
+		var count = 0;
+		var mypos = position;
+		while (len != total_len) {
+			var current_len = 0;
+			// 4.2.2.1. One-Octet Lengths
+			if (input[mypos].charCodeAt() < 192) {
+				packet_length = input[mypos++].charCodeAt();
+				current_len = 1;
+			// 4.2.2.2. Two-Octet Lengths
+			} else if (input[mypos].charCodeAt() >= 192 && input[mypos].charCodeAt() < 224) {
+				packet_length = ((input[mypos++].charCodeAt() - 192) << 8)
+					+ (input[mypos++].charCodeAt()) + 192;
+				current_len = 2;
+			// 4.2.2.4. Partial Body Lengths
+			} else if (input[mypos].charCodeAt() > 223 && input[mypos].charCodeAt() < 255) {
+				packet_length = 1 << (input[mypos++].charCodeAt() & 0x1F);
+				current_len = 1;
+			// 4.2.2.3. Five-Octet Lengths
+			} else {
+				current_len = 5;
+				mypos++;
+				packet_length = (input[mypos++].charCodeAt() << 24) | (input[mypos++].charCodeAt() << 16)
+					| (input[mypos++].charCodeAt() << 8) | input[mypos++].charCodeAt();
+			}
+			
+			var subpackettype = input[mypos++].charCodeAt();
+			packet_length--;
+			current_len++;
+			this.userattributes[count] = new Array();
+			this.userattributes[count] = input.substring(mypos, mypos + packet_length);
+			mypos += packet_length;
+			total_len += current_len+packet_length;
+		}
+		this.packetLength = mypos - position;
+		return this;
+	}
+	
+	/**
+	 * generates debug output (pretty print)
+	 * @return {String} String which gives some information about the user attribute packet
+	 */
+	function toString() {
+		var result = '5.12.  User Attribute Packet (Tag 17)\n'+
+		             '    AttributePackets: (count = '+this.userattributes.length+')\n';
+		for (var i = 0; i < this.userattributes.length; i++) {
+			result += '    ('+this.userattributes[i].length+') bytes: ['+util.hexidump(this.userattributes[i])+']\n'; 
+		}
+		return result;
+	}
+	
+	/**
+	 * Continue parsing packets belonging to the user attribute packet such as signatures
+	 * @param {Object} parent_node the parent object
+	 * @param {String} input input string to read the packet(s) from
+	 * @param {Integer} position start position for the parser
+	 * @param {Integer} len length of the packet(s) or remaining length of input
+	 * @return {Integer} length of nodes read
+	 */
+	function read_nodes(parent_node, input, position, len) {
+		
+		this.parentNode = parent_node;
+		var exit = false;
+		var pos = position;
+		var l = len;
+		while (input.length != pos) {
+			var result = openpgp_packet.read_packet(input, pos, l);
+			if (result == null) {
+				util.print_error("openpgp.packet.userattribute.js\n"+'[user_attr] parsing ends here @:' + pos + " l:" + l);
+				break;
+			} else {
+				switch (result.tagType) {
+				case 2: // Signature Packet
+					if (result.signatureType > 15
+							&& result.signatureType < 20) // certification
+						// //
+						// signature
+						this.certificationSignatures[this.certificationSignatures.length] = result;
+					else if (result.signatureType == 32) // certification revocation signature
+						this.certificationRevocationSignatures[this.certificationRevocationSignatures.length] = result;
+					pos += result.packetLength + result.headerLength;
+					l = len - (pos - position);
+					break;
+				default:
+					this.data = input;
+					this.position = position - parent_node.packetLength;
+					this.len = pos - position;
+					return this.len;
+					break;
+				}
+			}
+		}
+		this.data = input;
+		this.position = position - parent_node.packetLength;
+		this.len = pos - position;
+		return this.len;
+
+	}
+	
+	this.read_packet = read_packet;
+	this.read_nodes = read_nodes;
+	this.toString = toString;
+	
+};
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.packet.userid.js.html b/doc/openpgp.packet.userid.js.html new file mode 100644 index 00000000..fa8c072a --- /dev/null +++ b/doc/openpgp.packet.userid.js.html @@ -0,0 +1,385 @@ + + + + + JSDoc: Source: packet/openpgp.packet.userid.js + + + + + + + + + + +
+ +

Source: packet/openpgp.packet.userid.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+/**
+ * @class
+ * @classdesc Implementation of the User ID Packet (Tag 13)
+ * A User ID packet consists of UTF-8 text that is intended to represent
+ * the name and email address of the key holder.  By convention, it
+ * includes an RFC 2822 [RFC2822] mail name-addr, but there are no
+ * restrictions on its content.  The packet length in the header
+ * specifies the length of the User ID. 
+ */
+
+function openpgp_packet_userid() {
+	this.tagType = 13;
+	this.certificationSignatures = new Array();
+	this.certificationRevocationSignatures = new Array();
+	this.revocationSignatures = new Array();
+	this.parentNode = null;
+
+	/**
+	 * parsing function for a user id packet (tag 13).
+	 * @param {String} input payload of a tag 13 packet
+	 * @param {Integer} position position to start reading from the input string
+	 * @param {Integer} len length of the packet or the remaining length of input at position
+	 * @return {openpgp_packet_encrypteddata} object representation
+	 */
+	function read_packet(input, position, len) {
+		this.text = '';
+		this.packetLength = len;
+
+		for ( var i = 0; i < len; i++) {
+			this.text += input[position + i];
+		}
+		return this;
+	}
+
+	/**
+	 * creates a string representation of the user id packet
+	 * @param {String} user_id the user id as string ("John Doe <john.doe@mail.us")
+	 * @return {String} string representation
+	 */
+	function write_packet(user_id) {
+		this.text = user_id;
+		var result = openpgp_packet.write_packet_header(13,this.text.length);
+		result += this.text;
+		return result;
+	}
+
+	/**
+	 * Continue parsing packets belonging to the userid packet such as signatures
+	 * @param {Object} parent_node the parent object
+	 * @param {String} input input string to read the packet(s) from
+	 * @param {Integer} position start position for the parser
+	 * @param {Integer} len length of the packet(s) or remaining length of input
+	 * @return {Integer} length of nodes read
+	 */
+	function read_nodes(parent_node, input, position, len) {
+		if (parent_node.tagType == 6) { // public key
+			this.parentNode = parent_node;
+			var pos = position;
+			var l = len;
+			while (input.length != pos) {
+				var result = openpgp_packet.read_packet(input, pos, l - (pos - position));
+				if (result == null) {
+					util.print_error('[user_id] parsing ends here @:' + pos + " l:" + l);
+					break;
+				} else {
+					
+					pos += result.packetLength + result.headerLength;
+					l = input.length - pos;
+					switch (result.tagType) {
+					case 2: // Signature Packet
+						if (result.signatureType > 15
+								&& result.signatureType < 20) { // certification
+							// //
+							// signature
+							this.certificationSignatures[this.certificationSignatures.length] = result;
+							break;
+						} else if (result.signatureType == 48) {// certification revocation signature
+							this.certificationRevocationSignatures[this.certificationRevocationSignatures.length] = result;
+							break;
+						} else if (result.signatureType == 24) { // omg. standalone signature 
+							this.certificationSignatures[this.certificationSignatures.length] = result;
+							break;
+						} else {
+							util.print_debug("unknown sig t: "+result.signatureType+"@"+(pos - (result.packetLength + result.headerLength)));
+						}
+					default:
+						this.data = input;
+						this.position = position - parent_node.packetLength;
+						this.len = pos - position -(result.headerLength + result.packetLength);
+						return this.len;
+					}
+				}
+			}
+			this.data = input;
+			this.position = position - parent_node.packetLength;
+			this.len = pos - position -(result.headerLength + result.packetLength);
+			return this.len;
+		} else if (parent_node.tagType == 5) { // secret Key
+			this.parentNode = parent_node;
+			var exit = false;
+			var pos = position;
+			while (input.length != pos) {
+				var result = openpgp_packet.read_packet(input, pos, l - (pos - position));
+				if (result == null) {
+					util.print_error('parsing ends here @:' + pos + " l:" + l);
+					break;
+				} else {
+					pos += result.packetLength + result.headerLength;
+					l = input.length - pos;
+					switch (result.tagType) {
+					case 2: // Signature Packet certification signature
+						if (result.signatureType > 15
+								&& result.signatureType < 20)
+							this.certificationSignatures[this.certificationSignatures.length] = result;
+						// certification revocation signature
+						else if (result.signatureType == 48)
+							this.certificationRevocationSignatures[this.certificationRevocationSignatures.length] = result;
+					default:
+						this.data = input;
+						this.position = position - parent_node.packetLength;
+						this.len = pos - position -(result.headerLength + result.packetLength);
+						return this.len;
+					}
+				}
+			}
+		} else {
+			util.print_error("unknown parent node for a userId packet "+parent_node.tagType);
+		}
+	}
+	
+	/**
+	 * generates debug output (pretty print)
+	 * @return {String} String which gives some information about the user id packet
+	 */
+	function toString() {
+		var result = '     5.11.  User ID Packet (Tag 13)\n' + '    text ('
+				+ this.text.length + '): "' + this.text.replace("<", "<")
+				+ '"\n';
+		result +="certification signatures:\n";
+		for (var i = 0; i < this.certificationSignatures.length; i++) {
+			result += "        "+this.certificationSignatures[i].toString();
+		}
+		result +="certification revocation signatures:\n";
+		for (var i = 0; i < this.certificationRevocationSignatures.length; i++) {
+			result += "        "+this.certificationRevocationSignatures[i].toString();
+		}
+		return result;
+	}
+
+	/**
+	 * lookup function to find certification revocation signatures
+	 * @param {String} keyId string containing the key id of the issuer of this signature
+	 * @return a CertificationRevocationSignature if found; otherwise null
+	 */
+	function hasCertificationRevocationSignature(keyId) {
+		for (var i = 0; i < this.certificationRevocationSignatures.length; i++) {
+			if ((this.certificationRevocationSignatures[i].version == 3 &&
+				 this.certificationRevocationSignatures[i].keyId == keyId) ||
+				(this.certificationRevocationSignatures[i].version == 4 &&
+				 this.certificationRevocationSignatures[i].issuerKeyId == keyId))
+				return this.certificationRevocationSignatures[i];
+		}
+		return null;
+	}
+
+	/**
+	 * Verifies all certification signatures. This method does not consider possible revocation signatures.
+	 * @param {Object} publicKeyPacket the top level key material
+	 * @return {Integer[]} An array of integers corresponding to the array of certification signatures. The meaning of each integer is the following:
+	 * 0 = bad signature
+	 * 1 = signature expired
+	 * 2 = issuer key not available
+	 * 3 = revoked
+	 * 4 = signature valid
+	 * 5 = signature by key owner expired
+	 * 6 = signature by key owner revoked
+	 */
+	function verifyCertificationSignatures(publicKeyPacket) {
+		result = new Array();
+		for (var i = 0 ; i < this.certificationSignatures.length; i++) {
+			// A certification signature (type 0x10 through 0x13) hashes the User
+			// ID being bound to the key into the hash context after the above
+			// data.  A V3 certification hashes the contents of the User ID or
+			// attribute packet packet, without any header.  A V4 certification
+			// hashes the constant 0xB4 for User ID certifications or the constant
+			// 0xD1 for User Attribute certifications, followed by a four-octet
+			// number giving the length of the User ID or User Attribute data, and
+			// then the User ID or User Attribute data.
+
+			if (this.certificationSignatures[i].version == 4) {
+				if (this.certificationSignatures[i].signatureExpirationTime != null &&
+						this.certificationSignatures[i].signatureExpirationTime != null &&
+						this.certificationSignatures[i].signatureExpirationTime != 0 &&
+						!this.certificationSignatures[i].signatureNeverExpires &&
+						new Date(this.certificationSignatures[i].creationTime.getTime() +(this.certificationSignatures[i].signatureExpirationTime*1000)) < new Date()) {
+					if (this.certificationSignatures[i].issuerKeyId == publicKeyPacket.getKeyId())
+						result[i] = 5;
+					else
+						result[i] = 1;
+					continue;
+				}
+				if (this.certificationSignatures[i].issuerKeyId == null) {
+					result[i] = 0;
+					continue;
+				}
+				var issuerPublicKey = openpgp.keyring.getPublicKeysForKeyId(this.certificationSignatures[i].issuerKeyId);
+				if (issuerPublicKey == null || issuerPublicKey.length == 0) {
+					result[i] = 2;
+					continue;
+				}
+				// TODO: try to verify all returned issuer public keys (key ids are not unique!)
+				var issuerPublicKey = issuerPublicKey[0];
+				var signingKey = issuerPublicKey.obj.getSigningKey();
+				if (signingKey == null) {
+					result[i] = 0;
+					continue;
+				}
+				var revocation = this.hasCertificationRevocationSignature(this.certificationSignatures[i].issuerKeyId);
+				if (revocation != null && revocation.creationTime > 
+					this.certificationSignatures[i].creationTime) {
+					var signaturedata = String.fromCharCode(0x99)+ publicKeyPacket.header.substring(1)+
+					publicKeyPacket.data+String.fromCharCode(0xB4)+
+					String.fromCharCode((this.text.length >> 24) & 0xFF)+
+					String.fromCharCode((this.text.length >> 16) & 0xFF)+
+					String.fromCharCode((this.text.length >>  8) & 0xFF)+
+					String.fromCharCode((this.text.length) & 0xFF)+
+					this.text;
+					if (revocation.verify(signaturedata, signingKey)) {
+						if (this.certificationSignatures[i].issuerKeyId == publicKeyPacket.getKeyId())
+							result[i] = 6;
+						else
+							result[i] = 3;
+						continue;
+					}
+				}
+				var signaturedata = String.fromCharCode(0x99)+ publicKeyPacket.header.substring(1)+
+						publicKeyPacket.data+String.fromCharCode(0xB4)+
+						String.fromCharCode((this.text.length >> 24) & 0xFF)+
+						String.fromCharCode((this.text.length >> 16) & 0xFF)+
+						String.fromCharCode((this.text.length >>  8) & 0xFF)+
+						String.fromCharCode((this.text.length) & 0xFF)+
+						this.text;
+				if (this.certificationSignatures[i].verify(signaturedata, signingKey)) {
+					result[i] = 4;
+				} else
+				result[i] = 0;
+			} else if (this.certificationSignatures[i].version == 3) {
+				if (this.certificationSignatures[i].keyId == null) {
+					result[i] = 0;
+					continue;
+				}
+				var issuerPublicKey = openpgp.keyring.getPublicKeysForKeyId(this.certificationSignatures[i].keyId);
+				if (issuerPublicKey == null || issuerPublicKey.length == 0) {
+					result[i] = 2;
+					continue;
+				}
+				issuerPublicKey = issuerPublicKey[0];
+				var signingKey = publicKey.obj.getSigningKey();
+				if (signingKey == null) {
+					result[i] = 0;
+					continue;
+				}
+				var revocation = this.hasCertificationRevocationSignature(this.certificationSignatures[i].keyId);
+				if (revocation != null && revocation.creationTime > 
+					this.certificationSignatures[i].creationTime) {
+					var signaturedata = String.fromCharCode(0x99)+ this.publicKeyPacket.header.substring(1)+
+					this.publicKeyPacket.data+this.text;
+					if (revocation.verify(signaturedata, signingKey)) {
+						if (revocation.keyId == publicKeyPacket.getKeyId())
+							result[i] = 6;
+						else
+							result[i] = 3;
+						continue;
+					}
+				}
+				var signaturedata = String.fromCharCode(0x99)+ publicKeyPacket.header.substring(1)+
+					publicKeyPacket.data+this.text;
+				if (this.certificationSignatures[i].verify(signaturedata, signingKey)) {
+					result[i] = 4;
+				} else 
+				result[i] = 0;
+			} else {
+				result[i] = 0;
+			}
+		}
+		return result;
+	}
+
+	/**
+	 * verifies the signatures of the user id
+	 * @return 0 if the userid is valid; 1 = userid expired; 2 = userid revoked
+	 */
+	function verify(publicKeyPacket) {
+		var result = this.verifyCertificationSignatures(publicKeyPacket);
+		if (result.indexOf(6) != -1)
+			return 2;
+		if (result.indexOf(5) != -1)
+			return 1;
+		return 0;
+	}
+
+	// TODO: implementation missing
+	function addCertification(publicKeyPacket, privateKeyPacket) {
+		
+	}
+
+	// TODO: implementation missing
+	function revokeCertification(publicKeyPacket, privateKeyPacket) {
+		
+	}
+
+	this.hasCertificationRevocationSignature = hasCertificationRevocationSignature;
+	this.verifyCertificationSignatures = verifyCertificationSignatures;
+	this.verify = verify;
+	this.read_packet = read_packet;
+	this.write_packet = write_packet;
+	this.toString = toString;
+	this.read_nodes = read_nodes;
+}
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.type.keyid.js.html b/doc/openpgp.type.keyid.js.html new file mode 100644 index 00000000..097a6c4a --- /dev/null +++ b/doc/openpgp.type.keyid.js.html @@ -0,0 +1,98 @@ + + + + + JSDoc: Source: type/openpgp.type.keyid.js + + + + + + + + + + +
+ +

Source: type/openpgp.type.keyid.js

+ + + + + +
+
+
// 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 type key id (RFC4880 3.3)
+ *  A Key ID is an eight-octet scalar that identifies a key.
+   Implementations SHOULD NOT assume that Key IDs are unique.  The
+   section "Enhanced Key Formats" below describes how Key IDs are
+   formed.
+ */
+function openpgp_type_keyid() {
+	/**
+	 * Parsing method for a key id
+	 * @param {String} input Input to read the key id from 
+	 * @param {integer} position Position where to start reading the key 
+	 * id from input
+	 * @return {openpgp_type_keyid} This object
+	 */
+	function read_packet(input, position) {
+		this.bytes = input.substring(position, position+8);
+		return this;
+	}
+	
+	/**
+	 * Generates debug output (pretty print)
+	 * @return {String} Key Id as hexadecimal string
+	 */
+	function toString() {
+		return util.hexstrdump(this.bytes);
+	}
+	
+	this.read_packet = read_packet;
+	this.toString = toString;
+};
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.type.mpi.js.html b/doc/openpgp.type.mpi.js.html new file mode 100644 index 00000000..d2ba414e --- /dev/null +++ b/doc/openpgp.type.mpi.js.html @@ -0,0 +1,184 @@ + + + + + JSDoc: Source: type/openpgp.type.mpi.js + + + + + + + + + + +
+ +

Source: type/openpgp.type.mpi.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+// Hint: We hold our MPIs as an array of octets in big endian format preceeding a two
+// octet scalar: MPI: [a,b,c,d,e,f]
+// - MPI size: (a << 8) | b 
+// - MPI = c | d << 8 | e << ((MPI.length -2)*8) | f ((MPI.length -2)*8)
+
+/**
+ * @class
+ * @classdescImplementation of type MPI (RFC4880 3.2)
+ * Multiprecision integers (also called MPIs) are unsigned integers used
+ * to hold large integers such as the ones used in cryptographic
+ * calculations.
+ * An MPI consists of two pieces: a two-octet scalar that is the length
+ * of the MPI in bits followed by a string of octets that contain the
+ * actual integer.
+ */
+function openpgp_type_mpi() {
+	this.MPI = null;
+	this.mpiBitLength = null;
+	this.mpiByteLength = null;
+	this.data = null;
+	/**
+	 * Parsing function for a mpi (RFC 4880 3.2).
+	 * @param {String} input Payload of mpi data
+	 * @param {Integer} position Position to start reading from the input 
+	 * string
+	 * @param {Integer} len Length of the packet or the remaining length of 
+	 * input at position
+	 * @return {openpgp_type_mpi} Object representation
+	 */
+	function read(input, position, len) {
+		var mypos = position;
+		
+		this.mpiBitLength = (input[mypos++].charCodeAt() << 8) | input[mypos++].charCodeAt();
+		
+		// Additional rules:
+		//
+		//    The size of an MPI is ((MPI.length + 7) / 8) + 2 octets.
+		//
+		//    The length field of an MPI describes the length starting from its
+		//	  most significant non-zero bit.  Thus, the MPI [00 02 01] is not
+		//    formed correctly.  It should be [00 01 01].
+
+		// TODO: Verification of this size method! This size calculation as
+		// 		 specified above is not applicable in JavaScript
+		this.mpiByteLength = (this.mpiBitLength - (this.mpiBitLength % 8)) / 8;
+		if (this.mpiBitLength % 8 != 0)
+			this.mpiByteLength++;
+		
+		this.MPI = input.substring(mypos,mypos+this.mpiByteLength);
+		this.data = input.substring(position, position+2+this.mpiByteLength);
+		this.packetLength = this.mpiByteLength +2;
+		return this;
+	}
+	
+	/**
+	 * Generates debug output (pretty print)
+	 * @return {String} String which gives some information about the mpi
+	 */
+	function toString() {
+		var r = "    MPI("+this.mpiBitLength+"b/"+this.mpiByteLength+"B) : 0x";
+		r+=util.hexstrdump(this.MPI);
+		return r+'\n';
+	}
+	
+	/**
+	 * Converts the mpi to an BigInteger object
+	 * @return {BigInteger}
+	 */
+	function getBigInteger() {
+		return new BigInteger(util.hexstrdump(this.MPI),16); 
+	}
+
+	
+	function getBits(num) {
+		for (var i = 0; i < 9; i++)
+		if (num >> i == 0)
+		return i;
+	}
+	
+	/**
+	 * Gets the length of the mpi in bytes
+	 * @return {Integer} Mpi byte length
+	 */
+	function getByteLength() {
+		return this.mpiByteLength;
+	}
+	
+	/**
+	 * Creates an mpi from the specified string
+	 * @param {String} data Data to read the mpi from
+	 * @return {openpgp_type_mpi} 
+	 */
+	function create(data) {
+		this.MPI = data;
+		this.mpiBitLength = (data.length -1) *8 + getBits(data.charCodeAt(0));
+		this.mpiByteLength = data.length;
+		return this;
+	}
+	
+	/**
+	 * Converts the mpi object to a string as specified in RFC4880 3.2
+	 * @return {String} mpi Byte representation
+	 */
+	function toBin() {
+		var result = String.fromCharCode((this.mpiBitLength >> 8) & 0xFF);
+		result += String.fromCharCode(this.mpiBitLength & 0xFF);
+		result += this.MPI;
+		return result;
+	}
+	
+	this.read = read;
+	this.toBigInteger = getBigInteger;
+	this.toString = toString;
+	this.create = create;
+	this.toBin = toBin;
+	this.getByteLength = getByteLength;
+}
+
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/openpgp.type.s2k.js.html b/doc/openpgp.type.s2k.js.html new file mode 100644 index 00000000..ab0d4894 --- /dev/null +++ b/doc/openpgp.type.s2k.js.html @@ -0,0 +1,189 @@ + + + + + JSDoc: Source: type/openpgp.type.s2k.js + + + + + + + + + + +
+ +

Source: type/openpgp.type.s2k.js

+ + + + + +
+
+
// 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;
+		}
+		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) {
+		if (this.type == 0) {
+			return openpgp_crypto_hashData(this.hashAlgorithm,passphrase);
+		} else if (this.type == 1) {
+			return openpgp_crypto_hashData(this.hashAlgorithm,this.saltValue+passphrase);
+		} else if (this.type == 3) {
+			var isp = [];
+			isp[0] = this.saltValue+passphrase;
+			while (isp.length*(this.saltValue+passphrase).length < this.count)
+				isp.push(this.saltValue+passphrase);
+			isp = isp.join('');			
+			if (isp.length > this.count)
+				isp = isp.substr(0, this.count);
+			if(numBytes && (numBytes == 24 || numBytes == 32)){ //This if accounts for RFC 4880 3.7.1.1 -- If hash size is greater than block size, use leftmost bits.  If blocksize larger than hash size, we need to rehash isp and prepend with 0.
+			    var key = openpgp_crypto_hashData(this.hashAlgorithm,isp);
+			    return key + openpgp_crypto_hashData(this.hashAlgorithm,String.fromCharCode(0)+isp);
+			}
+			return openpgp_crypto_hashData(this.hashAlgorithm,isp);
+		} else return null;
+	}
+	
+	this.read = read;
+	this.write = write;
+	this.produce_key = produce_key;
+}
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/rsa.js.html b/doc/rsa.js.html new file mode 100644 index 00000000..5c07d159 --- /dev/null +++ b/doc/rsa.js.html @@ -0,0 +1,184 @@ + + + + + JSDoc: Source: ciphers/asymmetric/rsa.js + + + + + + + + + + +
+ +

Source: ciphers/asymmetric/rsa.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// RSA implementation
+
+function SecureRandom(){
+    function nextBytes(byteArray){
+        for(var n = 0; n < byteArray.length;n++){
+            byteArray[n] = openpgp_crypto_getSecureRandomOctet();
+        }
+    }
+    this.nextBytes = nextBytes;
+}
+
+function RSA() {
+	/**
+	 * This function uses jsbn Big Num library to decrypt RSA
+	 * @param m
+	 *            message
+	 * @param d
+	 *            RSA d as BigInteger
+	 * @param p
+	 *            RSA p as BigInteger
+	 * @param q
+	 *            RSA q as BigInteger
+	 * @param u
+	 *            RSA u as BigInteger
+	 * @return {BigInteger} The decrypted value of the message
+	 */
+	function decrypt(m, d, p, q, u) {
+		var xp = m.mod(p).modPow(d.mod(p.subtract(BigInteger.ONE)), p);
+		var xq = m.mod(q).modPow(d.mod(q.subtract(BigInteger.ONE)), q);
+		util.print_debug("rsa.js decrypt\nxpn:"+util.hexstrdump(xp.toMPI())+"\nxqn:"+util.hexstrdump(xq.toMPI()));
+
+		var t = xq.subtract(xp);
+		if (t[0] == 0) {
+			t = xp.subtract(xq);
+			t = t.multiply(u).mod(q);
+			t = q.subtract(t);
+		} else {
+			t = t.multiply(u).mod(q);
+		}
+		return t.multiply(p).add(xp);
+	}
+	
+	/**
+	 * encrypt message
+	 * @param m message as BigInteger
+	 * @param e public MPI part as BigInteger
+	 * @param n public MPI part as BigInteger
+	 * @return BigInteger
+	 */
+	function encrypt(m,e,n) {
+		return m.modPowInt(e, n);
+	}
+	
+	/* Sign and Verify */
+	function sign(m,d,n) {
+		return m.modPow(d, n);
+	}
+		
+	function verify(x,e,n) {
+		return x.modPowInt(e, n);
+	}
+	
+	// "empty" RSA key constructor
+    function keyObject() {
+        this.n = null;
+        this.e = 0;
+        this.ee = null;
+        this.d = null;
+        this.p = null;
+        this.q = null;
+        this.dmp1 = null;
+        this.dmq1 = null;
+        this.u = null;
+    }
+	
+	// Generate a new random private key B bits long, using public expt E
+    function generate(B,E) {
+        var key = new keyObject();
+        var rng = new SecureRandom();
+        var qs = B>>1;
+        key.e = parseInt(E,16);
+        key.ee = new BigInteger(E,16);
+        for(;;) {
+            for(;;) {
+                key.p = new BigInteger(B-qs,1,rng);
+                if(key.p.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) == 0 && key.p.isProbablePrime(10)) break;
+            }
+            for(;;) {
+                key.q = new BigInteger(qs,1,rng);
+                if(key.q.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) == 0 && key.q.isProbablePrime(10)) break;
+            }
+            if(key.p.compareTo(key.q) <= 0) {
+                var t = key.p;
+                key.p = key.q;
+                key.q = t;
+            }
+            var p1 = key.p.subtract(BigInteger.ONE);
+            var q1 = key.q.subtract(BigInteger.ONE);
+            var phi = p1.multiply(q1);
+            if(phi.gcd(key.ee).compareTo(BigInteger.ONE) == 0) {
+                key.n = key.p.multiply(key.q);
+                key.d = key.ee.modInverse(phi);
+                key.dmp1 = key.d.mod(p1);
+                key.dmq1 = key.d.mod(q1);
+                key.u = key.p.modInverse(key.q);
+                break;
+            }
+        }
+        return key;
+    }
+		
+	this.encrypt = encrypt;
+	this.decrypt = decrypt;
+	this.verify = verify;
+	this.sign = sign;
+	this.generate = generate;
+	this.keyObject = keyObject;
+}
+
+
+
+ + + + +
+ + + +
+ + + + + + diff --git a/doc/util.js.html b/doc/util.js.html new file mode 100644 index 00000000..cb8575a1 --- /dev/null +++ b/doc/util.js.html @@ -0,0 +1,336 @@ + + + + + JSDoc: Source: util/util.js + + + + + + + + + + +
+ +

Source: util/util.js

+ + + + + +
+
+
// GPG4Browsers - An OpenPGP implementation in javascript
+// Copyright (C) 2011 Recurity Labs GmbH
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+var Util = function() {
+
+    this.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.hexdump = function(str) {
+	    var r=[];
+	    var e=str.length;
+	    var c=0;
+	    var h;
+	    var i = 0;
+	    while(c<e){
+	        h=str.charCodeAt(c++).toString(16);
+	        while(h.length<2) h="0"+h;
+	        r.push(" "+h);
+	        i++;
+	        if (i % 32 == 0)
+	        	r.push("\n           ");
+	    }
+	    return r.join('');
+	};
+	
+	/**
+	 * Create hexstring from a binary
+	 * @param {String} str String to convert
+	 * @return {String} String containing the hexadecimal values
+	 */
+	this.hexstrdump = function(str) {
+		if (str == null)
+			return "";
+	    var r=[];
+	    var e=str.length;
+	    var c=0;
+	    var h;
+	    while(c<e){
+	        h=str[c++].charCodeAt().toString(16);
+	        while(h.length<2) h="0"+h;
+	        r.push(""+h);
+	    }
+	    return r.join('');
+	};
+	
+	/**
+	 * Create binary string from a hex encoded string
+	 * @param {String} str Hex string to convert
+	 * @return {String} String containing the binary values
+	 */
+	this.hex2bin = function(hex) {
+	    var str = '';
+	    for (var i = 0; i < hex.length; i += 2)
+	        str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
+	    return str;
+	};
+	
+	/**
+	 * Creating a hex string from an binary array of integers (0..255)
+	 * @param {String} str Array of bytes to convert
+	 * @return {String} Hexadecimal representation of the array
+	 */
+	this.hexidump = function(str) {
+	    var r=[];
+	    var e=str.length;
+	    var c=0;
+	    var h;
+	    while(c<e){
+	        h=str[c++].toString(16);
+	        while(h.length<2) h="0"+h;
+	        r.push(""+h);
+	    }
+	    return r.join('');
+	};
+	
+	/**
+	 * Convert a string to an array of integers(0.255)
+	 * @param {String} str String to convert
+	 * @return {Integer[]} An array of (binary) integers
+	 */
+	this.str2bin = function(str) {
+		var result = new Array();
+		for (var i = 0; i < str.length; i++) {
+			result[i] = str.charCodeAt(i);
+		}
+		
+		return result;
+	};
+
+	/**
+	 * Convert an array of integers(0.255) to a string 
+	 * @param {Integer[]} bin An array of (binary) integers to convert
+	 * @return {String} The string representation of the array
+	 */
+	this.bin2str = function(bin) {
+		var result = [];
+		for (var i = 0; i < bin.length; i++) {
+			result.push(String.fromCharCode(bin[i]));
+		}
+		return result.join('');
+	};
+	
+	/**
+	 * Convert a string to a Uint8Array
+	 * @param {String} str String to convert
+	 * @return {Uint8Array} The array of (binary) integers
+	 */
+	this.str2Uint8Array = function(str){
+        var uintArray = new Uint8Array(new ArrayBuffer(str.length));
+        for(var n = 0; n < str.length; n++){
+            uintArray[n] = str.charCodeAt(n);
+        }
+        return uintArray;
+	};
+	
+	/**
+	 * Convert a Uint8Array to a string. This currently functions 
+	 * the same as bin2str. 
+	 * @param {Uint8Array} bin An array of (binary) integers to convert
+	 * @return {String} String representation of the array
+	 */
+	this.Uint8Array2str = function(bin) {
+        var result = [];
+        for(n = 0; n< bin.length; n++){
+            result[n] = String.fromCharCode(bin[n]);
+        }
+        return result.join('');
+	};
+	
+	/**
+	 * Calculates a 16bit sum of a string by adding each character 
+	 * codes modulus 65535
+	 * @param {String} text String to create a sum of
+	 * @return {Integer} An integer containing the sum of all character 
+	 * codes % 65535
+	 */
+	this.calc_checksum = function(text) {
+		var checksum = {  s: 0, add: function (sadd) { this.s = (this.s + sadd) % 65536; }};
+		for (var i = 0; i < text.length; i++) {
+			checksum.add(text.charCodeAt(i));
+		}
+		return checksum.s;
+	};
+	
+	/**
+	 * Helper function to print a debug message. Debug 
+	 * messages are only printed if
+	 * openpgp.config.debug is set to true. The calling
+	 * Javascript context MUST define
+	 * a "showMessages(text)" function. Line feeds ('\n')
+	 * are automatically converted to HTML line feeds '<br/>'
+	 * @param {String} str String of the debug message
+	 * @return {String} An HTML tt entity containing a paragraph with a 
+	 * style attribute where the debug message is HTMLencoded in. 
+	 */
+	this.print_debug = function(str) {
+		if (openpgp.config.debug) {
+			str = openpgp_encoding_html_encode(str);
+			showMessages("<tt><p style=\"background-color: #ffffff; width: 652px; word-break: break-word; padding: 5px; border-bottom: 1px solid black;\">"+str.replace(/\n/g,"<br>")+"</p></tt>");
+		}
+	};
+	
+	/**
+	 * Helper function to print a debug message. Debug 
+	 * messages are only printed if
+	 * openpgp.config.debug is set to true. The calling
+	 * Javascript context MUST define
+	 * a "showMessages(text)" function. Line feeds ('\n')
+	 * are automatically converted to HTML line feeds '<br/>'
+	 * Different than print_debug because will call hexstrdump iff necessary.
+	 * @param {String} str String of the debug message
+	 * @return {String} An HTML tt entity containing a paragraph with a 
+	 * style attribute where the debug message is HTMLencoded in. 
+	 */
+	this.print_debug_hexstr_dump = function(str,strToHex) {
+		if (openpgp.config.debug) {
+			str = str + this.hexstrdump(strToHex);
+			str = openpgp_encoding_html_encode(str);
+			showMessages("<tt><p style=\"background-color: #ffffff; width: 652px; word-break: break-word; padding: 5px; border-bottom: 1px solid black;\">"+str.replace(/\n/g,"<br>")+"</p></tt>");
+		}
+	};
+	
+	/**
+	 * Helper function to print an error message. 
+	 * The calling Javascript context MUST define
+	 * a "showMessages(text)" function. Line feeds ('\n')
+	 * are automatically converted to HTML line feeds '<br/>'
+	 * @param {String} str String of the error message
+	 * @return {String} A HTML paragraph entity with a style attribute 
+	 * containing the HTML encoded error message
+	 */
+	this.print_error = function(str) {
+		str = openpgp_encoding_html_encode(str);
+		showMessages("<p style=\"font-size: 80%; background-color: #FF8888; margin:0; width: 652px; word-break: break-word; padding: 5px; border-bottom: 1px solid black;\"><span style=\"color: #888;\"><b>ERROR:</b></span>	"+str.replace(/\n/g,"<br>")+"</p>");
+	};
+	
+	/**
+	 * Helper function to print an info message. 
+	 * The calling Javascript context MUST define
+	 * a "showMessages(text)" function. Line feeds ('\n')
+	 * are automatically converted to HTML line feeds '<br/>'.
+	 * @param {String} str String of the info message
+	 * @return {String} A HTML paragraph entity with a style attribute 
+	 * containing the HTML encoded info message
+	 */
+	this.print_info = function(str) {
+		str = openpgp_encoding_html_encode(str);
+		showMessages("<p style=\"font-size: 80%; background-color: #88FF88; margin:0; width: 652px; word-break: break-word; padding: 5px; border-bottom: 1px solid black;\"><span style=\"color: #888;\"><b>INFO:</b></span>	"+str.replace(/\n/g,"<br>")+"</p>");
+	};
+	
+	this.print_warning = function(str) {
+		str = openpgp_encoding_html_encode(str);
+		showMessages("<p style=\"font-size: 80%; background-color: #FFAA88; margin:0; width: 652px; word-break: break-word; padding: 5px; border-bottom: 1px solid black;\"><span style=\"color: #888;\"><b>WARNING:</b></span>	"+str.replace(/\n/g,"<br>")+"</p>");
+	};
+	
+	this.getLeftNBits = function (string, bitcount) {
+		var rest = bitcount % 8;
+		if (rest == 0)
+			return string.substring(0, bitcount / 8);
+		var bytes = (bitcount - rest) / 8 +1;
+		var result = string.substring(0, bytes);
+		return this.shiftRight(result, 8-rest); // +String.fromCharCode(string.charCodeAt(bytes -1) << (8-rest) & 0xFF);
+	};
+
+	/**
+	 * Shifting a string to n bits right
+	 * @param {String} value The string to shift
+	 * @param {Integer} bitcount Amount of bits to shift (MUST be smaller 
+	 * than 9)
+	 * @return {String} Resulting string. 
+	 */
+	this.shiftRight = function(value, bitcount) {
+		var temp = util.str2bin(value);
+        if (bitcount % 8 != 0) {
+        	for (var i = temp.length-1; i >= 0; i--) {
+        		temp[i] >>= bitcount % 8;
+        		if (i > 0)
+        			temp[i] |= (temp[i - 1] << (8 - (bitcount % 8))) & 0xFF;
+        	}
+        } else {
+        	return value;
+        }
+        return util.bin2str(temp);
+	};
+	
+	/**
+	 * Return the algorithm type as string
+	 * @return {String} String representing the message type
+	 */
+	this.get_hashAlgorithmString = function(algo) {
+		switch(algo) {
+		case 1:
+			return "MD5";
+		case 2:
+			return "SHA1";
+		case 3:
+			return "RIPEMD160";
+		case 8:
+			return "SHA256";
+		case 9:
+			return "SHA384";
+		case 10:
+			return "SHA512";
+		case 11:
+			return "SHA224";
+		}
+		return "unknown";
+	};
+};
+
+/**
+ * an instance that should be used. 
+ */
+var util = new Util();
+
+
+
+ + + + +
+ + + +
+ + + + + +