1 2/* OpenPGP encryption using RSA/AES 3 * Copyright 2005-2006 Herbert Hanewinkel, www.haneWIN.de 4 * version 2.0, check www.haneWIN.de for the latest version 5 6 * This software is provided as-is, without express or implied warranty. 7 * Permission to use, copy, modify, distribute or sell this software, with or 8 * without fee, for any purpose and by any individual or organization, is hereby 9 * granted, provided that the above copyright notice and this paragraph appear 10 * in all copies. Distribution as a part of an application or binary must 11 * include the above copyright notice in the documentation and/or other 12 * materials provided with the application or distribution. 13 */ 14 15/* We need an unpredictable session key of 128 bits ( = 2^128 possible keys). 16 * If we generate the session key with a PRNG from a small seed we get only 17 * a small number of session keys, e.g. 4 bytes seed => 2^32 keys, a brute 18 * force attack could try all 2^32 session keys. 19 * (see RFC 1750 - Randomness Recommendations for Security.) 20 * 21 * Sources for randomness in Javascript are limited. 22 * We have load, exec time, seed from random(), mouse movement events 23 * and the timing from key press events. 24 * But even here we have restrictions. 25 * - A mailer will add a timestamp to the encrypted message, therefore 26 * only the msecs from the clock can be seen as unpredictable. 27 * - Because the Windows timer is still based on the old DOS timer, 28 * the msecs jump under Windows in 18.2 msecs steps. 29 * - Only a few bits from mouse mouvemen event coordinates are unpredictable, 30 * if the same buttons are clicked on the screen. 31 */ 32 33var rnArray = new Array(256); 34var rnNext = 0; 35var rnRead = 0; 36 37function randomByte() { return Math.round(Math.random()*255)&255; } 38function timeByte() { return ((new Date().getTime())>>>2)&255; } 39 40function rnTimer() 41{ 42 var t = timeByte(); // load time 43 44 for(var i=0; i<256; i++) 45 { 46 t ^= randomByte(); 47 rnArray[(rnNext++)&255] ^= t; 48 } 49 window.setTimeout("rnTimer()",randomByte()|128); 50} 51 52// rnTimer() and mouseMoveCollect() are started on page load. 53 54rnTimer(); 55eventsCollect(); 56 57// ---------------------------------------- 58 59function randomString(len, nozero) 60{ 61 var r = ''; 62 var t = timeByte(); // exec time 63 64 for(var i=0; i<len;) 65 { 66 t ^= rnArray[(rnRead++)&255]^mouseByte()^keyByte(); 67 if(t==0 && nozero) continue; 68 i++; 69 70 r+=String.fromCharCode(t); 71 } 72 return r; 73} 74 75// ---------------------------------------- 76 77function hex2s(hex) 78{ 79 var r=''; 80 if(hex.length%2) hex+='0'; 81 82 for(var i = 0; i<hex.length; i += 2) 83 r += String.fromCharCode(parseInt(hex.slice(i, i+2), 16)); 84 return r; 85} 86 87function crc24(data) 88{ 89 var crc = 0xb704ce; 90 91 for(var n=0; n<data.length;n++) 92 { 93 crc ^=(data.charCodeAt(n)&255)<<16; 94 for(i=0;i<8;i++) 95 { 96 crc<<=1; 97 if(crc & 0x1000000) crc^=0x1864cfb; 98 } 99 } 100 return String.fromCharCode((crc>>16)&255) 101 +String.fromCharCode((crc>>8)&255) 102 +String.fromCharCode(crc&255); 103} 104 105// -------------------------------------- 106// GPG CFB symmetric encryption using AES 107 108var symAlg = 7; // AES=7, AES192=8, AES256=9 109var kSize = [16,24,32] // key length in bytes 110var bpbl = 16; // bytes per data block 111 112function GPGencrypt(key, text) 113{ 114 var i, n; 115 var len = text.length; 116 var lsk = key.length; 117 var iblock = new Array(bpbl) 118 var rblock = new Array(bpbl); 119 var ct = new Array(bpbl+2); 120 var expandedKey = new Array(); 121 122 var ciphertext = ''; 123 124 // append zero padding 125 if(len%bpbl) 126 { 127 for(i=(len%bpbl); i<bpbl; i++) text+='\0'; 128 } 129 130 expandedKey = keyExpansion(key); 131 132 // set up initialisation vector and random byte vector 133 for(i=0; i<bpbl; i++) 134 { 135 iblock[i] = 0; 136 rblock[i] = randomByte(); 137 } 138 139 iblock = AESencrypt(iblock, expandedKey); 140 for(i=0; i<bpbl; i++) 141 { 142 ct[i] = (iblock[i] ^= rblock[i]); 143 } 144 145 iblock = AESencrypt(iblock, expandedKey); 146 // append check octets 147 ct[bpbl] = (iblock[0] ^ rblock[bpbl-2]); 148 ct[bpbl+1] = (iblock[1] ^ rblock[bpbl-1]); 149 150 for(i = 0; i < bpbl+2; i++) ciphertext += String.fromCharCode(ct[i]); 151 152 // resync 153 iblock = ct.slice(2, bpbl+2); 154 155 for(n = 0; n < text.length; n+=bpbl) 156 { 157 iblock = AESencrypt(iblock, expandedKey); 158 for(i = 0; i < bpbl; i++) 159 { 160 iblock[i] ^= text.charCodeAt(n+i); 161 ciphertext += String.fromCharCode(iblock[i]); 162 } 163 } 164 return ciphertext.substr(0,len+bpbl+2); 165} 166 167// ------------------------------ 168// GPG packet header (old format) 169 170function GPGpkt(tag, len) 171{ 172 if(len>255) tag +=1; 173 var h = String.fromCharCode(tag); 174 if(len>255) h+=String.fromCharCode(len/256); 175 h += String.fromCharCode(len%256); 176 return h; 177} 178 179// ---------------------------------------------- 180// GPG public key encryted session key packet (1) 181 182var el = [3,5,9,17,513,1025,2049,4097]; 183 184function GPGpkesk(keyId, keytyp, symAlgo, sessionkey, pkey) 185{ 186 var mod=new Array(); 187 var exp=new Array(); 188 var enc=''; 189 190 var s = r2s(pkey);
191 var l = Math.floor((s.charCodeAt(0)*256 + s.charCodeAt(1)+7)/8); 192 193 mod = mpi2b(s.substr(0,l+2)); 194 195 if(keytyp) 196 { 197 var grp=new Array(); 198 var y =new Array(); 199 var B =new Array(); 200 var C =new Array(); 201 202 var l2 = Math.floor((s.charCodeAt(l+2)*256 + s.charCodeAt(l+3)+7)/8)+2; 203 204 grp = mpi2b(s.substr(l+2,l2)); 205 y = mpi2b(s.substr(l+2+l2)); 206 exp[0] = el[randomByte()&7]; 207 B = bmodexp(grp,exp,mod); 208 C = bmodexp(y,exp,mod); 209 } 210 else 211 { 212 exp = mpi2b(s.substr(l+2)); 213 } 214 215 var lsk = sessionkey.length; 216 217 // calculate checksum of session key 218 var c = 0; 219 for(var i = 0; i < lsk; i++) c += sessionkey.charCodeAt(i); 220 c &= 0xffff; 221 222 // create MPI from session key using PKCS-1 block type 02 223 var lm = (l-2)*8+2; 224 var m = String.fromCharCode(lm/256)+String.fromCharCode(lm%256) 225 +String.fromCharCode(2) // skip leading 0 for MPI 226 +randomString(l-lsk-6,1)+'\0' // add random padding (non-zero) 227 +String.fromCharCode(symAlgo)+sessionkey 228 +String.fromCharCode(c/256)+String.fromCharCode(c&255); 229 230 if(keytyp) 231 { 232 // add Elgamal encrypted mpi values 233 enc = b2mpi(B)+b2mpi(bmod(bmul(mpi2b(m),C),mod)); 234 235 return GPGpkt(0x84,enc.length+10) 236 +String.fromCharCode(3)+keyId+String.fromCharCode(16)+enc; 237 } 238 else 239 { 240 // rsa encrypt the result and convert into mpi 241 enc = b2mpi(bmodexp(mpi2b(m),exp,mod)); 242 243 return GPGpkt(0x84,enc.length+10) 244 +String.fromCharCode(3)+keyId+String.fromCharCode(1)+enc; 245 } 246} 247 248// ------------------------------------------ 249// GPG literal data packet (11) for text file 250 251function GPGld(text) 252{ 253 if(text.indexOf('\r\n') == -1) 254 text = text.replace(/\n/g,'\r\n'); 255 return GPGpkt(0xAC,text.length+10)+'t' 256 +String.fromCharCode(4)+'file\0\0\0\0'+text; 257} 258 259// ------------------------------------------- 260// GPG symmetrically encrypted data packet (9) 261 262function GPGsed(key, text) 263{ 264 var enc = GPGencrypt(key, GPGld(text)); 265 return GPGpkt(0xA4,enc.length)+enc; 266} 267 268// ------------------------------------------------ 269 270function doEncrypt(keyId,keytyp,pkey,text) 271{ 272 var keylen = kSize[symAlg-7]; // session key length in bytes 273 274 var sesskey = randomString(keylen,0); 275 keyId = hex2s(keyId); 276 var cp = GPGpkesk(keyId,keytyp,symAlg,sesskey,pkey)+GPGsed(sesskey,text); 277 278 return '\n\n-----BEGIN PGP MESSAGE-----\nVersion: haneWIN JavascriptPG v2.0 w/ wp2pgpmail\n\n' 279 +s2r(cp)+'\n='+s2r(crc24(cp))+'\n-----END PGP MESSAGE-----\n\n'; 280}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.