blob: c2f610c0c0a0ee49c71b26a1a84d0223bd41bce8 [file] [log] [blame]
Wentao Shangc0311e52012-12-03 10:38:23 -08001/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002 * @author: Jeff Thompson
3 * See COPYING for copyright and distribution information.
4 * Provide the callback closure for the async communication methods in the NDN class.
5 * This is a port of Closure.py from PyCCN, written by:
6 * Derek Kulinski <takeda@takeda.tk>
7 * Jeff Burke <jburke@ucla.edu>
8 */
9
10/*
11 * Create a subclass of Closure and pass an object to async calls.
12 */
13var Closure = function Closure() {
14 // I don't think storing NDN's closure is needed
15 // and it creates a reference loop, as of now both
16 // of those variables are never set -- Derek
17 //
18 // Use instance variables to return data to callback
19 this.ndn_data = null; // this holds the ndn_closure
20 this.ndn_data_dirty = false;
Wentao Shangc0311e52012-12-03 10:38:23 -080021
22 this.timerID = -1; // Store the interest timer; used to cancel the timer upon receiving interest
Wentao Shang0e291c82012-12-02 23:36:29 -080023};
24
25// Upcall result
26Closure.RESULT_ERR = -1; // upcall detected an error
27Closure.RESULT_OK = 0; // normal upcall return
28Closure.RESULT_REEXPRESS = 1; // reexpress the same interest again
29Closure.RESULT_INTEREST_CONSUMED = 2; // upcall claims to consume interest
30Closure.RESULT_VERIFY = 3; // force an unverified result to be verified
31Closure.RESULT_FETCHKEY = 4; // get the key in the key locator and re-call the interest
32 // with the key available in the local storage
33
34// Upcall kind
35Closure.UPCALL_FINAL = 0; // handler is about to be deregistered
36Closure.UPCALL_INTEREST = 1; // incoming interest
37Closure.UPCALL_CONSUMED_INTEREST = 2; // incoming interest, someone has answered
38Closure.UPCALL_CONTENT = 3; // incoming verified content
39Closure.UPCALL_INTEREST_TIMED_OUT = 4; // interest timed out
40Closure.UPCALL_CONTENT_UNVERIFIED = 5; // content that has not been verified
41Closure.UPCALL_CONTENT_BAD = 6; // verification failed
42
43/*
44 * Override this in your subclass.
45 * If you're getting strange errors in upcall()
46 * check your code whether you're returning a value.
47 */
48Closure.prototype.upcall = function(kind, upcallInfo) {
49 //dump('upcall ' + this + " " + kind + " " + upcallInfo + "\n");
50 return Closure.RESULT_OK;
51};
52
53var UpcallInfo = function UpcallInfo(ndn, interest, matchedComps, contentObject) {
54 this.ndn = ndn; // NDN object (not used)
55 this.interest = interest; // Interest object
56 this.matchedComps = matchedComps; // int
57 this.contentObject = contentObject; // Content object
58};
59
60UpcallInfo.prototype.toString = function() {
61 var ret = "ndn = " + this.ndn;
62 ret += "\nInterest = " + this.interest;
63 ret += "\nmatchedComps = " + this.matchedComps;
64 ret += "\nContentObject: " + this.contentObject;
65 return ret;
66}
Wentao Shangc0311e52012-12-03 10:38:23 -080067/**
Wentao Shang0e291c82012-12-02 23:36:29 -080068 * @author: Meki Cherkaoui, Jeff Thompson, Wentao Shang
69 * See COPYING for copyright and distribution information.
70 * This class represents the top-level object for communicating with an NDN host.
71 */
72
Wentao Shangc0311e52012-12-03 10:38:23 -080073var LOG = 0;
Wentao Shang0e291c82012-12-02 23:36:29 -080074
75/**
76 * settings is an associative array with the following defaults:
77 * {
78 * host: 'localhost',
79 * port: 9696,
80 * getTransport: function() { return new WebSocketTransport(); }
Wentao Shangc0311e52012-12-03 10:38:23 -080081 * onopen: function() { if (LOG > 3) console.log("NDN connection established."); }
82 * onclose: function() { if (LOG > 3) console.log("NDN connection closed."); }
Wentao Shang0e291c82012-12-02 23:36:29 -080083 * }
84 */
85var NDN = function NDN(settings) {
86 settings = (settings || {});
87 this.host = (settings.host || "localhost");
88 this.port = (settings.port || 9696);
89 var getTransport = (settings.getTransport || function() { return new WebSocketTransport(); });
90 this.transport = getTransport();
91 this.readyStatus = NDN.UNOPEN;
92 // Event handler
Wentao Shangc0311e52012-12-03 10:38:23 -080093 this.onopen = (settings.onopen || function() { if (LOG > 3) console.log("NDN connection established."); });
94 this.onclose = (settings.onclose || function() { if (LOG > 3) console.log("NDN connection closed."); });
Wentao Shang0e291c82012-12-02 23:36:29 -080095};
96
97NDN.UNOPEN = 0; // created but not opened yet
98NDN.OPENED = 1; // connection to ccnd opened
99NDN.CLOSED = 2; // connection to ccnd closed
100
101/* Java Socket Bridge and XPCOM transport */
102
103NDN.prototype.createRoute = function(host,port){
104 this.host=host;
105 this.port=port;
106}
107
108/** Encode name as an Interest. If template is not null, use its attributes.
109 * Send the interest to host:port, read the entire response and call
110 * closure.upcall(Closure.UPCALL_CONTENT (or Closure.UPCALL_CONTENT_UNVERIFIED),
111 * new UpcallInfo(this, interest, 0, contentObject)).
112 */
113NDN.prototype.expressInterest = function(
114 // Name
115 name,
116 // Closure
117 closure,
118 // Interest
119 template) {
120 if (this.host == null || this.port == null) {
121 dump('ERROR host OR port NOT SET\n');
122 return;
123 }
124
125 var interest = new Interest(name);
126 if (template != null) {
127 interest.minSuffixComponents = template.minSuffixComponents;
128 interest.maxSuffixComponents = template.maxSuffixComponents;
129 interest.publisherPublicKeyDigest = template.publisherPublicKeyDigest;
130 interest.exclude = template.exclude;
131 interest.childSelector = template.childSelector;
132 interest.answerOriginKind = template.answerOriginKind;
133 interest.scope = template.scope;
134 interest.interestLifetime = template.interestLifetime;
135 }
136 else
Jeff Thompson84db2632012-12-09 22:31:39 -0800137 interest.interestLifetime = 4.0; // default interest timeout value in seconds.
Wentao Shang0e291c82012-12-02 23:36:29 -0800138
139 this.transport.expressInterest(this, interest, closure);
140};
141
142
143NDN.prototype.registerPrefix = function(name, closure, flag) {
144 return this.transport.registerPrefix(this, name, closure, flag);
145}
Wentao Shangc0311e52012-12-03 10:38:23 -0800146/**
Wentao Shang0e291c82012-12-02 23:36:29 -0800147 * @author: Wentao Shang
148 * See COPYING for copyright and distribution information.
Wentao Shang0e291c82012-12-02 23:36:29 -0800149 */
150
151var WebSocketTransport = function WebSocketTransport() {
152 this.ws = null;
153 this.ccndid = null;
154 this.maxBufferSize = 10000; // Currently support 10000 bytes data input, consistent with BinaryXMLEncoder
155 this.buffer = new Uint8Array(this.maxBufferSize);
Wentao Shang2b740e62012-12-07 00:02:53 -0800156 this.bufferOffset = 0;
Wentao Shang0e291c82012-12-02 23:36:29 -0800157 this.structureDecoder = new BinaryXMLStructureDecoder();
158};
159
Wentao Shang0e291c82012-12-02 23:36:29 -0800160var ccndIdFetcher = '/%C1.M.S.localhost/%C1.M.SRV/ccnd/KEY';
161
162WebSocketTransport.prototype.connectWebSocket = function(ndn) {
163 if (this.ws != null)
164 delete this.ws;
165
166 this.ws = new WebSocket('ws://' + ndn.host + ':' + ndn.port);
Wentao Shangc0311e52012-12-03 10:38:23 -0800167 if (LOG > 0) console.log('ws connection created.');
Wentao Shang0e291c82012-12-02 23:36:29 -0800168
169 this.ws.binaryType = "arraybuffer";
170
171 var self = this;
172 this.ws.onmessage = function(ev) {
173 var result = ev.data;
174 //console.log('RecvHandle called.');
175
176 if(result == null || result == undefined || result == "" ) {
177 console.log('INVALID ANSWER');
178 } else if (result instanceof ArrayBuffer) {
179 var bytearray = new Uint8Array(result);
180
Wentao Shangc0311e52012-12-03 10:38:23 -0800181 if (LOG>3) console.log('BINARY RESPONSE IS ' + DataUtils.toHex(bytearray));
Wentao Shang0e291c82012-12-02 23:36:29 -0800182
183 try {
Wentao Shang2b740e62012-12-07 00:02:53 -0800184 if (bytearray.length + self.bufferOffset >= self.buffer.byteLength) {
185 if (LOG>3) {
186 console.log("NDN.ws.onmessage: buffer overflow. Accumulate received length: " + self.bufferOffset
187 + ". Current packet length: " + bytearray.length + ".");
188 }
189
Wentao Shang0e291c82012-12-02 23:36:29 -0800190 // Purge and quit.
191 delete self.structureDecoder;
192 delete self.buffer;
193 self.structureDecoder = new BinaryXMLStructureDecoder();
194 self.buffer = new Uint8Array(self.maxBufferSize);
Wentao Shang2b740e62012-12-07 00:02:53 -0800195 self.bufferOffset = 0;
Wentao Shang0e291c82012-12-02 23:36:29 -0800196 return;
197 }
198
199 /*for (var i = 0; i < bytearray.length; i++) {
200 self.buffer.push(bytearray[i]);
201 }*/
Wentao Shang2b740e62012-12-07 00:02:53 -0800202 self.buffer.set(bytearray, self.bufferOffset);
203 self.bufferOffset += bytearray.length;
Wentao Shang0e291c82012-12-02 23:36:29 -0800204
Wentao Shang2b740e62012-12-07 00:02:53 -0800205 if (!self.structureDecoder.findElementEnd(self.buffer.subarray(0, self.bufferOffset))) {
Wentao Shang0e291c82012-12-02 23:36:29 -0800206 // Need more data to decode
Wentao Shang2b740e62012-12-07 00:02:53 -0800207 if (LOG>3) console.log('Incomplete packet received. Length ' + bytearray.length + '. Wait for more input.');
Wentao Shang0e291c82012-12-02 23:36:29 -0800208 return;
209 }
Wentao Shang2b740e62012-12-07 00:02:53 -0800210 if (LOG>3) console.log('Complete packet received. Length ' + bytearray.length + '. Start decoding.');
Wentao Shang0e291c82012-12-02 23:36:29 -0800211 } catch (ex) {
212 console.log("NDN.ws.onmessage exception: " + ex);
213 return;
214 }
215
216 var decoder = new BinaryXMLDecoder(self.buffer);
217 // Dispatch according to packet type
218 if (decoder.peekStartElement(CCNProtocolDTags.Interest)) { // Interest packet
Wentao Shangc0311e52012-12-03 10:38:23 -0800219 if (LOG > 3) console.log('Interest packet received.');
Wentao Shang0e291c82012-12-02 23:36:29 -0800220
221 var interest = new Interest();
222 interest.from_ccnb(decoder);
223 if (LOG>3) console.log(interest);
224 var nameStr = escape(interest.name.getName());
Wentao Shangc0311e52012-12-03 10:38:23 -0800225 if (LOG > 3) console.log(nameStr);
Wentao Shang0e291c82012-12-02 23:36:29 -0800226
227 var entry = getEntryForRegisteredPrefix(nameStr);
228 if (entry != null) {
229 //console.log(entry);
230 entry.closure.upcall(Closure.UPCALL_INTEREST, new UpcallInfo(ndn, interest, 0, null));
231 }
232
233 } else if (decoder.peekStartElement(CCNProtocolDTags.ContentObject)) { // Content packet
Wentao Shangc0311e52012-12-03 10:38:23 -0800234 if (LOG > 3) console.log('ContentObject packet received.');
Wentao Shang0e291c82012-12-02 23:36:29 -0800235
236 var co = new ContentObject();
237 co.from_ccnb(decoder);
Wentao Shangc0311e52012-12-03 10:38:23 -0800238 if (LOG > 3) console.log(co);
Wentao Shang0e291c82012-12-02 23:36:29 -0800239 nameStr = co.name.getName();
Wentao Shangc0311e52012-12-03 10:38:23 -0800240 if (LOG > 3) console.log(nameStr);
Wentao Shang0e291c82012-12-02 23:36:29 -0800241
242 if (self.ccndid == null && nameStr.match(ccndIdFetcher) != null) {
243 // We are in starting phase, record publisherPublicKeyDigest in self.ccndid
244 if(!co.signedInfo || !co.signedInfo.publisher
245 || !co.signedInfo.publisher.publisherPublicKeyDigest) {
Wentao Shangc0311e52012-12-03 10:38:23 -0800246 console.log("Cannot contact router, close NDN now.");
Wentao Shang0e291c82012-12-02 23:36:29 -0800247
248 // Close NDN if we fail to connect to a ccn router
249 ndn.readyStatus = NDN.CLOSED;
250 ndn.onclose();
Wentao Shangc0311e52012-12-03 10:38:23 -0800251 //console.log("NDN.onclose event fired.");
Wentao Shang0e291c82012-12-02 23:36:29 -0800252 } else {
Wentao Shangc0311e52012-12-03 10:38:23 -0800253 //console.log('Connected to ccnd.');
Wentao Shang0e291c82012-12-02 23:36:29 -0800254 self.ccndid = co.signedInfo.publisher.publisherPublicKeyDigest;
255 if (LOG>3) console.log(self.ccndid);
256
257 // Call NDN.onopen after success
258 ndn.readyStatus = NDN.OPENED;
259 ndn.onopen();
Wentao Shangc0311e52012-12-03 10:38:23 -0800260 //console.log("NDN.onopen event fired.");
Wentao Shang0e291c82012-12-02 23:36:29 -0800261 }
262 } else {
263 var pitEntry = getEntryForExpressedInterest(nameStr);
264 if (pitEntry != null) {
265 //console.log(pitEntry);
Wentao Shangc0311e52012-12-03 10:38:23 -0800266
267 // Cancel interest timer
268 clearTimeout(pitEntry.closure.timerID);
269 //console.log("Clear interest timer");
270 //console.log(pitEntry.closure.timerID);
Wentao Shangbd63e462012-12-03 16:19:33 -0800271
272 // Remove PIT entry from PITTable
Jeff Thompson84db2632012-12-09 22:31:39 -0800273 var index = PITTable.indexOf(pitEntry);
Wentao Shangbd63e462012-12-03 16:19:33 -0800274 PITTable.splice(index, 1);
275
Wentao Shangc0311e52012-12-03 10:38:23 -0800276 // Raise callback
Wentao Shang0e291c82012-12-02 23:36:29 -0800277 pitEntry.closure.upcall(Closure.UPCALL_CONTENT, new UpcallInfo(ndn, null, 0, co));
278 }
279 }
280 } else {
281 console.log('Incoming packet is not Interest or ContentObject. Discard now.');
282 }
283
284 delete decoder;
285
286 // Renew StrcutureDecoder and buffer after we process a full packet
287 delete self.structureDecoder;
288 delete self.buffer;
289 self.structureDecoder = new BinaryXMLStructureDecoder();
290 self.buffer = new Uint8Array(self.maxBufferSize);
Wentao Shang2b740e62012-12-07 00:02:53 -0800291 self.bufferOffset = 0;
Wentao Shang0e291c82012-12-02 23:36:29 -0800292 }
293 }
294
295 this.ws.onopen = function(ev) {
Wentao Shangc0311e52012-12-03 10:38:23 -0800296 if (LOG > 3) console.log(ev);
297 if (LOG > 3) console.log('ws.onopen: WebSocket connection opened.');
298 if (LOG > 3) console.log('ws.onopen: ReadyState: ' + this.readyState);
Wentao Shang0e291c82012-12-02 23:36:29 -0800299
300 // Fetch ccndid now
Wentao Shangc0311e52012-12-03 10:38:23 -0800301 var interest = new Interest(new Name(ccndIdFetcher));
Jeff Thompson84db2632012-12-09 22:31:39 -0800302 interest.interestLifetime = 4.0; // seconds
303 var subarray = encodeToBinaryInterest(interest);
Wentao Shang0e291c82012-12-02 23:36:29 -0800304
Jeff Thompson84db2632012-12-09 22:31:39 -0800305 var bytes = new Uint8Array(subarray.length);
306 bytes.set(subarray);
Wentao Shang0e291c82012-12-02 23:36:29 -0800307
308 self.ws.send(bytes.buffer);
309 }
310
311 this.ws.onerror = function(ev) {
312 console.log('ws.onerror: ReadyState: ' + this.readyState);
313 console.log(ev);
314 console.log('ws.onerror: WebSocket error: ' + ev.data);
315 }
316
317 this.ws.onclose = function(ev) {
318 console.log('ws.onclose: WebSocket connection closed.');
319 self.ws = null;
320
321 // Close NDN when WebSocket is closed
322 ndn.readyStatus = NDN.CLOSED;
323 ndn.onclose();
Wentao Shangc0311e52012-12-03 10:38:23 -0800324 //console.log("NDN.onclose event fired.");
Wentao Shang0e291c82012-12-02 23:36:29 -0800325 }
326}
327
328
329// For fetching data
330var PITTable = new Array();
331
332var PITEntry = function PITEntry(interest, closure) {
333 this.interest = interest; // String
334 this.closure = closure; // Closure
335}
336
337function getEntryForExpressedInterest(name) {
338 for (var i = 0; i < PITTable.length; i++) {
339 if (name.match(PITTable[i].interest) != null)
340 return PITTable[i];
341 // TODO: handle multiple matching prefixes
342 }
343 return null;
344}
345
Wentao Shangc0311e52012-12-03 10:38:23 -0800346WebSocketTransport.prototype.expressInterest = function(ndn, interest, closure) {
347 if (this.ws != null) {
348 //TODO: check local content store first
349
350 var binaryInterest = encodeToBinaryInterest(interest);
351 var bytearray = new Uint8Array(binaryInterest.length);
352 bytearray.set(binaryInterest);
353
354 var pitEntry = new PITEntry(interest.name.getName(), closure);
355 PITTable.push(pitEntry);
356
357 this.ws.send(bytearray.buffer);
358 if (LOG > 3) console.log('ws.send() returned.');
359
360 // Set interest timer
361 closure.timerID = setTimeout(function() {
Wentao Shangbd63e462012-12-03 16:19:33 -0800362 if (LOG > 3) console.log("Interest time out.");
Wentao Shangc0311e52012-12-03 10:38:23 -0800363
364 // Remove PIT entry from PITTable
Jeff Thompson84db2632012-12-09 22:31:39 -0800365 var index = PITTable.indexOf(pitEntry);
Wentao Shangc0311e52012-12-03 10:38:23 -0800366 //console.log(PITTable);
367 PITTable.splice(index, 1);
368 //console.log(PITTable);
369 // Raise closure callback
370 closure.upcall(Closure.UPCALL_INTEREST_TIMED_OUT, new UpcallInfo(ndn, interest, 0, null));
Jeff Thompson84db2632012-12-09 22:31:39 -0800371 }, interest.interestLifetime * 1000); // convert interestLifetime from seconds to ms.
Wentao Shangc0311e52012-12-03 10:38:23 -0800372 //console.log(closure.timerID);
373 }
374 else
375 console.log('WebSocket connection is not established.');
376};
377
Wentao Shang0e291c82012-12-02 23:36:29 -0800378
379// For publishing data
380var CSTable = new Array();
381
382var CSEntry = function CSEntry(name, closure) {
383 this.name = name; // String
384 this.closure = closure; // Closure
385}
386
387function getEntryForRegisteredPrefix(name) {
388 for (var i = 0; i < CSTable.length; i++) {
389 if (CSTable[i].name.match(name) != null)
390 return CSTable[i];
391 }
392 return null;
393}
394
395WebSocketTransport.prototype.registerPrefix = function(ndn, name, closure, flag) {
396 if (this.ws != null) {
397 if (this.ccndid == null) {
398 console.log('ccnd node ID unkonwn. Cannot register prefix.');
Wentao Shangc0311e52012-12-03 10:38:23 -0800399 return -1;
Wentao Shang0e291c82012-12-02 23:36:29 -0800400 }
401
402 var fe = new ForwardingEntry('selfreg', name, null, null, 3, 2147483647);
403 var bytes = encodeForwardingEntry(fe);
404
405 var si = new SignedInfo();
406 si.setFields();
407
408 var co = new ContentObject(new Name(), si, bytes, new Signature());
409 co.sign();
410 var coBinary = encodeToBinaryContentObject(co);
411
412 //var nodename = unescape('%00%88%E2%F4%9C%91%16%16%D6%21%8E%A0c%95%A5%A6r%11%E0%A0%82%89%A6%A9%85%AB%D6%E2%065%DB%AF');
413 var nodename = this.ccndid;
414 var interestName = new Name(['ccnx', nodename, 'selfreg', coBinary]);
415
416 var interest = new Interest(interestName);
417 interest.scope = 1;
Wentao Shang0e291c82012-12-02 23:36:29 -0800418 var binaryInterest = encodeToBinaryInterest(interest);
419 // If we directly use binaryInterest.buffer to feed ws.send(),
420 // WebSocket will end up sending a packet with 10000 bytes of data.
421 // That is, WebSocket will flush the entire buffer in BinaryXMLEncoder
422 // regardless of the offset of the Uint8Array. So we have to create
423 // a new Uint8Array buffer with just the right size and copy the
424 // content from binaryInterest to the new buffer.
425 // ---Wentao
426 var bytearray = new Uint8Array(binaryInterest.length);
427 bytearray.set(binaryInterest);
Wentao Shangc0311e52012-12-03 10:38:23 -0800428 if (LOG > 3) console.log('Send Interest registration packet.');
Wentao Shang0e291c82012-12-02 23:36:29 -0800429
430 var csEntry = new CSEntry(name.getName(), closure);
431 CSTable.push(csEntry);
432
433 this.ws.send(bytearray.buffer);
434
435 return 0;
436 } else {
437 console.log('WebSocket connection is not established.');
438 return -1;
439 }
440}
441
Wentao Shangbd63e462012-12-03 16:19:33 -0800442/**
Wentao Shang0e291c82012-12-02 23:36:29 -0800443 * @author: Meki Cheraoui
444 * See COPYING for copyright and distribution information.
445 * This class contains all CCNx tags
446 */
447
448
449var CCNProtocolDTags = {
450
451 /**
452 * Note if you add one of these, add it to the reverse string map as well.
453 * Emphasize getting the work done at compile time over trying to make something
454 * flexible and developer error-proof.
455 */
456
457 Any : 13,
458 Name : 14,
459 Component : 15,
460 Certificate : 16,
461 Collection : 17,
462 CompleteName : 18,
463 Content : 19,
464 SignedInfo : 20,
465 ContentDigest : 21,
466 ContentHash : 22,
467 Count : 24,
468 Header : 25,
469 Interest : 26, /* 20090915 */
470 Key : 27,
471 KeyLocator : 28,
472 KeyName : 29,
473 Length : 30,
474 Link : 31,
475 LinkAuthenticator : 32,
476 NameComponentCount : 33, /* DeprecatedInInterest */
477 RootDigest : 36,
478 Signature : 37,
479 Start : 38,
480 Timestamp : 39,
481 Type : 40,
482 Nonce : 41,
483 Scope : 42,
484 Exclude : 43,
485 Bloom : 44,
486 BloomSeed : 45,
487 AnswerOriginKind : 47,
488 InterestLifetime : 48,
489 Witness : 53,
490 SignatureBits : 54,
491 DigestAlgorithm : 55,
492 BlockSize : 56,
493 FreshnessSeconds : 58,
494 FinalBlockID : 59,
495 PublisherPublicKeyDigest : 60,
496 PublisherCertificateDigest : 61,
497 PublisherIssuerKeyDigest : 62,
498 PublisherIssuerCertificateDigest : 63,
499 ContentObject : 64, /* 20090915 */
500 WrappedKey : 65,
501 WrappingKeyIdentifier : 66,
502 WrapAlgorithm : 67,
503 KeyAlgorithm : 68,
504 Label : 69,
505 EncryptedKey : 70,
506 EncryptedNonceKey : 71,
507 WrappingKeyName : 72,
508 Action : 73,
509 FaceID : 74,
510 IPProto : 75,
511 Host : 76,
512 Port : 77,
513 MulticastInterface : 78,
514 ForwardingFlags : 79,
515 FaceInstance : 80,
516 ForwardingEntry : 81,
517 MulticastTTL : 82,
518 MinSuffixComponents : 83,
519 MaxSuffixComponents : 84,
520 ChildSelector : 85,
521 RepositoryInfo : 86,
522 Version : 87,
523 RepositoryVersion : 88,
524 GlobalPrefix : 89,
525 LocalName : 90,
526 Policy : 91,
527 Namespace : 92,
528 GlobalPrefixName : 93,
529 PolicyVersion : 94,
530 KeyValueSet : 95,
531 KeyValuePair : 96,
532 IntegerValue : 97,
533 DecimalValue : 98,
534 StringValue : 99,
535 BinaryValue : 100,
536 NameValue : 101,
537 Entry : 102,
538 ACL : 103,
539 ParameterizedName : 104,
540 Prefix : 105,
541 Suffix : 106,
542 Root : 107,
543 ProfileName : 108,
544 Parameters : 109,
545 InfoString : 110,
546 // 111 unallocated
547 StatusResponse : 112,
548 StatusCode : 113,
549 StatusText : 114,
550
551 // Sync protocol
552 SyncNode : 115,
553 SyncNodeKind : 116,
554 SyncNodeElement : 117,
555 SyncVersion : 118,
556 SyncNodeElements : 119,
557 SyncContentHash : 120,
558 SyncLeafCount : 121,
559 SyncTreeDepth : 122,
560 SyncByteCount : 123,
561 ConfigSlice : 124,
562 ConfigSliceList : 125,
563 ConfigSliceOp : 126,
564
565 // Remember to keep in sync with schema/tagnames.csvsdict
566 CCNProtocolDataUnit : 17702112,
567 CCNPROTOCOL_DATA_UNIT : "CCNProtocolDataUnit"
568};
569
570var CCNProtocolDTagsStrings = [
571 null, null, null, null, null, null, null, null, null, null, null,
572 null, null,
573 "Any", "Name", "Component", "Certificate", "Collection", "CompleteName",
574 "Content", "SignedInfo", "ContentDigest", "ContentHash", null, "Count", "Header",
575 "Interest", "Key", "KeyLocator", "KeyName", "Length", "Link", "LinkAuthenticator",
576 "NameComponentCount", null, null, "RootDigest", "Signature", "Start", "Timestamp", "Type",
577 "Nonce", "Scope", "Exclude", "Bloom", "BloomSeed", null, "AnswerOriginKind",
578 "InterestLifetime", null, null, null, null, "Witness", "SignatureBits", "DigestAlgorithm", "BlockSize",
579 null, "FreshnessSeconds", "FinalBlockID", "PublisherPublicKeyDigest", "PublisherCertificateDigest",
580 "PublisherIssuerKeyDigest", "PublisherIssuerCertificateDigest", "ContentObject",
581 "WrappedKey", "WrappingKeyIdentifier", "WrapAlgorithm", "KeyAlgorithm", "Label",
582 "EncryptedKey", "EncryptedNonceKey", "WrappingKeyName", "Action", "FaceID", "IPProto",
583 "Host", "Port", "MulticastInterface", "ForwardingFlags", "FaceInstance",
584 "ForwardingEntry", "MulticastTTL", "MinSuffixComponents", "MaxSuffixComponents", "ChildSelector",
585 "RepositoryInfo", "Version", "RepositoryVersion", "GlobalPrefix", "LocalName",
586 "Policy", "Namespace", "GlobalPrefixName", "PolicyVersion", "KeyValueSet", "KeyValuePair",
587 "IntegerValue", "DecimalValue", "StringValue", "BinaryValue", "NameValue", "Entry",
588 "ACL", "ParameterizedName", "Prefix", "Suffix", "Root", "ProfileName", "Parameters",
589 "InfoString", null,
590 "StatusResponse", "StatusCode", "StatusText", "SyncNode", "SyncNodeKind", "SyncNodeElement",
591 "SyncVersion", "SyncNodeElements", "SyncContentHash", "SyncLeafCount", "SyncTreeDepth", "SyncByteCount",
592 "ConfigSlice", "ConfigSliceList", "ConfigSliceOp" ];
593
594
595//TESTING
596//console.log(exports.CCNProtocolDTagsStrings[17]);
597
Wentao Shangbd63e462012-12-03 16:19:33 -0800598/**
Wentao Shang0e291c82012-12-02 23:36:29 -0800599 * @author: Meki Cheraoui
600 * See COPYING for copyright and distribution information.
601 * This class represents CCNTime Objects
602 */
603
604var CCNTime = function CCNTime(
605
606 input) {
607
608
609
610
611 this.NANOS_MAX = 999877929;
612
613 /*if(typeof input =='object'){
614 this.longDate = DataUtils.byteArrayToUnsignedLong(input);
615 this.binaryDate = input;
616 }*/
617 if(typeof input =='number'){
618 this.msec = input;
619 //this.binaryDate = DataUtils.unsignedLongToByteArray(input);
620
621 }
622 else{
623 if(LOG>1) console.log('UNRECOGNIZED TYPE FOR TIME');
624 }
625};
626
627
628CCNTime.prototype.getJavascriptDate = function(){
629 var d = new Date();
630 d.setTime( this.msec );
631 return d
632};
633
634 /**
635 * Create a CCNTime
636 * @param timestamp source timestamp to initialize from, some precision will be lost
637 */
638
639
640 /**
641 * Create a CCNTime from its binary encoding
642 * @param binaryTime12 the binary representation of a CCNTime
643 */
644/*CCNTime.prototype.setDateBinary = function(
645 //byte []
646 binaryTime12) {
647
648
649 if ((null == binaryTime12) || (binaryTime12.length == 0)) {
650 throw new IllegalArgumentException("Invalid binary time!");
651 }
652
653
654 value = 0;
655 for(i = 0; i < binaryTime12.length; i++) {
656 value = value << 8;
657 b = (binaryTime12[i]) & 0xFF;
658 value |= b;
659 }
660
661 //this.date = new Date(value);
662
663};
664
665//byte[]
666CCNTime.prototype.toBinaryTime = function() {
667
668 return this.msec; //unsignedLongToByteArray(this.date.getTime());
669
670}*/
671/*
672unsignedLongToByteArray= function( value) {
673 if( 0 == value )
674 return [0];
675
676 if( 0 <= value && value <= 0x00FF ) {
677 //byte []
678 bb = new Array[1];
679 bb[0] = (value & 0x00FF);
680 return bb;
681 }
682
683
684 //byte []
685 out = null;
686 //int
687 offset = -1;
688 for(var i = 7; i >=0; --i) {
689 //byte
690 b = ((value >> (i * 8)) & 0xFF);
691 if( out == null && b != 0 ) {
692 out = new Array(i+1);//byte[i+1];
693 offset = i;
694 }
695 if( out != null )
696 out[ offset - i ] = b;
697 }
698 return out;
699}*/
700
Wentao Shangbd63e462012-12-03 16:19:33 -0800701/**
Wentao Shang0e291c82012-12-02 23:36:29 -0800702 * @author: Meki Cheraoui, Jeff Thompson
703 * See COPYING for copyright and distribution information.
704 * This class represents a Name as an array of components where each is a byte array.
705 */
706
707/*
708 * Create a new Name from _components.
709 * If _components is a string, parse it as a URI. Otherwise it is an array of components
710 * where each is a string, byte array, ArrayBuffer or Uint8Array.
711 * Convert and store as an array of Uint8Array.
712 * If a component is a string, encode as utf8.
713 */
714var Name = function Name(_components){
715 if( typeof _components == 'string') {
716 if(LOG>3)console.log('Content Name String '+_components);
717 this.components = Name.createNameArray(_components);
718 }
719 else if(typeof _components === 'object'){
720 if(LOG>4)console.log('Content Name Array '+_components);
721 this.components = [];
722 for (var i = 0; i < _components.length; ++i)
723 this.add(_components[i]);
724 }
725 else if(_components==null)
726 this.components =[];
727 else
728 if(LOG>1)console.log("NO CONTENT NAME GIVEN");
729};
730
731Name.prototype.getName = function() {
732 return this.to_uri();
733};
734
735/* Parse name as a URI and return an array of Uint8Array components.
736 *
737 */
738Name.createNameArray = function(name) {
739 name = name.trim();
740 if (name.length <= 0)
741 return [];
742
743 var iColon = name.indexOf(':');
744 if (iColon >= 0) {
745 // Make sure the colon came before a '/'.
746 var iFirstSlash = name.indexOf('/');
747 if (iFirstSlash < 0 || iColon < iFirstSlash)
748 // Omit the leading protocol such as ndn:
749 name = name.substr(iColon + 1, name.length - iColon - 1).trim();
750 }
751
752 if (name[0] == '/') {
753 if (name.length >= 2 && name[1] == '/') {
754 // Strip the authority following "//".
755 var iAfterAuthority = name.indexOf('/', 2);
756 if (iAfterAuthority < 0)
757 // Unusual case: there was only an authority.
758 return [];
759 else
760 name = name.substr(iAfterAuthority + 1, name.length - iAfterAuthority - 1).trim();
761 }
762 else
763 name = name.substr(1, name.length - 1).trim();
764 }
765
766 var array = name.split('/');
767
768 // Unescape the components.
769 for (var i = 0; i < array.length; ++i) {
770 var component = unescape(array[i].trim());
771
772 if (component.match(/[^.]/) == null) {
773 // Special case for component of only periods.
774 if (component.length <= 2) {
775 // Zero, one or two periods is illegal. Ignore this componenent to be
776 // consistent with the C implmentation.
777 // This also gets rid of a trailing '/'.
778 array.splice(i, 1);
779 --i;
780 continue;
781 }
782 else
783 // Remove 3 periods.
784 array[i] = component.substr(3, component.length - 3);
785 }
786 else
787 array[i] = component;
788
789 // Change the component to Uint8Array now.
790 array[i] = DataUtils.toNumbersFromString(array[i]);
791 }
792
793 return array;
794}
795
796
797Name.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
798 decoder.readStartElement(this.getElementLabel());
799
800
801 this.components = new Array(); //new ArrayList<byte []>();
802
803 while (decoder.peekStartElement(CCNProtocolDTags.Component)) {
804 this.add(decoder.readBinaryElement(CCNProtocolDTags.Component));
805 }
806
807 decoder.readEndElement();
808};
809
810Name.prototype.to_ccnb = function(/*XMLEncoder*/ encoder) {
811
812 if( this.components ==null )
813 throw new Error("CANNOT ENCODE EMPTY CONTENT NAME");
814
815 encoder.writeStartElement(this.getElementLabel());
816 var count = this.components.length;
817 for (var i=0; i < count; i++) {
818 encoder.writeElement(CCNProtocolDTags.Component, this.components[i]);
819 }
820 encoder.writeEndElement();
821};
822
823Name.prototype.getElementLabel = function(){
824 return CCNProtocolDTags.Name;
825};
826
827/*
828 * component is a string, byte array, ArrayBuffer or Uint8Array.
829 * Convert to Uint8Array and add to this Name.
830 * If a component is a string, encode as utf8.
831 * Return the converted value.
832 */
833Name.prototype.add = function(component){
834 var result;
835 if(typeof component == 'string')
836 result = DataUtils.stringToUtf8Array(component);
837 else if(typeof component == 'object' && component instanceof Uint8Array)
838 result = new Uint8Array(component);
839 else if(typeof component == 'object' && component instanceof ArrayBuffer) {
840 // Make a copy. Don't use ArrayBuffer.slice since it isn't always supported.
841 result = new Uint8Array(new ArrayBuffer(component.byteLength));
842 result.set(new Uint8Array(component));
843 }
844 else if(typeof component == 'object')
845 // Assume component is a byte array. We can't check instanceof Array because
846 // this doesn't work in JavaScript if the array comes from a different module.
847 result = new Uint8Array(component);
848 else
849 throw new Error("Cannot add Name element at index " + this.components.length +
850 ": Invalid type");
851
852 return this.components.push(result);
853};
854
855// Return the escaped name string according to "CCNx URI Scheme".
856Name.prototype.to_uri = function() {
857 var result = "";
858
859 for(var i = 0; i < this.components.length; ++i)
860 result += "/"+ Name.toEscapedString(this.components[i]);
861
862 return result;
863};
864
865/*
866 * Return a new Name with the first nComponents components of this Name.
867 */
868Name.prototype.getPrefix = function(nComponents) {
869 return new Name(this.components.slice(0, nComponents));
870}
871
872/*
873 * Return a new ArrayBuffer of the component at i.
874 */
875Name.prototype.getComponent = function(i) {
876 var result = new ArrayBuffer(this.components[i].length);
877 new Uint8Array(result).set(this.components[i]);
878 return result;
879}
880
881/*
882 * The "file name" in a name is the last component that isn't blank and doesn't start with one of the
883 * special marker octets (for version, etc.). Return the index in this.components of
884 * the file name, or -1 if not found.
885 */
886Name.prototype.indexOfFileName = function() {
887 for (var i = this.components.length - 1; i >= 0; --i) {
888 var component = this.components[i];
889 if (component.length <= 0)
890 continue;
891
892 if (component[0] == 0 || component[0] == 0xC0 || component[0] == 0xC1 ||
893 (component[0] >= 0xF5 && component[0] <= 0xFF))
894 continue;
895
896 return i;
897 }
898
899 return -1;
900}
901
Wentao Shangc0311e52012-12-03 10:38:23 -0800902/*
903 * Find the last component in name that has a ContentDigest and return the digest value as Uint8Array,
904 * or null if not found.
905 * A ContentDigest component is Name.ContentDigestPrefix + 32 bytes + Name.ContentDigestSuffix.
906 */
907Name.prototype.getContentDigestValue = function() {
908 var digestComponentLength = Name.ContentDigestPrefix.length + 32 + Name.ContentDigestSuffix.length;
909 for (var i = this.components.length - 1; i >= 0; --i) {
910 // Check for the correct length and equal ContentDigestPrefix and ContentDigestSuffix.
911 if (this.components[i].length == digestComponentLength &&
912 DataUtils.arraysEqual(this.components[i].subarray(0, Name.ContentDigestPrefix.length),
913 Name.ContentDigestPrefix) &&
914 DataUtils.arraysEqual(this.components[i].subarray
915 (this.components[i].length - Name.ContentDigestSuffix.length, this.components[i].length),
916 Name.ContentDigestSuffix))
917 return this.components[i].subarray
918 (Name.ContentDigestPrefix.length, Name.ContentDigestPrefix.length + 32);
919 }
920
921 return null;
922}
923
924// Meta GUID "%C1.M.G%C1" + ContentDigest with a 32 byte BLOB.
925Name.ContentDigestPrefix = new Uint8Array([0xc1, 0x2e, 0x4d, 0x2e, 0x47, 0xc1, 0x01, 0xaa, 0x02, 0x85]);
926Name.ContentDigestSuffix = new Uint8Array([0x00]);
927
Wentao Shang0e291c82012-12-02 23:36:29 -0800928/**
929 * Return component as an escaped string according to "CCNx URI Scheme".
930 * We can't use encodeURIComponent because that doesn't encode all the characters we want to.
931 */
932Name.toEscapedString = function(component) {
933 var result = "";
934 var gotNonDot = false;
935 for (var i = 0; i < component.length; ++i) {
936 if (component[i] != 0x2e) {
937 gotNonDot = true;
938 break;
939 }
940 }
941 if (!gotNonDot) {
942 // Special case for component of zero or more periods. Add 3 periods.
943 result = "...";
944 for (var i = 0; i < component.length; ++i)
945 result += ".";
946 }
947 else {
948 for (var i = 0; i < component.length; ++i) {
949 var value = component[i];
950 // Check for 0-9, A-Z, a-z, (+), (-), (.), (_)
951 if (value >= 0x30 && value <= 0x39 || value >= 0x41 && value <= 0x5a ||
952 value >= 0x61 && value <= 0x7a || value == 0x2b || value == 0x2d ||
953 value == 0x2e || value == 0x5f)
954 result += String.fromCharCode(value);
955 else
956 result += "%" + (value < 16 ? "0" : "") + value.toString(16).toUpperCase();
957 }
958 }
959 return result;
960};
Wentao Shangbd63e462012-12-03 16:19:33 -0800961/**
Wentao Shang0e291c82012-12-02 23:36:29 -0800962 * @author: Meki Cheraoui
963 * See COPYING for copyright and distribution information.
964 * This class represents ContentObject Objects
965 */
966var ContentObject = function ContentObject(_name,_signedInfo,_content,_signature){
967
968
969 if (typeof _name === 'string'){
970 this.name = new Name(_name);
971 }
972 else{
973 //TODO Check the class of _name
974 this.name = _name;
975 }
976 this.signedInfo = _signedInfo;
977 this.content=_content;
978 this.signature = _signature;
979
980
981 this.startSIG = null;
982 this.endSIG = null;
983
984 this.startSignedInfo = null;
985 this.endContent = null;
986
987 this.rawSignatureData = null;
988};
989
990ContentObject.prototype.sign = function(){
991
992 var n1 = this.encodeObject(this.name);
993 var n2 = this.encodeObject(this.signedInfo);
994 var n3 = this.encodeContent();
995 /*console.log('sign: ');
996 console.log(n1);
997 console.log(n2);
998 console.log(n3);*/
999
1000 //var n = n1.concat(n2,n3);
1001 var tempBuf = new ArrayBuffer(n1.length + n2.length + n3.length);
1002 var n = new Uint8Array(tempBuf);
1003 //console.log(n);
1004 n.set(n1, 0);
1005 //console.log(n);
1006 n.set(n2, n1.length);
1007 //console.log(n);
1008 n.set(n3, n1.length + n2.length);
1009 //console.log(n);
1010
1011 if(LOG>4)console.log('Signature Data is (binary) '+n);
1012
1013 if(LOG>4)console.log('Signature Data is (RawString)');
1014
1015 if(LOG>4)console.log( DataUtils.toString(n) );
1016
1017 //var sig = DataUtils.toString(n);
1018
1019
1020 var rsa = new RSAKey();
1021
1022 rsa.readPrivateKeyFromPEMString(globalKeyManager.privateKey);
1023
1024 //var hSig = rsa.signString(sig, "sha256");
1025
1026 var hSig = rsa.signByteArrayWithSHA256(n);
1027
1028
1029 if(LOG>4)console.log('SIGNATURE SAVED IS');
1030
1031 if(LOG>4)console.log(hSig);
1032
1033 if(LOG>4)console.log( DataUtils.toNumbers(hSig.trim()));
1034
1035 this.signature.signature = DataUtils.toNumbers(hSig.trim());
1036
1037
1038};
1039
1040ContentObject.prototype.encodeObject = function encodeObject(obj){
1041 var enc = new BinaryXMLEncoder();
1042
1043 obj.to_ccnb(enc);
1044
1045 var num = enc.getReducedOstream();
1046
1047 return num;
1048
1049
1050};
1051
1052ContentObject.prototype.encodeContent = function encodeContent(obj){
1053 var enc = new BinaryXMLEncoder();
1054
1055 enc.writeElement(CCNProtocolDTags.Content, this.content);
1056
1057 var num = enc.getReducedOstream();
1058
1059 return num;
1060
1061
1062};
1063
1064ContentObject.prototype.saveRawData = function(bytes){
1065
1066 var sigBits = bytes.subarray(this.startSIG, this.endSIG);
1067
1068 this.rawSignatureData = sigBits;
1069};
1070
1071ContentObject.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
1072
1073 // TODO VALIDATE THAT ALL FIELDS EXCEPT SIGNATURE ARE PRESENT
1074
1075 decoder.readStartElement(this.getElementLabel());
1076
1077
1078 if( decoder.peekStartElement(CCNProtocolDTags.Signature) ){
1079 this.signature = new Signature();
1080 this.signature.from_ccnb(decoder);
1081 }
1082
1083 //this.endSIG = decoder.offset;
1084
1085 this.startSIG = decoder.offset;
1086
1087 this.name = new Name();
1088 this.name.from_ccnb(decoder);
1089
1090 //this.startSignedInfo = decoder.offset;
1091
1092
1093 if( decoder.peekStartElement(CCNProtocolDTags.SignedInfo) ){
1094 this.signedInfo = new SignedInfo();
1095 this.signedInfo.from_ccnb(decoder);
1096 }
1097
1098 this.content = decoder.readBinaryElement(CCNProtocolDTags.Content);
1099
1100
1101 //this.endContent = decoder.offset;
1102 this.endSIG = decoder.offset;
1103
1104
1105 decoder.readEndElement();
1106
1107 this.saveRawData(decoder.istream);
1108};
1109
1110ContentObject.prototype.to_ccnb = function(/*XMLEncoder*/ encoder) {
1111
1112 //TODO verify name, SignedInfo and Signature is present
1113
1114
1115 encoder.writeStartElement(this.getElementLabel());
1116
1117
1118
1119
1120 if(null!=this.signature) this.signature.to_ccnb(encoder);
1121
1122
1123 this.startSIG = encoder.offset;
1124
1125
1126 if(null!=this.name) this.name.to_ccnb(encoder);
1127
1128 //this.endSIG = encoder.offset;
1129 //this.startSignedInfo = encoder.offset;
1130
1131
1132 if(null!=this.signedInfo) this.signedInfo.to_ccnb(encoder);
1133
1134 encoder.writeElement(CCNProtocolDTags.Content, this.content);
1135
1136
1137 this.endSIG = encoder.offset;
1138
1139 //this.endContent = encoder.offset;
1140
1141
1142 encoder.writeEndElement();
1143
1144 this.saveRawData(encoder.ostream);
1145
1146};
1147
1148ContentObject.prototype.getElementLabel= function(){return CCNProtocolDTags.ContentObject;};
1149
1150/**
1151 * Signature
1152 */
1153var Signature = function Signature(_witness,_signature,_digestAlgorithm) {
1154
1155 this.Witness = _witness;//byte [] _witness;
1156 this.signature = _signature;//byte [] _signature;
1157 this.digestAlgorithm = _digestAlgorithm//String _digestAlgorithm;
1158};
1159
Wentao Shang0e291c82012-12-02 23:36:29 -08001160Signature.prototype.from_ccnb =function( decoder) {
1161 decoder.readStartElement(this.getElementLabel());
1162
1163 if(LOG>4)console.log('STARTED DECODING SIGNATURE ');
1164
1165 if (decoder.peekStartElement(CCNProtocolDTags.DigestAlgorithm)) {
1166
1167 if(LOG>4)console.log('DIGIEST ALGORITHM FOUND');
1168 this.digestAlgorithm = decoder.readUTF8Element(CCNProtocolDTags.DigestAlgorithm);
1169 }
1170 if (decoder.peekStartElement(CCNProtocolDTags.Witness)) {
1171 if(LOG>4)console.log('WITNESS FOUND FOUND');
1172 this.Witness = decoder.readBinaryElement(CCNProtocolDTags.Witness);
1173 }
1174
1175 //FORCE TO READ A SIGNATURE
1176
1177 //if(LOG>4)console.log('SIGNATURE FOUND ');
1178 this.signature = decoder.readBinaryElement(CCNProtocolDTags.SignatureBits);
1179 if(LOG>4)console.log('READ SIGNATURE ');
1180
1181 decoder.readEndElement();
1182
1183};
1184
1185
1186Signature.prototype.to_ccnb= function( encoder){
1187
1188 if (!this.validate()) {
1189 throw new Error("Cannot encode: field values missing.");
1190 }
1191
1192 encoder.writeStartElement(this.getElementLabel());
1193
1194 if ((null != this.digestAlgorithm) && (!this.digestAlgorithm.equals(CCNDigestHelper.DEFAULT_DIGEST_ALGORITHM))) {
1195 encoder.writeElement(CCNProtocolDTags.DigestAlgorithm, OIDLookup.getDigestOID(this.DigestAlgorithm));
1196 }
1197
1198 if (null != this.Witness) {
1199 // needs to handle null witness
1200 encoder.writeElement(CCNProtocolDTags.Witness, this.Witness);
1201 }
1202
1203 encoder.writeElement(CCNProtocolDTags.SignatureBits, this.signature);
1204
1205 encoder.writeEndElement();
1206};
1207
1208Signature.prototype.getElementLabel = function() { return CCNProtocolDTags.Signature; };
1209
1210
1211Signature.prototype.validate = function() {
1212 return null != this.signature;
1213};
1214
1215
1216/**
1217 * SignedInfo
1218 */
1219var ContentType = {DATA:0, ENCR:1, GONE:2, KEY:3, LINK:4, NACK:5};
1220var ContentTypeValue = {0:0x0C04C0, 1:0x10D091,2:0x18E344,3:0x28463F,4:0x2C834A,5:0x34008A};
1221var ContentTypeValueReverse = {0x0C04C0:0, 0x10D091:1,0x18E344:2,0x28463F:3,0x2C834A:4,0x34008A:5};
1222
1223var SignedInfo = function SignedInfo(_publisher,_timestamp,_type,_locator,_freshnessSeconds,_finalBlockID){
1224
1225 //TODO, Check types
1226
1227 this.publisher = _publisher; //publisherPublicKeyDigest
1228 this.timestamp=_timestamp; // CCN Time
1229 this.type=_type; // ContentType
1230 this.locator =_locator;//KeyLocator
1231 this.freshnessSeconds =_freshnessSeconds; // Integer
1232 this.finalBlockID=_finalBlockID; //byte array
1233
1234};
1235
1236SignedInfo.prototype.setFields = function(){
1237 //BASE64 -> RAW STRING
1238
1239 //this.locator = new KeyLocator( DataUtils.toNumbersFromString(stringCertificate) ,KeyLocatorType.CERTIFICATE );
1240
1241 var publicKeyHex = globalKeyManager.publicKey;
1242
1243 if(LOG>4)console.log('PUBLIC KEY TO WRITE TO CONTENT OBJECT IS ');
1244 if(LOG>4)console.log(publicKeyHex);
1245
1246 var publicKeyBytes = DataUtils.toNumbers(globalKeyManager.publicKey) ;
1247
1248
1249
1250 //var stringCertificate = DataUtils.base64toString(globalKeyManager.certificate);
1251
1252 //if(LOG>3)console.log('string Certificate is '+stringCertificate);
1253
1254 //HEX -> BYTE ARRAY
1255 //var publisherkey = DataUtils.toNumbers(hex_sha256(stringCertificate));
1256
1257 //if(LOG>3)console.log('publisher key is ');
1258 //if(LOG>3)console.log(publisherkey);
1259
1260 var publisherKeyDigest = hex_sha256_from_bytes(publicKeyBytes);
1261
1262 this.publisher = new PublisherPublicKeyDigest( DataUtils.toNumbers( publisherKeyDigest ) );
1263
1264 //this.publisher = new PublisherPublicKeyDigest(publisherkey);
1265
1266 var d = new Date();
1267
1268 var time = d.getTime();
1269
1270
1271 this.timestamp = new CCNTime( time );
1272
1273 if(LOG>4)console.log('TIME msec is');
1274
1275 if(LOG>4)console.log(this.timestamp.msec);
1276
1277 //DATA
1278 this.type = 0;//0x0C04C0;//ContentTypeValue[ContentType.DATA];
1279
1280 //if(LOG>4)console.log('toNumbersFromString(stringCertificate) '+DataUtils.toNumbersFromString(stringCertificate));
1281
1282 if(LOG>4)console.log('PUBLIC KEY TO WRITE TO CONTENT OBJECT IS ');
1283 if(LOG>4)console.log(publicKeyBytes);
1284
1285 this.locator = new KeyLocator( publicKeyBytes ,KeyLocatorType.KEY );
1286
1287 //this.locator = new KeyLocator( DataUtils.toNumbersFromString(stringCertificate) ,KeyLocatorType.CERTIFICATE );
1288
1289};
1290
1291SignedInfo.prototype.from_ccnb = function( decoder){
1292
1293 decoder.readStartElement( this.getElementLabel() );
1294
1295 if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
1296 if(LOG>3) console.log('DECODING PUBLISHER KEY');
1297 this.publisher = new PublisherPublicKeyDigest();
1298 this.publisher.from_ccnb(decoder);
1299 }
1300
1301 if (decoder.peekStartElement(CCNProtocolDTags.Timestamp)) {
1302 this.timestamp = decoder.readDateTime(CCNProtocolDTags.Timestamp);
1303 if(LOG>4)console.log('TIMESTAMP FOUND IS '+this.timestamp);
1304
1305 }
1306
1307 if (decoder.peekStartElement(CCNProtocolDTags.Type)) {
1308 binType = decoder.readBinaryElement(CCNProtocolDTags.Type);//byte []
1309
1310
1311 //TODO Implement type of Key Reading
1312
1313 if(LOG>4)console.log('Binary Type of of Signed Info is '+binType);
1314
1315 this.type = binType;
1316
1317
1318 //TODO Implement type of Key Reading
1319
1320
1321 if (null == this.type) {
1322 throw new Error("Cannot parse signedInfo type: bytes.");
1323 }
1324
1325 } else {
1326 this.type = ContentType.DATA; // default
1327 }
1328
1329 if (decoder.peekStartElement(CCNProtocolDTags.FreshnessSeconds)) {
1330 this.freshnessSeconds = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
1331 if(LOG>4) console.log('FRESHNESS IN SECONDS IS '+ this.freshnessSeconds);
1332 }
1333
1334 if (decoder.peekStartElement(CCNProtocolDTags.FinalBlockID)) {
1335 this.finalBlockID = decoder.readBinaryElement(CCNProtocolDTags.FinalBlockID);
1336 }
1337
1338 if (decoder.peekStartElement(CCNProtocolDTags.KeyLocator)) {
1339 this.locator = new KeyLocator();
1340 this.locator.from_ccnb(decoder);
1341 }
1342
1343 decoder.readEndElement();
1344};
1345
1346SignedInfo.prototype.to_ccnb = function( encoder) {
1347 if (!this.validate()) {
1348 throw new Error("Cannot encode : field values missing.");
1349 }
1350 encoder.writeStartElement(this.getElementLabel());
1351
1352 if (null!=this.publisher) {
1353 if(LOG>3) console.log('ENCODING PUBLISHER KEY' + this.publisher.publisherPublicKeyDigest);
1354
1355 this.publisher.to_ccnb(encoder);
1356 }
1357
1358 if (null!=this.timestamp) {
1359 encoder.writeDateTime(CCNProtocolDTags.Timestamp, this.timestamp );
1360 }
1361
1362 if (null!=this.type && this.type !=0) {
1363
1364 encoder.writeElement(CCNProtocolDTags.type, this.type);
1365 }
1366
1367 if (null!=this.freshnessSeconds) {
1368 encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.freshnessSeconds);
1369 }
1370
1371 if (null!=this.finalBlockID) {
1372 encoder.writeElement(CCNProtocolDTags.FinalBlockID, this.finalBlockID);
1373 }
1374
1375 if (null!=this.locator) {
1376 this.locator.to_ccnb(encoder);
1377 }
1378
1379 encoder.writeEndElement();
1380};
1381
1382SignedInfo.prototype.valueToType = function(){
1383 //for (Entry<byte [], ContentType> entry : ContentValueTypes.entrySet()) {
1384 //if (Arrays.equals(value, entry.getKey()))
1385 //return entry.getValue();
1386 //}
1387 return null;
1388
1389};
1390
1391SignedInfo.prototype.getElementLabel = function() {
1392 return CCNProtocolDTags.SignedInfo;
1393};
1394
1395SignedInfo.prototype.validate = function() {
1396 // We don't do partial matches any more, even though encoder/decoder
1397 // is still pretty generous.
1398 if (null ==this.publisher || null==this.timestamp ||null== this.locator)
1399 return false;
1400 return true;
1401};
1402/*
1403 * Date Format 1.2.3
1404 * (c) 2007-2009 Steven Levithan <stevenlevithan.com>
1405 * MIT license
1406 *
1407 * Includes enhancements by Scott Trenda <scott.trenda.net>
1408 * and Kris Kowal <cixar.com/~kris.kowal/>
1409 *
1410 * Accepts a date, a mask, or a date and a mask.
1411 * Returns a formatted version of the given date.
1412 * The date defaults to the current date/time.
1413 * The mask defaults to dateFormat.masks.default.
1414 */
1415
1416var DateFormat = function () {
1417 var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
1418 timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
1419 timezoneClip = /[^-+\dA-Z]/g,
1420 pad = function (val, len) {
1421 val = String(val);
1422 len = len || 2;
1423 while (val.length < len) val = "0" + val;
1424 return val;
1425 };
1426
1427 // Regexes and supporting functions are cached through closure
1428 return function (date, mask, utc) {
1429 var dF = dateFormat;
1430
1431 // You can't provide utc if you skip other args (use the "UTC:" mask prefix)
1432 if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) {
1433 mask = date;
1434 date = undefined;
1435 }
1436
1437 // Passing date through Date applies Date.parse, if necessary
1438 date = date ? new Date(date) : new Date;
1439 if (isNaN(date)) throw SyntaxError("invalid date");
1440
1441 mask = String(dF.masks[mask] || mask || dF.masks["default"]);
1442
1443 // Allow setting the utc argument via the mask
1444 if (mask.slice(0, 4) == "UTC:") {
1445 mask = mask.slice(4);
1446 utc = true;
1447 }
1448
1449 var _ = utc ? "getUTC" : "get",
1450 d = date[_ + "Date"](),
1451 D = date[_ + "Day"](),
1452 m = date[_ + "Month"](),
1453 y = date[_ + "FullYear"](),
1454 H = date[_ + "Hours"](),
1455 M = date[_ + "Minutes"](),
1456 s = date[_ + "Seconds"](),
1457 L = date[_ + "Milliseconds"](),
1458 o = utc ? 0 : date.getTimezoneOffset(),
1459 flags = {
1460 d: d,
1461 dd: pad(d),
1462 ddd: dF.i18n.dayNames[D],
1463 dddd: dF.i18n.dayNames[D + 7],
1464 m: m + 1,
1465 mm: pad(m + 1),
1466 mmm: dF.i18n.monthNames[m],
1467 mmmm: dF.i18n.monthNames[m + 12],
1468 yy: String(y).slice(2),
1469 yyyy: y,
1470 h: H % 12 || 12,
1471 hh: pad(H % 12 || 12),
1472 H: H,
1473 HH: pad(H),
1474 M: M,
1475 MM: pad(M),
1476 s: s,
1477 ss: pad(s),
1478 l: pad(L, 3),
1479 L: pad(L > 99 ? Math.round(L / 10) : L),
1480 t: H < 12 ? "a" : "p",
1481 tt: H < 12 ? "am" : "pm",
1482 T: H < 12 ? "A" : "P",
1483 TT: H < 12 ? "AM" : "PM",
1484 Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
1485 o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
1486 S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
1487 };
1488
1489 return mask.replace(token, function ($0) {
1490 return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
1491 });
1492 };
1493}();
1494
1495// Some common format strings
1496DateFormat.masks = {
1497 "default": "ddd mmm dd yyyy HH:MM:ss",
1498 shortDate: "m/d/yy",
1499 mediumDate: "mmm d, yyyy",
1500 longDate: "mmmm d, yyyy",
1501 fullDate: "dddd, mmmm d, yyyy",
1502 shortTime: "h:MM TT",
1503 mediumTime: "h:MM:ss TT",
1504 longTime: "h:MM:ss TT Z",
1505 isoDate: "yyyy-mm-dd",
1506 isoTime: "HH:MM:ss",
1507 isoDateTime: "yyyy-mm-dd'T'HH:MM:ss",
1508 isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
1509};
1510
1511// Internationalization strings
1512DateFormat.i18n = {
1513 dayNames: [
1514 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
1515 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
1516 ],
1517 monthNames: [
1518 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
1519 "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
1520 ]
1521};
1522
1523// For convenience...
1524Date.prototype.format = function (mask, utc) {
1525 return dateFormat(this, mask, utc);
1526};
Wentao Shangbd63e462012-12-03 16:19:33 -08001527/**
Wentao Shang0e291c82012-12-02 23:36:29 -08001528 * @author: Meki Cheraoui
1529 * See COPYING for copyright and distribution information.
1530 * This class represents Interest Objects
1531 */
1532
1533var Interest = function Interest(_name,_faceInstance,_minSuffixComponents,_maxSuffixComponents,_publisherPublicKeyDigest, _exclude, _childSelector,_answerOriginKind,_scope,_interestLifetime,_nonce){
1534
1535 this.name = _name;
1536 this.faceInstance = _faceInstance;
1537 this.maxSuffixComponents = _maxSuffixComponents;
1538 this.minSuffixComponents = _minSuffixComponents;
1539
1540 this.publisherPublicKeyDigest = _publisherPublicKeyDigest;
1541 this.exclude = _exclude;
1542 this.childSelector = _childSelector;
1543 this.answerOriginKind = _answerOriginKind;
1544 this.scope = _scope;
1545 this.interestLifetime = _interestLifetime; // number of seconds
1546 this.nonce = _nonce;
1547};
1548
1549Interest.RECURSIVE_POSTFIX = "*";
1550
1551Interest.CHILD_SELECTOR_LEFT = 0;
1552Interest.CHILD_SELECTOR_RIGHT = 1;
1553Interest.ANSWER_CONTENT_STORE = 1;
1554Interest.ANSWER_GENERATED = 2;
1555Interest.ANSWER_STALE = 4; // Stale answer OK
1556Interest.MARK_STALE = 16; // Must have scope 0. Michael calls this a "hack"
1557
1558Interest.DEFAULT_ANSWER_ORIGIN_KIND = Interest.ANSWER_CONTENT_STORE | Interest.ANSWER_GENERATED;
1559
1560
1561Interest.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
1562
1563 decoder.readStartElement(CCNProtocolDTags.Interest);
1564
1565 this.name = new Name();
1566 this.name.from_ccnb(decoder);
1567
1568 if (decoder.peekStartElement(CCNProtocolDTags.MinSuffixComponents))
1569 this.minSuffixComponents = decoder.readIntegerElement(CCNProtocolDTags.MinSuffixComponents);
1570
1571 if (decoder.peekStartElement(CCNProtocolDTags.MaxSuffixComponents))
1572 this.maxSuffixComponents = decoder.readIntegerElement(CCNProtocolDTags.MaxSuffixComponents);
1573
1574 if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
1575 this.publisherPublicKeyDigest = new PublisherPublicKeyDigest();
1576 this.publisherPublicKeyDigest.from_ccnb(decoder);
1577 }
1578
1579 if (decoder.peekStartElement(CCNProtocolDTags.Exclude)) {
1580 this.exclude = new Exclude();
1581 this.exclude.from_ccnb(decoder);
1582 }
1583
1584 if (decoder.peekStartElement(CCNProtocolDTags.ChildSelector))
1585 this.childSelector = decoder.readIntegerElement(CCNProtocolDTags.ChildSelector);
1586
1587 if (decoder.peekStartElement(CCNProtocolDTags.AnswerOriginKind))
1588 this.answerOriginKind = decoder.readIntegerElement(CCNProtocolDTags.AnswerOriginKind);
1589
1590 if (decoder.peekStartElement(CCNProtocolDTags.Scope))
1591 this.scope = decoder.readIntegerElement(CCNProtocolDTags.Scope);
1592
1593 if (decoder.peekStartElement(CCNProtocolDTags.InterestLifetime))
1594 this.interestLifetime = DataUtils.bigEndianToUnsignedInt
1595 (decoder.readBinaryElement(CCNProtocolDTags.InterestLifetime)) / 4096;
1596
1597 if (decoder.peekStartElement(CCNProtocolDTags.Nonce))
1598 this.nonce = decoder.readBinaryElement(CCNProtocolDTags.Nonce);
1599
1600 decoder.readEndElement();
1601};
1602
1603Interest.prototype.to_ccnb = function(/*XMLEncoder*/ encoder){
1604 //Could check if name is present
1605
1606 encoder.writeStartElement(CCNProtocolDTags.Interest);
1607
1608 this.name.to_ccnb(encoder);
1609
1610 if (null != this.minSuffixComponents)
1611 encoder.writeElement(CCNProtocolDTags.MinSuffixComponents, this.minSuffixComponents);
1612
1613 if (null != this.maxSuffixComponents)
1614 encoder.writeElement(CCNProtocolDTags.MaxSuffixComponents, this.maxSuffixComponents);
1615
1616 if (null != this.publisherPublicKeyDigest)
1617 this.publisherPublicKeyDigest.to_ccnb(encoder);
1618
1619 if (null != this.exclude)
1620 this.exclude.to_ccnb(encoder);
1621
1622 if (null != this.childSelector)
1623 encoder.writeElement(CCNProtocolDTags.ChildSelector, this.childSelector);
1624
1625 if (this.DEFAULT_ANSWER_ORIGIN_KIND != this.answerOriginKind && this.answerOriginKind!=null)
1626 encoder.writeElement(CCNProtocolDTags.AnswerOriginKind, this.answerOriginKind);
1627
1628 if (null != this.scope)
1629 encoder.writeElement(CCNProtocolDTags.Scope, this.scope);
1630
1631 if (null != this.interestLifetime)
1632 encoder.writeElement(CCNProtocolDTags.InterestLifetime,
1633 DataUtils.nonNegativeIntToBigEndian(this.interestLifetime * 4096));
1634
1635 if (null != this.nonce)
1636 encoder.writeElement(CCNProtocolDTags.Nonce, this.nonce);
1637
1638 encoder.writeEndElement();
1639
1640};
1641
1642Interest.prototype.matches_name = function(/*Name*/ name){
1643 var i_name = this.name.components;
1644 var o_name = name.components;
1645
1646 // The intrest name is longer than the name we are checking it against.
1647 if (i_name.length > o_name.length)
1648 return false;
1649
1650 // Check if at least one of given components doesn't match.
1651 for (var i = 0; i < i_name.length; ++i) {
1652 if (!DataUtils.arraysEqual(i_name[i], o_name[i]))
1653 return false;
1654 }
1655
1656 return true;
1657}
1658
1659/**
1660 * Exclude
1661 */
1662var Exclude = function Exclude(_values){
1663
1664 this.OPTIMUM_FILTER_SIZE = 100;
1665
1666
1667 this.values = _values; //array of elements
1668
1669}
1670
1671Exclude.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
1672
1673
1674
1675 decoder.readStartElement(this.getElementLabel());
1676
1677 //TODO APPLY FILTERS/EXCLUDE
1678
1679 //TODO
1680 /*var component;
1681 var any = false;
1682 while ((component = decoder.peekStartElement(CCNProtocolDTags.Component)) ||
1683 (any = decoder.peekStartElement(CCNProtocolDTags.Any)) ||
1684 decoder.peekStartElement(CCNProtocolDTags.Bloom)) {
1685 var ee = component?new ExcludeComponent(): any ? new ExcludeAny() : new BloomFilter();
1686 ee.decode(decoder);
1687 _values.add(ee);
1688 }*/
1689
1690 decoder.readEndElement();
1691
1692};
1693
1694Exclude.prototype.to_ccnb=function(/*XMLEncoder*/ encoder) {
1695 if (!validate()) {
1696 throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
1697 }
1698
1699 if (empty())
1700 return;
1701
1702 encoder.writeStartElement(getElementLabel());
1703
1704 encoder.writeEndElement();
1705
1706 };
1707
1708Exclude.prototype.getElementLabel = function() { return CCNProtocolDTags.Exclude; };
1709
1710
1711/**
1712 * ExcludeAny
1713 */
1714var ExcludeAny = function ExcludeAny() {
1715
1716};
1717
1718ExcludeAny.prototype.from_ccnb = function(decoder) {
1719 decoder.readStartElement(this.getElementLabel());
1720 decoder.readEndElement();
1721};
1722
1723
1724ExcludeAny.prototype.to_ccnb = function( encoder) {
1725 encoder.writeStartElement(this.getElementLabel());
1726 encoder.writeEndElement();
1727};
1728
1729ExcludeAny.prototype.getElementLabel=function() { return CCNProtocolDTags.Any; };
1730
1731
1732/**
1733 * ExcludeComponent
1734 */
1735var ExcludeComponent = function ExcludeComponent(_body) {
1736
1737 //TODO Check BODY is an Array of componenets.
1738
1739 this.body = _body
1740};
1741
1742ExcludeComponent.prototype.from_ccnb = function( decoder) {
1743 this.body = decoder.readBinaryElement(this.getElementLabel());
1744};
1745
1746ExcludeComponent.prototype.to_ccnb = function(encoder) {
1747 encoder.writeElement(this.getElementLabel(), this.body);
1748};
1749
1750ExcludeComponent.prototype.getElementLabel = function() { return CCNProtocolDTags.Component; };
Wentao Shangbd63e462012-12-03 16:19:33 -08001751/**
Wentao Shang0e291c82012-12-02 23:36:29 -08001752 * @author: Meki Cheraoui
1753 * See COPYING for copyright and distribution information.
1754 * This class represents Key Objects
1755 */
1756
1757var Key = function Key(){
1758 /* TODO: Port from PyCCN:
1759 generateRSA()
1760 privateToDER()
1761 publicToDER()
1762 privateToPEM()
1763 publicToPEM()
1764 fromDER()
1765 fromPEM()
1766 */
1767}
1768
1769/**
1770 * KeyLocator
1771 */
1772var KeyLocatorType = {
1773 NAME:1,
1774 KEY:2,
1775 CERTIFICATE:3
1776};
1777
1778var KeyLocator = function KeyLocator(_input,_type){
1779
1780 this.type=_type;
1781
1782 if (_type==KeyLocatorType.NAME){
1783 this.keyName = _input;
1784 }
1785 else if(_type==KeyLocatorType.KEY){
1786 if(LOG>4)console.log('SET KEY');
1787 this.publicKey = _input;
1788 }
1789 else if(_type==KeyLocatorType.CERTIFICATE){
1790 this.certificate = _input;
1791 }
1792
1793};
1794
1795KeyLocator.prototype.from_ccnb = function(decoder) {
1796
1797 decoder.readStartElement(this.getElementLabel());
1798
1799 if (decoder.peekStartElement(CCNProtocolDTags.Key)) {
1800 try {
1801 encodedKey = decoder.readBinaryElement(CCNProtocolDTags.Key);
1802 // This is a DER-encoded SubjectPublicKeyInfo.
1803
1804 //TODO FIX THIS, This should create a Key Object instead of keeping bytes
1805
1806 this.publicKey = encodedKey;//CryptoUtil.getPublicKey(encodedKey);
1807 this.type = 2;
1808
1809
1810 if(LOG>4) console.log('PUBLIC KEY FOUND: '+ this.publicKey);
1811 //this.publicKey = encodedKey;
1812
1813
1814 } catch (e) {
1815 throw new Error("Cannot parse key: ", e);
1816 }
1817
1818 if (null == this.publicKey) {
1819 throw new Error("Cannot parse key: ");
1820 }
1821
1822 } else if ( decoder.peekStartElement(CCNProtocolDTags.Certificate)) {
1823 try {
1824 encodedCert = decoder.readBinaryElement(CCNProtocolDTags.Certificate);
1825
1826 /*
1827 * Certificates not yet working
1828 */
1829
1830 //CertificateFactory factory = CertificateFactory.getInstance("X.509");
1831 //this.certificate = (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(encodedCert));
1832
1833
1834 this.certificate = encodedCert;
1835 this.type = 3;
1836
1837 if(LOG>4) console.log('CERTIFICATE FOUND: '+ this.certificate);
1838
1839 } catch ( e) {
1840 throw new Error("Cannot decode certificate: " + e);
1841 }
1842 if (null == this.certificate) {
1843 throw new Error("Cannot parse certificate! ");
1844 }
1845 } else {
1846 this.type = 1;
1847
1848
1849 this.keyName = new KeyName();
1850 this.keyName.from_ccnb(decoder);
1851 }
1852 decoder.readEndElement();
1853 }
1854
1855
1856 KeyLocator.prototype.to_ccnb = function( encoder) {
1857
1858 if(LOG>4) console.log('type is is ' + this.type);
1859 //TODO Check if Name is missing
1860 if (!this.validate()) {
1861 throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
1862 }
1863
1864
1865 //TODO FIX THIS TOO
1866 encoder.writeStartElement(this.getElementLabel());
1867
1868 if (this.type == KeyLocatorType.KEY) {
1869 if(LOG>5)console.log('About to encode a public key' +this.publicKey);
1870 encoder.writeElement(CCNProtocolDTags.Key, this.publicKey);
1871
1872 } else if (this.type == KeyLocatorType.CERTIFICATE) {
1873
1874 try {
1875 encoder.writeElement(CCNProtocolDTags.Certificate, this.certificate);
1876 } catch ( e) {
1877 throw new Error("CertificateEncodingException attempting to write key locator: " + e);
1878 }
1879
1880 } else if (this.type == KeyLocatorType.NAME) {
1881
1882 this.keyName.to_ccnb(encoder);
1883 }
1884 encoder.writeEndElement();
1885
1886};
1887
1888KeyLocator.prototype.getElementLabel = function() {
1889 return CCNProtocolDTags.KeyLocator;
1890};
1891
1892KeyLocator.prototype.validate = function() {
1893 return ( (null != this.keyName) || (null != this.publicKey) || (null != this.certificate) );
1894};
1895
1896/**
1897 * KeyName is only used by KeyLocator.
1898 */
1899var KeyName = function KeyName() {
1900
1901
1902 this.contentName = this.contentName;//contentName
1903 this.publisherID =this.publisherID;//publisherID
1904
1905};
1906
1907KeyName.prototype.from_ccnb=function( decoder){
1908
1909
1910 decoder.readStartElement(this.getElementLabel());
1911
1912 this.contentName = new Name();
1913 this.contentName.from_ccnb(decoder);
1914
1915 if(LOG>4) console.log('KEY NAME FOUND: ');
1916
1917 if ( PublisherID.peek(decoder) ) {
1918 this.publisherID = new PublisherID();
1919 this.publisherID.from_ccnb(decoder);
1920 }
1921
1922 decoder.readEndElement();
1923};
1924
1925KeyName.prototype.to_ccnb = function( encoder) {
1926 if (!this.validate()) {
1927 throw new Error("Cannot encode : field values missing.");
1928 }
1929
1930 encoder.writeStartElement(this.getElementLabel());
1931
1932 this.contentName.to_ccnb(encoder);
1933 if (null != this.publisherID)
1934 this.publisherID.to_ccnb(encoder);
1935
1936 encoder.writeEndElement();
1937};
1938
1939KeyName.prototype.getElementLabel = function() { return CCNProtocolDTags.KeyName; };
1940
1941KeyName.prototype.validate = function() {
1942 // DKS -- do we do recursive validation?
1943 // null signedInfo ok
1944 return (null != this.contentName);
1945};
Wentao Shangbd63e462012-12-03 16:19:33 -08001946/**
Wentao Shang0e291c82012-12-02 23:36:29 -08001947 * @author: Meki Cheraoui
1948 * See COPYING for copyright and distribution information.
1949 * This class represents Publisher and PublisherType Objects
1950 */
1951
1952
1953var PublisherType = function PublisherType(_tag){
1954 this.KEY =(CCNProtocolDTags.PublisherPublicKeyDigest);
1955 this.CERTIFICATE= (CCNProtocolDTags.PublisherCertificateDigest);
1956 this.ISSUER_KEY= (CCNProtocolDTags.PublisherIssuerKeyDigest);
1957 this.ISSUER_CERTIFICATE =(CCNProtocolDTags.PublisherIssuerCertificateDigest);
1958
1959 this.Tag = _tag;
1960};
1961
1962var isTypeTagVal = function(tagVal) {
1963 if ((tagVal == CCNProtocolDTags.PublisherPublicKeyDigest) ||
1964 (tagVal == CCNProtocolDTags.PublisherCertificateDigest) ||
1965 (tagVal == CCNProtocolDTags.PublisherIssuerKeyDigest) ||
1966 (tagVal == CCNProtocolDTags.PublisherIssuerCertificateDigest)) {
1967 return true;
1968 }
1969 return false;
1970};
1971
1972
1973
1974
1975var PublisherID = function PublisherID() {
1976
1977 this.PUBLISHER_ID_DIGEST_ALGORITHM = "SHA-256";
1978 this.PUBLISHER_ID_LEN = 256/8;
1979
1980 //TODO, implement publisherID creation and key creation
1981
1982 //TODO implement generatePublicKeyDigest
1983 this.publisherID =null;//= generatePublicKeyDigest(key);//ByteArray
1984
1985 //TODO implement generate key
1986 //CryptoUtil.generateKeyID(PUBLISHER_ID_DIGEST_ALGORITHM, key);
1987 this.publisherType = null;//isIssuer ? PublisherType.ISSUER_KEY : PublisherType.KEY;//publisher Type
1988
1989};
1990
1991
1992PublisherID.prototype.from_ccnb = function(decoder) {
1993
1994 // We have a choice here of one of 4 binary element types.
1995 var nextTag = decoder.peekStartElementAsLong();
1996
1997 if (null == nextTag) {
1998 throw new Error("Cannot parse publisher ID.");
1999 }
2000
2001 this.publisherType = new PublisherType(nextTag);
2002
2003 if (!isTypeTagVal(nextTag)) {
2004 throw new Error("Invalid publisher ID, got unexpected type: " + nextTag);
2005 }
2006 this.publisherID = decoder.readBinaryElement(nextTag);
2007 if (null == this.publisherID) {
2008 throw new ContentDecodingException(new Error("Cannot parse publisher ID of type : " + nextTag + "."));
2009 }
2010};
2011
2012PublisherID.prototype.to_ccnb = function(encoder) {
2013 if (!this.validate()) {
2014 throw new Error("Cannot encode " + this.getClass().getName() + ": field values missing.");
2015 }
2016
2017 encoder.writeElement(this.getElementLabel(), this.publisherID);
2018};
2019
2020PublisherID.peek = function(/* XMLDecoder */ decoder) {
2021
2022 //Long
2023 nextTag = decoder.peekStartElementAsLong();
2024
2025 if (null == nextTag) {
2026 // on end element
2027 return false;
2028 }
2029 return (isTypeTagVal(nextTag));
2030 };
2031
2032PublisherID.prototype.getElementLabel = function() {
2033 return this.publisherType.Tag;
2034};
2035
2036PublisherID.prototype.validate = function(){
2037 return ((null != id() && (null != type())));
2038};
2039
2040
2041
Wentao Shangbd63e462012-12-03 16:19:33 -08002042/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002043 * @author: Meki Cheraoui
2044 * See COPYING for copyright and distribution information.
2045 * This class represents PublisherPublicKeyDigest Objects
2046 */
2047var PublisherPublicKeyDigest = function PublisherPublicKeyDigest(_pkd){
2048
2049 //this.PUBLISHER_ID_LEN = 256/8;
2050 this.PUBLISHER_ID_LEN = 512/8;
2051
2052
2053 this.publisherPublicKeyDigest = _pkd;
2054 //if( typeof _pkd == "object") this.publisherPublicKeyDigest = _pkd; // Byte Array
2055 //else if( typeof _pkd == "PublicKey") ;//TODO...
2056
2057};
2058
2059PublisherPublicKeyDigest.prototype.from_ccnb = function( decoder) {
2060
2061 this.publisherPublicKeyDigest = decoder.readBinaryElement(this.getElementLabel());
2062
2063 if(LOG>4)console.log('Publisher public key digest is ' + this.publisherPublicKeyDigest);
2064
2065 if (null == this.publisherPublicKeyDigest) {
2066 throw new Error("Cannot parse publisher key digest.");
2067 }
2068
2069 //TODO check if the length of the PublisherPublicKeyDigest is correct ( Security reason)
2070
2071 if (this.publisherPublicKeyDigest.length != this.PUBLISHER_ID_LEN) {
2072 if (LOG > 0)
2073 console.log('LENGTH OF PUBLISHER ID IS WRONG! Expected ' + this.PUBLISHER_ID_LEN + ", got " + this.publisherPublicKeyDigest.length);
2074
2075 //this.publisherPublicKeyDigest = new PublisherPublicKeyDigest(this.PublisherPublicKeyDigest).PublisherKeyDigest;
2076 }
2077 };
2078
2079PublisherPublicKeyDigest.prototype.to_ccnb= function( encoder) {
2080 //TODO Check that the ByteArray for the key is present
2081 if (!this.validate()) {
2082 throw new Error("Cannot encode : field values missing.");
2083 }
2084 if(LOG>3) console.log('PUBLISHER KEY DIGEST IS'+this.publisherPublicKeyDigest);
2085 encoder.writeElement(this.getElementLabel(), this.publisherPublicKeyDigest);
2086};
2087
2088PublisherPublicKeyDigest.prototype.getElementLabel = function() { return CCNProtocolDTags.PublisherPublicKeyDigest; };
2089
2090PublisherPublicKeyDigest.prototype.validate =function() {
2091 return (null != this.publisherPublicKeyDigest);
2092};
Wentao Shangbd63e462012-12-03 16:19:33 -08002093/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002094 * @author: Meki Cheraoui
2095 * See COPYING for copyright and distribution information.
2096 * This class represents Face Instances
2097 */
2098
2099var NetworkProtocol = { TCP:6, UDP:17};
2100
2101var FaceInstance = function FaceInstance(
2102 _action,
2103 _publisherPublicKeyDigest,
2104 _faceID,
2105 _ipProto,
2106 _host,
2107 _port,
2108 _multicastInterface,
2109 _multicastTTL,
2110 _freshnessSeconds){
2111
2112
2113 this.action = _action;
2114 this.publisherPublicKeyDigest = _publisherPublicKeyDigest;
2115 this.faceID = _faceID;
2116 this.ipProto = _ipProto;
2117 this.host = _host;
2118 this.Port = _port;
2119 this.multicastInterface =_multicastInterface;
2120 this.multicastTTL =_multicastTTL;
2121 this.freshnessSeconds = _freshnessSeconds;
2122
2123 //action ::= ("newface" | "destroyface" | "queryface")
2124 //publisherPublicKeyDigest ::= SHA-256 digest
2125 //faceID ::= nonNegativeInteger
2126 //ipProto ::= nonNegativeInteger [IANA protocol number, 6=TCP, 17=UDP]
2127 //Host ::= textual representation of numeric IPv4 or IPv6 address
2128 //Port ::= nonNegativeInteger [1..65535]
2129 //MulticastInterface ::= textual representation of numeric IPv4 or IPv6 address
2130 //MulticastTTL ::= nonNegativeInteger [1..255]
2131 //freshnessSeconds ::= nonNegativeInteger
2132
2133};
2134
2135/**
2136 * Used by NetworkObject to decode the object from a network stream.
2137 */
2138FaceInstance.prototype.from_ccnb = function(//XMLDecoder
2139 decoder) {
2140
2141 decoder.readStartElement(this.getElementLabel());
2142
2143 if (decoder.peekStartElement(CCNProtocolDTags.Action)) {
2144
2145 this.action = decoder.readUTF8Element(CCNProtocolDTags.Action);
2146
2147 }
2148 if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
2149
2150 this.publisherPublicKeyDigest = new PublisherPublicKeyDigest();
2151 this.publisherPublicKeyDigest.from_ccnb(decoder);
2152
2153 }
2154 if (decoder.peekStartElement(CCNProtocolDTags.FaceID)) {
2155
2156 this.faceID = decoder.readIntegerElement(CCNProtocolDTags.FaceID);
2157
2158 }
2159 if (decoder.peekStartElement(CCNProtocolDTags.IPProto)) {
2160
2161 //int
2162 var pI = decoder.readIntegerElement(CCNProtocolDTags.IPProto);
2163
2164 this.ipProto = null;
2165
2166 if (NetworkProtocol.TCP == pI) {
2167
2168 this.ipProto = NetworkProtocol.TCP;
2169
2170 } else if (NetworkProtocol.UDP == pI) {
2171
2172 this.ipProto = NetworkProtocol.UDP;
2173
2174 } else {
2175
2176 throw new Error("FaceInstance.decoder. Invalid " +
2177 CCNProtocolDTags.tagToString(CCNProtocolDTags.IPProto) + " field: " + pI);
2178
2179 }
2180 }
2181
2182 if (decoder.peekStartElement(CCNProtocolDTags.Host)) {
2183
2184 this.host = decoder.readUTF8Element(CCNProtocolDTags.Host);
2185
2186 }
2187
2188 if (decoder.peekStartElement(CCNProtocolDTags.Port)) {
2189 this.Port = decoder.readIntegerElement(CCNProtocolDTags.Port);
2190 }
2191
2192 if (decoder.peekStartElement(CCNProtocolDTags.MulticastInterface)) {
2193 this.multicastInterface = decoder.readUTF8Element(CCNProtocolDTags.MulticastInterface);
2194 }
2195
2196 if (decoder.peekStartElement(CCNProtocolDTags.MulticastTTL)) {
2197 this.multicastTTL = decoder.readIntegerElement(CCNProtocolDTags.MulticastTTL);
2198 }
2199
2200 if (decoder.peekStartElement(CCNProtocolDTags.FreshnessSeconds)) {
2201 this.freshnessSeconds = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
2202 }
2203 decoder.readEndElement();
2204}
2205
2206/**
2207 * Used by NetworkObject to encode the object to a network stream.
2208 */
2209FaceInstance.prototype.to_ccnb = function(//XMLEncoder
2210 encoder){
2211
2212 //if (!this.validate()) {
2213 //throw new Error("Cannot encode : field values missing.");
2214 //throw new Error("")
2215 //}
2216 encoder.writeStartElement(this.getElementLabel());
2217
2218 if (null != this.action && this.action.length != 0)
2219 encoder.writeElement(CCNProtocolDTags.Action, this.action);
2220
2221 if (null != this.publisherPublicKeyDigest) {
2222 this.publisherPublicKeyDigest.to_ccnb(encoder);
2223 }
2224 if (null != this.faceID) {
2225 encoder.writeElement(CCNProtocolDTags.FaceID, this.faceID);
2226 }
2227 if (null != this.ipProto) {
2228 //encoder.writeElement(CCNProtocolDTags.IPProto, this.IpProto.value());
2229 encoder.writeElement(CCNProtocolDTags.IPProto, this.ipProto);
2230 }
2231 if (null != this.host && this.host.length != 0) {
2232 encoder.writeElement(CCNProtocolDTags.Host, this.host);
2233 }
2234 if (null != this.Port) {
2235 encoder.writeElement(CCNProtocolDTags.Port, this.Port);
2236 }
2237 if (null != this.multicastInterface && this.multicastInterface.length != 0) {
2238 encoder.writeElement(CCNProtocolDTags.MulticastInterface, this.multicastInterface);
2239 }
2240 if (null != this.multicastTTL) {
2241 encoder.writeElement(CCNProtocolDTags.MulticastTTL, this.multicastTTL);
2242 }
2243 if (null != this.freshnessSeconds) {
2244 encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.freshnessSeconds);
2245 }
2246 encoder.writeEndElement();
2247}
2248
2249
2250FaceInstance.prototype.getElementLabel= function(){return CCNProtocolDTags.FaceInstance;};
2251
Wentao Shangbd63e462012-12-03 16:19:33 -08002252/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002253 * @author: Meki Cheraoui
2254 * See COPYING for copyright and distribution information.
2255 * This class represents Forwarding Entries
2256 */
2257
2258var ForwardingEntry = function ForwardingEntry(
2259 //ActionType
2260 _action,
2261 //Name
2262 _prefixName,
2263 //PublisherPublicKeyDigest
2264 _ccndId,
2265 //Integer
2266 _faceID,
2267 //Integer
2268 _flags,
2269 //Integer
2270 _lifetime){
2271
2272
2273
2274 //String
2275 this.action = _action;
2276 //Name\
2277 this.prefixName = _prefixName;
2278 //PublisherPublicKeyDigest
2279 this.ccndID = _ccndId;
2280 //Integer
2281 this.faceID = _faceID;
2282 //Integer
2283 this.flags = _flags;
2284 //Integer
2285 this.lifetime = _lifetime; // in seconds
2286
2287};
2288
2289ForwardingEntry.prototype.from_ccnb =function(
2290 //XMLDecoder
2291 decoder)
2292 //throws ContentDecodingException
2293 {
2294 decoder.readStartElement(this.getElementLabel());
2295 if (decoder.peekStartElement(CCNProtocolDTags.Action)) {
2296 this.action = decoder.readUTF8Element(CCNProtocolDTags.Action);
2297 }
2298 if (decoder.peekStartElement(CCNProtocolDTags.Name)) {
2299 this.prefixName = new Name();
2300 this.prefixName.from_ccnb(decoder) ;
2301 }
2302 if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
2303 this.CcndId = new PublisherPublicKeyDigest();
2304 this.CcndId.from_ccnb(decoder);
2305 }
2306 if (decoder.peekStartElement(CCNProtocolDTags.FaceID)) {
2307 this.faceID = decoder.readIntegerElement(CCNProtocolDTags.FaceID);
2308 }
2309 if (decoder.peekStartElement(CCNProtocolDTags.ForwardingFlags)) {
2310 this.flags = decoder.readIntegerElement(CCNProtocolDTags.ForwardingFlags);
2311 }
2312 if (decoder.peekStartElement(CCNProtocolDTags.FreshnessSeconds)) {
2313 this.lifetime = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
2314 }
2315 decoder.readEndElement();
2316 };
2317
2318 /**
2319 * Used by NetworkObject to encode the object to a network stream.
2320 */
2321ForwardingEntry.prototype.to_ccnb =function(
2322 //XMLEncoder
2323encoder)
2324{
2325
2326
2327 //if (!validate()) {
2328 //throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
2329 //}
2330 encoder.writeStartElement(this.getElementLabel());
2331 if (null != this.action && this.action.length != 0)
2332 encoder.writeElement(CCNProtocolDTags.Action, this.action);
2333 if (null != this.prefixName) {
2334 this.prefixName.to_ccnb(encoder);
2335 }
2336 if (null != this.CcndId) {
2337 this.CcndId.to_ccnb(encoder);
2338 }
2339 if (null != this.faceID) {
2340 encoder.writeElement(CCNProtocolDTags.FaceID, this.faceID);
2341 }
2342 if (null != this.flags) {
2343 encoder.writeElement(CCNProtocolDTags.ForwardingFlags, this.flags);
2344 }
2345 if (null != this.lifetime) {
2346 encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.lifetime);
2347 }
2348 encoder.writeEndElement();
2349 };
2350
2351ForwardingEntry.prototype.getElementLabel = function() { return CCNProtocolDTags.ForwardingEntry; }
Wentao Shangbd63e462012-12-03 16:19:33 -08002352/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002353 * This class is used to encode ccnb binary elements (blob, type/value pairs).
2354 *
2355 * @author: Meki Cheraoui
2356 * See COPYING for copyright and distribution information.
2357 */
2358
2359var XML_EXT = 0x00;
2360
2361var XML_TAG = 0x01;
2362
2363var XML_DTAG = 0x02;
2364
2365var XML_ATTR = 0x03;
2366
2367var XML_DATTR = 0x04;
2368
2369var XML_BLOB = 0x05;
2370
2371var XML_UDATA = 0x06;
2372
2373var XML_CLOSE = 0x0;
2374
2375var XML_SUBTYPE_PROCESSING_INSTRUCTIONS = 16;
2376
2377
2378var XML_TT_BITS = 3;
2379var XML_TT_MASK = ((1 << XML_TT_BITS) - 1);
2380var XML_TT_VAL_BITS = XML_TT_BITS + 1;
2381var XML_TT_VAL_MASK = ((1 << (XML_TT_VAL_BITS)) - 1);
2382var XML_REG_VAL_BITS = 7;
2383var XML_REG_VAL_MASK = ((1 << XML_REG_VAL_BITS) - 1);
2384var XML_TT_NO_MORE = (1 << XML_REG_VAL_BITS); // 0x80
2385var BYTE_MASK = 0xFF;
2386var LONG_BYTES = 8;
2387var LONG_BITS = 64;
2388
2389var bits_11 = 0x0000007FF;
2390var bits_18 = 0x00003FFFF;
2391var bits_32 = 0x0FFFFFFFF;
2392
2393
2394var BinaryXMLEncoder = function BinaryXMLEncoder(){
2395 this.ostream = new Uint8Array(10000);
2396 this.offset =0;
2397 this.CODEC_NAME = "Binary";
2398};
2399
2400/*
2401 * Encode utf8Content as utf8.
2402 */
2403BinaryXMLEncoder.prototype.writeUString = function(/*String*/ utf8Content) {
2404 this.encodeUString(utf8Content, XML_UDATA);
2405};
2406
2407
2408BinaryXMLEncoder.prototype.writeBlob = function(
2409 /*Uint8Array*/ binaryContent
2410 ) {
2411
2412 if(LOG >3) console.log(binaryContent);
2413
2414 this.encodeBlob(binaryContent, binaryContent.length);
2415};
2416
2417
2418BinaryXMLEncoder.prototype.writeStartElement = function(
2419 /*String*/ tag,
2420 /*TreeMap<String,String>*/ attributes
2421 ) {
2422
2423 /*Long*/ var dictionaryVal = tag; //stringToTag(tag);
2424
2425 if (null == dictionaryVal) {
2426 this.encodeUString(tag, XML_TAG);
2427 } else {
2428 this.encodeTypeAndVal(XML_DTAG, dictionaryVal);
2429 }
2430
2431 if (null != attributes) {
2432 this.writeAttributes(attributes);
2433 }
2434};
2435
2436
2437BinaryXMLEncoder.prototype.writeEndElement = function() {
2438 this.ostream[this.offset] = XML_CLOSE;
2439 this.offset += 1;
2440}
2441
2442
2443BinaryXMLEncoder.prototype.writeAttributes = function(/*TreeMap<String,String>*/ attributes) {
2444 if (null == attributes) {
2445 return;
2446 }
2447
2448 // the keySet of a TreeMap is sorted.
2449
2450 for(var i=0; i<attributes.length;i++){
2451 var strAttr = attributes[i].k;
2452 var strValue = attributes[i].v;
2453
2454 var dictionaryAttr = stringToTag(strAttr);
2455 if (null == dictionaryAttr) {
2456 // not in dictionary, encode as attr
2457 // compressed format wants length of tag represented as length-1
2458 // to save that extra bit, as tag cannot be 0 length.
2459 // encodeUString knows to do that.
2460 this.encodeUString(strAttr, XML_ATTR);
2461 } else {
2462 this.encodeTypeAndVal(XML_DATTR, dictionaryAttr);
2463 }
2464 // Write value
2465 this.encodeUString(strValue);
2466
2467 }
2468}
2469
2470
2471//returns a string
2472stringToTag = function(/*long*/ tagVal) {
2473 if ((tagVal >= 0) && (tagVal < CCNProtocolDTagsStrings.length)) {
2474 return CCNProtocolDTagsStrings[tagVal];
2475 } else if (tagVal == CCNProtocolDTags.CCNProtocolDataUnit) {
2476 return CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT;
2477 }
2478 return null;
2479};
2480
2481//returns a Long
2482tagToString = function(/*String*/ tagName) {
2483 // the slow way, but right now we don't care.... want a static lookup for the forward direction
2484 for (var i=0; i < CCNProtocolDTagsStrings.length; ++i) {
2485 if ((null != CCNProtocolDTagsStrings[i]) && (CCNProtocolDTagsStrings[i] == tagName)) {
2486 return i;
2487 }
2488 }
2489 if (CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT == tagName) {
2490 return CCNProtocolDTags.CCNProtocolDataUnit;
2491 }
2492 return null;
2493};
2494
2495/*
2496 * If Content is a string, then encode as utf8 and write UDATA.
2497 */
2498BinaryXMLEncoder.prototype.writeElement = function(
2499 //long
2500 tag,
2501 //byte[]
2502 Content,
2503 //TreeMap<String, String>
2504 attributes
2505 ) {
2506 this.writeStartElement(tag, attributes);
2507 // Will omit if 0-length
2508
2509 if(typeof Content === 'number') {
2510 if(LOG>4) console.log('GOING TO WRITE THE NUMBER .charCodeAt(0) ' + Content.toString().charCodeAt(0) );
2511 if(LOG>4) console.log('GOING TO WRITE THE NUMBER ' + Content.toString() );
2512 if(LOG>4) console.log('type of number is ' + typeof Content.toString() );
2513
2514 this.writeUString(Content.toString());
2515 //whatever
2516 }
2517 else if(typeof Content === 'string'){
2518 if(LOG>4) console.log('GOING TO WRITE THE STRING ' + Content );
2519 if(LOG>4) console.log('type of STRING is ' + typeof Content );
2520
2521 this.writeUString(Content);
2522 }
2523 else{
2524 if(LOG>4) console.log('GOING TO WRITE A BLOB ' + Content );
2525
2526 this.writeBlob(Content);
2527 }
2528
2529 this.writeEndElement();
2530}
2531
2532
2533
2534var TypeAndVal = function TypeAndVal(_type,_val) {
2535 this.type = _type;
2536 this.val = _val;
2537
2538};
2539
2540
2541BinaryXMLEncoder.prototype.encodeTypeAndVal = function(
2542 //int
2543 type,
2544 //long
2545 val
2546 ) {
2547
2548 if(LOG>4) console.log('Encoding type '+ type+ ' and value '+ val);
2549
2550 if(LOG>4) console.log('OFFSET IS ' + this.offset);
2551
2552 if ((type > XML_UDATA) || (type < 0) || (val < 0)) {
2553 throw new Error("Tag and value must be positive, and tag valid.");
2554 }
2555
2556 // Encode backwards. Calculate how many bytes we need:
2557 var numEncodingBytes = this.numEncodingBytes(val);
2558
2559 if ((this.offset + numEncodingBytes) > this.ostream.length) {
2560 throw new Error("Buffer space of " + (this.ostream.length - this.offset) +
2561 " bytes insufficient to hold " +
2562 numEncodingBytes + " of encoded type and value.");
2563 }
2564
2565 // Bottom 4 bits of val go in last byte with tag.
2566 this.ostream[this.offset + numEncodingBytes - 1] =
2567 //(byte)
2568 (BYTE_MASK &
2569 (((XML_TT_MASK & type) |
2570 ((XML_TT_VAL_MASK & val) << XML_TT_BITS))) |
2571 XML_TT_NO_MORE); // set top bit for last byte
2572 val = val >>> XML_TT_VAL_BITS;;
2573
2574 // Rest of val goes into preceding bytes, 7 bits per byte, top bit
2575 // is "more" flag.
2576 var i = this.offset + numEncodingBytes - 2;
2577 while ((0 != val) && (i >= this.offset)) {
2578 this.ostream[i] = //(byte)
2579 (BYTE_MASK & (val & XML_REG_VAL_MASK)); // leave top bit unset
2580 val = val >>> XML_REG_VAL_BITS;
2581 --i;
2582 }
2583 if (val != 0) {
2584 throw new Error( "This should not happen: miscalculated encoding");
2585 //Log.warning(Log.FAC_ENCODING, "This should not happen: miscalculated encoding length, have " + val + " left.");
2586 }
2587 this.offset+= numEncodingBytes;
2588
2589 return numEncodingBytes;
2590};
2591
2592/*
2593 * Encode ustring as utf8.
2594 */
2595BinaryXMLEncoder.prototype.encodeUString = function(
2596 //String
2597 ustring,
2598 //byte
2599 type) {
2600
2601 if (null == ustring)
2602 return;
2603 if (type == XML_TAG || type == XML_ATTR && ustring.length == 0)
2604 return;
2605
2606 if(LOG>3) console.log("The string to write is ");
2607 if(LOG>3) console.log(ustring);
2608
2609 var strBytes = DataUtils.stringToUtf8Array(ustring);
2610
2611 this.encodeTypeAndVal(type,
2612 (((type == XML_TAG) || (type == XML_ATTR)) ?
2613 (strBytes.length-1) :
2614 strBytes.length));
2615
2616 if(LOG>3) console.log("THE string to write is ");
2617
2618 if(LOG>3) console.log(strBytes);
2619
2620 this.writeString(strBytes,this.offset);
2621 this.offset+= strBytes.length;
2622};
2623
2624
2625
2626BinaryXMLEncoder.prototype.encodeBlob = function(
2627 //Uint8Array
2628 blob,
2629 //int
2630 length) {
2631
2632
2633 if (null == blob)
2634 return;
2635
2636 if(LOG>4) console.log('LENGTH OF XML_BLOB IS '+length);
2637
2638 /*blobCopy = new Array(blob.Length);
2639
2640 for (i = 0; i < blob.length; i++) //in InStr.ToCharArray())
2641 {
2642 blobCopy[i] = blob[i];
2643 }*/
2644
2645 this.encodeTypeAndVal(XML_BLOB, length);
2646
2647 this.writeBlobArray(blob, this.offset);
2648 this.offset += length;
2649};
2650
2651var ENCODING_LIMIT_1_BYTE = ((1 << (XML_TT_VAL_BITS)) - 1);
2652var ENCODING_LIMIT_2_BYTES = ((1 << (XML_TT_VAL_BITS + XML_REG_VAL_BITS)) - 1);
2653var ENCODING_LIMIT_3_BYTES = ((1 << (XML_TT_VAL_BITS + 2 * XML_REG_VAL_BITS)) - 1);
2654
2655BinaryXMLEncoder.prototype.numEncodingBytes = function(
2656 //long
2657 x) {
2658 if (x <= ENCODING_LIMIT_1_BYTE) return (1);
2659 if (x <= ENCODING_LIMIT_2_BYTES) return (2);
2660 if (x <= ENCODING_LIMIT_3_BYTES) return (3);
2661
2662 var numbytes = 1;
2663
2664 // Last byte gives you XML_TT_VAL_BITS
2665 // Remainder each give you XML_REG_VAL_BITS
2666 x = x >>> XML_TT_VAL_BITS;
2667 while (x != 0) {
2668 numbytes++;
2669 x = x >>> XML_REG_VAL_BITS;
2670 }
2671 return (numbytes);
2672};
2673
2674BinaryXMLEncoder.prototype.writeDateTime = function(
2675 //String
2676 tag,
2677 //CCNTime
2678 dateTime) {
2679
2680 if(LOG>4)console.log('ENCODING DATE with LONG VALUE');
2681 if(LOG>4)console.log(dateTime.msec);
2682
2683 //var binarydate = DataUtils.unsignedLongToByteArray( Math.round((dateTime.msec/1000) * 4096) );
2684
2685
2686 //parse to hex
2687 var binarydate = Math.round((dateTime.msec/1000) * 4096).toString(16) ;
2688
2689 //HACK
2690 var binarydate = DataUtils.toNumbers( '0'.concat(binarydate,'0')) ;
2691
2692
2693 if(LOG>4)console.log('ENCODING DATE with BINARY VALUE');
2694 if(LOG>4)console.log(binarydate);
2695 if(LOG>4)console.log('ENCODING DATE with BINARY VALUE(HEX)');
2696 if(LOG>4)console.log(DataUtils.toHex(binarydate));
2697
2698 this.writeElement(tag, binarydate);
2699};
2700
2701BinaryXMLEncoder.prototype.writeString = function(
2702 //String
2703 input,
2704 //CCNTime
2705 offset) {
2706
2707 if(typeof input === 'string'){
2708 //console.log('went here');
2709 if(LOG>4) console.log('GOING TO WRITE A STRING');
2710 if(LOG>4) console.log(input);
2711
2712 for (i = 0; i < input.length; i++) {
2713 if(LOG>4) console.log('input.charCodeAt(i)=' + input.charCodeAt(i));
2714 this.ostream[this.offset+i] = (input.charCodeAt(i));
2715 }
2716 }
2717 else{
2718 if(LOG>4) console.log('GOING TO WRITE A STRING IN BINARY FORM');
2719 if(LOG>4) console.log(input);
2720
2721 this.writeBlobArray(input);
2722 }
2723 /*
2724 else if(typeof input === 'object'){
2725
2726 }
2727 */
2728};
2729
2730
2731BinaryXMLEncoder.prototype.writeBlobArray = function(
2732 //Uint8Array
2733 blob,
2734 //int
2735 offset) {
2736
2737 if(LOG>4) console.log('GOING TO WRITE A BLOB');
2738
2739 /*for (var i = 0; i < Blob.length; i++) {
2740 this.ostream[this.offset+i] = Blob[i];
2741 }*/
2742 this.ostream.set(blob, this.offset);
2743};
2744
2745
2746BinaryXMLEncoder.prototype.getReducedOstream = function() {
2747 return this.ostream.subarray(0, this.offset);
2748};
2749
Wentao Shangbd63e462012-12-03 16:19:33 -08002750/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002751 * This class is used to decode ccnb binary elements (blob, type/value pairs).
2752 *
2753 * @author: Meki Cheraoui
2754 * See COPYING for copyright and distribution information.
2755 */
2756
2757var XML_EXT = 0x00;
2758
2759var XML_TAG = 0x01;
2760
2761var XML_DTAG = 0x02;
2762
2763var XML_ATTR = 0x03;
2764
2765var XML_DATTR = 0x04;
2766
2767var XML_BLOB = 0x05;
2768
2769var XML_UDATA = 0x06;
2770
2771var XML_CLOSE = 0x0;
2772
2773var XML_SUBTYPE_PROCESSING_INSTRUCTIONS = 16;
2774
2775
2776var XML_TT_BITS = 3;
2777var XML_TT_MASK = ((1 << XML_TT_BITS) - 1);
2778var XML_TT_VAL_BITS = XML_TT_BITS + 1;
2779var XML_TT_VAL_MASK = ((1 << (XML_TT_VAL_BITS)) - 1);
2780var XML_REG_VAL_BITS = 7;
2781var XML_REG_VAL_MASK = ((1 << XML_REG_VAL_BITS) - 1);
2782var XML_TT_NO_MORE = (1 << XML_REG_VAL_BITS); // 0x80
2783var BYTE_MASK = 0xFF;
2784var LONG_BYTES = 8;
2785var LONG_BITS = 64;
2786
2787var bits_11 = 0x0000007FF;
2788var bits_18 = 0x00003FFFF;
2789var bits_32 = 0x0FFFFFFFF;
2790
2791
2792
2793//returns a string
2794tagToString = function(/*long*/ tagVal) {
2795 if ((tagVal >= 0) && (tagVal < CCNProtocolDTagsStrings.length)) {
2796 return CCNProtocolDTagsStrings[tagVal];
2797 } else if (tagVal == CCNProtocolDTags.CCNProtocolDataUnit) {
2798 return CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT;
2799 }
2800 return null;
2801};
2802
2803//returns a Long
2804stringToTag = function(/*String*/ tagName) {
2805 // the slow way, but right now we don't care.... want a static lookup for the forward direction
2806 for (var i=0; i < CCNProtocolDTagsStrings.length; ++i) {
2807 if ((null != CCNProtocolDTagsStrings[i]) && (CCNProtocolDTagsStrings[i] == tagName)) {
2808 return i;
2809 }
2810 }
2811 if (CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT == tagName) {
2812 return CCNProtocolDTags.CCNProtocolDataUnit;
2813 }
2814 return null;
2815};
2816
2817//console.log(stringToTag(64));
2818var BinaryXMLDecoder = function BinaryXMLDecoder(istream){
2819 var MARK_LEN=512;
2820 var DEBUG_MAX_LEN = 32768;
2821
2822 this.istream = istream;
2823 this.offset = 0;
2824};
2825
2826BinaryXMLDecoder.prototype.readAttributes = function(
2827 //TreeMap<String,String>
2828 attributes){
2829
2830 if (null == attributes) {
2831 return;
2832 }
2833
2834 try {
2835
2836 //this.TypeAndVal
2837 var nextTV = this.peekTypeAndVal();
2838
2839 while ((null != nextTV) && ((XML_ATTR == nextTV.type()) ||
2840 (XML_DATTR == nextTV.type()))) {
2841
2842 //this.TypeAndVal
2843 var thisTV = this.decodeTypeAndVal();
2844
2845 var attributeName = null;
2846 if (XML_ATTR == thisTV.type()) {
2847
2848 attributeName = this.decodeUString(thisTV.val()+1);
2849
2850 } else if (XML_DATTR == thisTV.type()) {
2851 // DKS TODO are attributes same or different dictionary?
2852 attributeName = tagToString(thisTV.val());
2853 if (null == attributeName) {
2854 throw new ContentDecodingException(new Error("Unknown DATTR value" + thisTV.val()));
2855 }
2856 }
2857
2858 var attributeValue = this.decodeUString();
2859
2860 attributes.put(attributeName, attributeValue);
2861
2862 nextTV = this.peekTypeAndVal();
2863 }
2864
2865 } catch ( e) {
2866
2867 throw new ContentDecodingException(new Error("readStartElement", e));
2868 }
2869};
2870
2871
2872BinaryXMLDecoder.prototype.initializeDecoding = function() {
2873 //if (!this.istream.markSupported()) {
2874 //throw new IllegalArgumentException(this.getClass().getName() + ": input stream must support marking!");
2875 //}
2876}
2877
2878BinaryXMLDecoder.prototype.readStartDocument = function(){
2879 // Currently no start document in binary encoding.
2880 }
2881
2882BinaryXMLDecoder.prototype.readEndDocument = function() {
2883 // Currently no end document in binary encoding.
2884 };
2885
2886BinaryXMLDecoder.prototype.readStartElement = function(
2887 //String
2888 startTag,
2889 //TreeMap<String, String>
2890 attributes) {
2891
2892
2893 //NOT SURE
2894 //if(typeof startTag == 'number')
2895 //startTag = tagToString(startTag);
2896
2897 //TypeAndVal
2898 tv = this.decodeTypeAndVal();
2899
2900 if (null == tv) {
2901 throw new ContentDecodingException(new Error("Expected start element: " + startTag + " got something not a tag."));
2902 }
2903
2904 //String
2905 var decodedTag = null;
2906 //console.log(tv);
2907 //console.log(typeof tv);
2908
2909 //console.log(XML_TAG);
2910 if (tv.type() == XML_TAG) {
2911 //console.log('got here');
2912 //Log.info(Log.FAC_ENCODING, "Unexpected: got tag in readStartElement; looking for tag " + startTag + " got length: " + (int)tv.val()+1);
2913 // Tag value represents length-1 as tags can never be empty.
2914 var valval ;
2915 if(typeof tv.val() == 'string'){
2916 valval = (parseInt(tv.val())) + 1;
2917 }
2918 else
2919 valval = (tv.val())+ 1;
2920
2921 //console.log('valval is ' +valval);
2922
2923 decodedTag = this.decodeUString(valval);
2924
2925 } else if (tv.type() == XML_DTAG) {
2926 //console.log('gothere');
2927 //console.log(tv.val());
2928 //decodedTag = tagToString(tv.val());
2929 //console.log()
2930 decodedTag = tv.val();
2931 }
2932
2933 //console.log(decodedTag);
2934 //console.log('startTag is '+startTag);
2935
2936
2937 if ((null == decodedTag) || decodedTag != startTag ) {
2938 console.log('expecting '+ startTag + ' but got '+ decodedTag);
2939 throw new ContentDecodingException(new Error("Expected start element: " + startTag + " got: " + decodedTag + "(" + tv.val() + ")"));
2940 }
2941
2942 // DKS: does not read attributes out of stream if caller doesn't
2943 // ask for them. Should possibly peek and skip over them regardless.
2944 // TODO: fix this
2945 if (null != attributes) {
2946 readAttributes(attributes);
2947 }
2948 }
2949
2950
2951BinaryXMLDecoder.prototype.readAttributes = function(
2952 //TreeMap<String,String>
2953 attributes) {
2954
2955 if (null == attributes) {
2956 return;
2957 }
2958
2959 try {
2960 // Now need to get attributes.
2961 //TypeAndVal
2962 var nextTV = this.peekTypeAndVal();
2963
2964 while ((null != nextTV) && ((XML_ATTR == nextTV.type()) ||
2965 (XML_DATTR == nextTV.type()))) {
2966
2967 // Decode this attribute. First, really read the type and value.
2968 //this.TypeAndVal
2969 var thisTV = this.decodeTypeAndVal();
2970
2971 //String
2972 var attributeName = null;
2973 if (XML_ATTR == thisTV.type()) {
2974 // Tag value represents length-1 as attribute names cannot be empty.
2975 var valval ;
2976 if(typeof tv.val() == 'string'){
2977 valval = (parseInt(tv.val())) + 1;
2978 }
2979 else
2980 valval = (tv.val())+ 1;
2981
2982 attributeName = this.decodeUString(valval);
2983
2984 } else if (XML_DATTR == thisTV.type()) {
2985 // DKS TODO are attributes same or different dictionary?
2986 attributeName = tagToString(thisTV.val());
2987 if (null == attributeName) {
2988 throw new ContentDecodingException(new Error("Unknown DATTR value" + thisTV.val()));
2989 }
2990 }
2991 // Attribute values are always UDATA
2992 //String
2993 var attributeValue = this.decodeUString();
2994
2995 //
2996 attributes.push([attributeName, attributeValue]);
2997
2998 nextTV = this.peekTypeAndVal();
2999 }
3000 } catch ( e) {
3001 throw new ContentDecodingException(new Error("readStartElement", e));
3002 }
3003};
3004
3005//returns a string
3006BinaryXMLDecoder.prototype.peekStartElementAsString = function() {
3007 //this.istream.mark(MARK_LEN);
3008
3009 //String
3010 var decodedTag = null;
3011 var previousOffset = this.offset;
3012 try {
3013 // Have to distinguish genuine errors from wrong tags. Could either use
3014 // a special exception subtype, or redo the work here.
3015 //this.TypeAndVal
3016 var tv = this.decodeTypeAndVal();
3017
3018 if (null != tv) {
3019
3020 if (tv.type() == XML_TAG) {
3021 /*if (tv.val()+1 > DEBUG_MAX_LEN) {
3022 throw new ContentDecodingException(new Error("Decoding error: length " + tv.val()+1 + " longer than expected maximum length!")(;
3023 }*/
3024
3025 // Tag value represents length-1 as tags can never be empty.
3026 var valval ;
3027 if(typeof tv.val() == 'string'){
3028 valval = (parseInt(tv.val())) + 1;
3029 }
3030 else
3031 valval = (tv.val())+ 1;
3032
3033 decodedTag = this.decodeUString(valval);
3034
3035 //Log.info(Log.FAC_ENCODING, "Unexpected: got text tag in peekStartElement; length: " + valval + " decoded tag = " + decodedTag);
3036
3037 } else if (tv.type() == XML_DTAG) {
3038 decodedTag = tagToString(tv.val());
3039 }
3040
3041 } // else, not a type and val, probably an end element. rewind and return false.
3042
3043 } catch ( e) {
3044
3045 } finally {
3046 try {
3047 this.offset = previousOffset;
3048 } catch ( e) {
3049 Log.logStackTrace(Log.FAC_ENCODING, Level.WARNING, e);
3050 throw new ContentDecodingException(new Error("Cannot reset stream! " + e.getMessage(), e));
3051 }
3052 }
3053 return decodedTag;
3054};
3055
3056BinaryXMLDecoder.prototype.peekStartElement = function(
3057 //String
3058 startTag) {
3059 //String
3060 if(typeof startTag == 'string'){
3061 var decodedTag = this.peekStartElementAsString();
3062
3063 if ((null != decodedTag) && decodedTag == startTag) {
3064 return true;
3065 }
3066 return false;
3067 }
3068 else if(typeof startTag == 'number'){
3069 var decodedTag = this.peekStartElementAsLong();
3070 if ((null != decodedTag) && decodedTag == startTag) {
3071 return true;
3072 }
3073 return false;
3074 }
3075 else{
3076 throw new ContentDecodingException(new Error("SHOULD BE STRING OR NUMBER"));
3077 }
3078}
3079//returns Long
3080BinaryXMLDecoder.prototype.peekStartElementAsLong = function() {
3081 //this.istream.mark(MARK_LEN);
3082
3083 //Long
3084 var decodedTag = null;
3085
3086 var previousOffset = this.offset;
3087
3088 try {
3089 // Have to distinguish genuine errors from wrong tags. Could either use
3090 // a special exception subtype, or redo the work here.
3091 //this.TypeAndVal
3092 var tv = this.decodeTypeAndVal();
3093
3094 if (null != tv) {
3095
3096 if (tv.type() == XML_TAG) {
3097 if (tv.val()+1 > DEBUG_MAX_LEN) {
3098 throw new ContentDecodingException(new Error("Decoding error: length " + tv.val()+1 + " longer than expected maximum length!"));
3099 }
3100
3101 var valval ;
3102 if(typeof tv.val() == 'string'){
3103 valval = (parseInt(tv.val())) + 1;
3104 }
3105 else
3106 valval = (tv.val())+ 1;
3107
3108 // Tag value represents length-1 as tags can never be empty.
3109 //String
3110 var strTag = this.decodeUString(valval);
3111
3112 decodedTag = stringToTag(strTag);
3113
3114 //Log.info(Log.FAC_ENCODING, "Unexpected: got text tag in peekStartElement; length: " + valval + " decoded tag = " + decodedTag);
3115
3116 } else if (tv.type() == XML_DTAG) {
3117 decodedTag = tv.val();
3118 }
3119
3120 } // else, not a type and val, probably an end element. rewind and return false.
3121
3122 } catch ( e) {
3123
3124 } finally {
3125 try {
3126 //this.istream.reset();
3127 this.offset = previousOffset;
3128 } catch ( e) {
3129 Log.logStackTrace(Log.FAC_ENCODING, Level.WARNING, e);
3130 throw new Error("Cannot reset stream! " + e.getMessage(), e);
3131 }
3132 }
3133 return decodedTag;
3134 };
3135
3136
3137// returns a byte[]
3138BinaryXMLDecoder.prototype.readBinaryElement = function(
3139 //long
3140 startTag,
3141 //TreeMap<String, String>
3142 attributes){
3143 //byte []
3144 var blob = null;
3145
3146 this.readStartElement(startTag, attributes);
3147 blob = this.readBlob();
3148
3149 return blob;
3150};
3151
3152
3153BinaryXMLDecoder.prototype.readEndElement = function(){
3154 if(LOG>4)console.log('this.offset is '+this.offset);
3155
3156 var next = this.istream[this.offset];
3157
3158 this.offset++;
3159 //read();
3160
3161 if(LOG>4)console.log('XML_CLOSE IS '+XML_CLOSE);
3162 if(LOG>4)console.log('next is '+next);
3163
3164 if (next != XML_CLOSE) {
3165 console.log("Expected end element, got: " + next);
3166 throw new ContentDecodingException(new Error("Expected end element, got: " + next));
3167 }
3168 };
3169
3170
3171//String
3172BinaryXMLDecoder.prototype.readUString = function(){
3173 //String
3174 var ustring = this.decodeUString();
3175 this.readEndElement();
3176 return ustring;
3177
3178 };
3179
3180
3181//returns a byte[]
3182BinaryXMLDecoder.prototype.readBlob = function() {
3183 //byte []
3184
3185 var blob = this.decodeBlob();
3186 this.readEndElement();
3187 return blob;
3188
3189 };
3190
3191
3192//CCNTime
3193BinaryXMLDecoder.prototype.readDateTime = function(
3194 //long
3195 startTag) {
3196 //byte []
3197
3198 var byteTimestamp = this.readBinaryElement(startTag);
3199
3200 //var lontimestamp = DataUtils.byteArrayToUnsignedLong(byteTimestamp);
3201
3202 byteTimestamp = DataUtils.toHex(byteTimestamp);
3203
3204
3205 byteTimestamp = parseInt(byteTimestamp, 16);
3206
3207 var lontimestamp = (byteTimestamp/ 4096) * 1000;
3208
3209 //if(lontimestamp<0) lontimestamp = - lontimestamp;
3210
3211 if(LOG>3) console.log('DECODED DATE WITH VALUE');
3212 if(LOG>3) console.log(lontimestamp);
3213
3214
3215 //CCNTime
3216 var timestamp = new CCNTime(lontimestamp);
3217 //timestamp.setDateBinary(byteTimestamp);
3218
3219 if (null == timestamp) {
3220 throw new ContentDecodingException(new Error("Cannot parse timestamp: " + DataUtils.printHexBytes(byteTimestamp)));
3221 }
3222 return timestamp;
3223};
3224
3225BinaryXMLDecoder.prototype.decodeTypeAndVal = function() {
3226
3227 /*int*/var type = -1;
3228 /*long*/var val = 0;
3229 /*boolean*/var more = true;
3230
3231 do {
3232
3233 var next = this.istream[this.offset ];
3234
3235
3236 if (next < 0) {
3237 return null;
3238 }
3239
3240 if ((0 == next) && (0 == val)) {
3241 return null;
3242 }
3243
3244 more = (0 == (next & XML_TT_NO_MORE));
3245
3246 if (more) {
3247 val = val << XML_REG_VAL_BITS;
3248 val |= (next & XML_REG_VAL_MASK);
3249 } else {
3250
3251 type = next & XML_TT_MASK;
3252 val = val << XML_TT_VAL_BITS;
3253 val |= ((next >>> XML_TT_BITS) & XML_TT_VAL_MASK);
3254 }
3255
3256 this.offset++;
3257
3258 } while (more);
3259
3260 if(LOG>3)console.log('TYPE is '+ type + ' VAL is '+ val);
3261
3262 return new TypeAndVal(type, val);
3263};
3264
3265
3266
3267//TypeAndVal
3268BinaryXMLDecoder.peekTypeAndVal = function() {
3269 //TypeAndVal
3270 var tv = null;
3271
3272 //this.istream.mark(LONG_BYTES*2);
3273
3274 var previousOffset = this.offset;
3275
3276 try {
3277 tv = this.decodeTypeAndVal();
3278 } finally {
3279 //this.istream.reset();
3280 this.offset = previousOffset;
3281 }
3282
3283 return tv;
3284};
3285
3286
3287//Uint8Array
3288BinaryXMLDecoder.prototype.decodeBlob = function(
3289 //int
3290 blobLength) {
3291
3292 if(null == blobLength){
3293 //TypeAndVal
3294 var tv = this.decodeTypeAndVal();
3295
3296 var valval ;
3297
3298 if(typeof tv.val() == 'string'){
3299 valval = (parseInt(tv.val()));
3300 }
3301 else
3302 valval = (tv.val());
3303
3304 //console.log('valval here is ' + valval);
3305 return this.decodeBlob(valval);
3306 }
3307
3308 //
3309 //Uint8Array
3310 var bytes = this.istream.subarray(this.offset, this.offset+ blobLength);
3311 this.offset += blobLength;
3312
3313 return bytes;
3314};
3315
3316var count =0;
3317
3318//String
3319BinaryXMLDecoder.prototype.decodeUString = function(
3320 //int
3321 byteLength) {
3322
3323 /*
3324 console.log('COUNT IS '+count);
3325 console.log('INPUT BYTELENGTH IS '+byteLength);
3326 count++;
3327 if(null == byteLength|| undefined == byteLength){
3328 console.log("!!!!");
3329 tv = this.decodeTypeAndVal();
3330 var valval ;
3331 if(typeof tv.val() == 'string'){
3332 valval = (parseInt(tv.val()));
3333 }
3334 else
3335 valval = (tv.val());
3336
3337 if(LOG>4) console.log('valval is ' + valval);
3338 byteLength= this.decodeUString(valval);
3339
3340 //if(LOG>4) console.log('byte Length found in type val is '+ byteLength.charCodeAt(0));
3341 byteLength = parseInt(byteLength);
3342
3343
3344 //byteLength = byteLength.charCodeAt(0);
3345 //if(LOG>4) console.log('byte Length found in type val is '+ byteLength);
3346 }
3347 if(LOG>4)console.log('byteLength is '+byteLength);
3348 if(LOG>4)console.log('type of byteLength is '+typeof byteLength);
3349
3350 stringBytes = this.decodeBlob(byteLength);
3351
3352 //console.log('String bytes are '+ stringBytes);
3353 //console.log('stringBytes);
3354
3355 if(LOG>4)console.log('byteLength is '+byteLength);
3356 if(LOG>4)console.log('this.offset is '+this.offset);
3357
3358 tempBuffer = this.istream.slice(this.offset, this.offset+byteLength);
3359 if(LOG>4)console.log('TEMPBUFFER IS' + tempBuffer);
3360 if(LOG>4)console.log( tempBuffer);
3361
3362 if(LOG>4)console.log('ADDING to offset value' + byteLength);
3363 this.offset+= byteLength;
3364 //if(LOG>3)console.log('read the String' + tempBuffer.toString('ascii'));
3365 //return tempBuffer.toString('ascii');//
3366
3367
3368 //if(LOG>3)console.log( 'STRING READ IS '+ DataUtils.getUTF8StringFromBytes(stringBytes) ) ;
3369 //if(LOG>3)console.log( 'STRING READ IS '+ DataUtils.getUTF8StringFromBytes(tempBuffer) ) ;
3370 //if(LOG>3)console.log(DataUtils.getUTF8StringFromBytes(tempBuffer) ) ;
3371 //return DataUtils.getUTF8StringFromBytes(tempBuffer);
3372
3373 if(LOG>3)console.log( 'STRING READ IS '+ DataUtils.toString(stringBytes) ) ;
3374 if(LOG>3)console.log( 'TYPE OF STRING READ IS '+ typeof DataUtils.toString(stringBytes) ) ;
3375
3376 return DataUtils.toString(stringBytes);*/
3377
3378 if(null == byteLength ){
3379 var tempStreamPosition = this.offset;
3380
3381 //TypeAndVal
3382 var tv = this.decodeTypeAndVal();
3383
3384 if(LOG>3)console.log('TV is '+tv);
3385 if(LOG>3)console.log(tv);
3386
3387 if(LOG>3)console.log('Type of TV is '+typeof tv);
3388
3389 if ((null == tv) || (XML_UDATA != tv.type())) { // if we just have closers left, will get back null
3390 //if (Log.isLoggable(Log.FAC_ENCODING, Level.FINEST))
3391 //Log.finest(Log.FAC_ENCODING, "Expected UDATA, got " + ((null == tv) ? " not a tag " : tv.type()) + ", assuming elided 0-length blob.");
3392
3393 this.offset = tempStreamPosition;
3394
3395 return "";
3396 }
3397
3398 return this.decodeUString(tv.val());
3399 }
3400 else{
3401 //byte []
3402 var stringBytes = this.decodeBlob(byteLength);
3403
3404 //return DataUtils.getUTF8StringFromBytes(stringBytes);
3405 return DataUtils.toString(stringBytes);
3406
3407 }
3408};
3409
3410
3411
3412
3413//OBject containg a pair of type and value
3414var TypeAndVal = function TypeAndVal(_type,_val) {
3415 this.t = _type;
3416 this.v = _val;
3417};
3418
3419TypeAndVal.prototype.type = function(){
3420 return this.t;
3421};
3422
3423TypeAndVal.prototype.val = function(){
3424 return this.v;
3425};
3426
3427
3428
3429
3430BinaryXMLDecoder.prototype.readIntegerElement =function(
3431 //String
3432 startTag) {
3433
3434 //String
3435 if(LOG>4) console.log('READING INTEGER '+ startTag);
3436 if(LOG>4) console.log('TYPE OF '+ typeof startTag);
3437
3438 var strVal = this.readUTF8Element(startTag);
3439
3440 return parseInt(strVal);
3441};
3442
3443
3444BinaryXMLDecoder.prototype.readUTF8Element =function(
3445 //String
3446 startTag,
3447 //TreeMap<String, String>
3448 attributes) {
3449 //throws Error where name == "ContentDecodingException"
3450
3451 this.readStartElement(startTag, attributes); // can't use getElementText, can't get attributes
3452 //String
3453 var strElementText = this.readUString();
3454 return strElementText;
3455};
3456
3457
3458/*
3459 * Set the offset into the input, used for the next read.
3460 */
3461BinaryXMLDecoder.prototype.seek = function(
3462 //int
3463 offset) {
3464 this.offset = offset;
3465}
3466
3467/*
3468 * Call with: throw new ContentDecodingException(new Error("message")).
3469 */
3470function ContentDecodingException(error) {
3471 this.message = error.message;
3472 // Copy lineNumber, etc. from where new Error was called.
3473 for (var prop in error)
3474 this[prop] = error[prop];
3475}
3476ContentDecodingException.prototype = new Error();
3477ContentDecodingException.prototype.name = "ContentDecodingException";
3478
Wentao Shangbd63e462012-12-03 16:19:33 -08003479/**
Wentao Shang0e291c82012-12-02 23:36:29 -08003480 * This class uses BinaryXMLDecoder to follow the structure of a ccnb binary element to
3481 * determine its end.
3482 *
3483 * @author: Jeff Thompson
3484 * See COPYING for copyright and distribution information.
3485 */
3486
3487var BinaryXMLStructureDecoder = function BinaryXMLDecoder() {
3488 this.gotElementEnd = false;
3489 this.offset = 0;
3490 this.level = 0;
3491 this.state = BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE;
3492 this.headerLength = 0;
3493 this.useHeaderBuffer = false;
3494 this.headerBuffer = new Uint8Array(5);
3495 this.nBytesToRead = 0;
3496};
3497
3498BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE = 0;
3499BinaryXMLStructureDecoder.READ_BYTES = 1;
3500
3501/*
3502 * Continue scanning input starting from this.offset. If found the end of the element
3503 * which started at offset 0 then return true, else false.
3504 * If this returns false, you should read more into input and call again.
3505 * You have to pass in input each time because the array could be reallocated.
3506 * This throws an exception for badly formed ccnb.
3507 */
3508BinaryXMLStructureDecoder.prototype.findElementEnd = function(
3509 // Uint8Array
3510 input)
3511{
3512 if (this.gotElementEnd)
3513 // Someone is calling when we already got the end.
3514 return true;
3515
3516 var decoder = new BinaryXMLDecoder(input);
3517
3518 while (true) {
3519 if (this.offset >= input.length)
3520 // All the cases assume we have some input.
3521 return false;
Wentao Shang2b740e62012-12-07 00:02:53 -08003522
Wentao Shang0e291c82012-12-02 23:36:29 -08003523 switch (this.state) {
3524 case BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE:
3525 // First check for XML_CLOSE.
3526 if (this.headerLength == 0 && input[this.offset] == XML_CLOSE) {
3527 ++this.offset;
3528 // Close the level.
3529 --this.level;
3530 if (this.level == 0)
3531 // Finished.
3532 return true;
3533 if (this.level < 0)
3534 throw new Error("BinaryXMLStructureDecoder: Unexepected close tag at offset " +
3535 (this.offset - 1));
3536
3537 // Get ready for the next header.
3538 this.startHeader();
3539 break;
3540 }
3541
3542 var startingHeaderLength = this.headerLength;
3543 while (true) {
3544 if (this.offset >= input.length) {
3545 // We can't get all of the header bytes from this input. Save in headerBuffer.
3546 this.useHeaderBuffer = true;
3547 var nNewBytes = this.headerLength - startingHeaderLength;
3548 this.setHeaderBuffer
3549 (input.subarray(this.offset - nNewBytes, nNewBytes), startingHeaderLength);
3550
3551 return false;
3552 }
3553 var headerByte = input[this.offset++];
3554 ++this.headerLength;
3555 if (headerByte & XML_TT_NO_MORE)
3556 // Break and read the header.
3557 break;
3558 }
3559
3560 var typeAndVal;
3561 if (this.useHeaderBuffer) {
3562 // Copy the remaining bytes into headerBuffer.
3563 nNewBytes = this.headerLength - startingHeaderLength;
3564 this.setHeaderBuffer
3565 (input.subarray(this.offset - nNewBytes, nNewBytes), startingHeaderLength);
3566
3567 typeAndVal = new BinaryXMLDecoder(this.headerBuffer).decodeTypeAndVal();
3568 }
3569 else {
3570 // We didn't have to use the headerBuffer.
3571 decoder.seek(this.offset - this.headerLength);
3572 typeAndVal = decoder.decodeTypeAndVal();
3573 }
3574
3575 if (typeAndVal == null)
3576 throw new Error("BinaryXMLStructureDecoder: Can't read header starting at offset " +
3577 (this.offset - this.headerLength));
3578
3579 // Set the next state based on the type.
3580 var type = typeAndVal.t;
3581 if (type == XML_DATTR)
3582 // We already consumed the item. READ_HEADER_OR_CLOSE again.
3583 // ccnb has rules about what must follow an attribute, but we are just scanning.
3584 this.startHeader();
3585 else if (type == XML_DTAG || type == XML_EXT) {
3586 // Start a new level and READ_HEADER_OR_CLOSE again.
3587 ++this.level;
3588 this.startHeader();
3589 }
3590 else if (type == XML_TAG || type == XML_ATTR) {
3591 if (type == XML_TAG)
3592 // Start a new level and read the tag.
3593 ++this.level;
3594 // Minimum tag or attribute length is 1.
3595 this.nBytesToRead = typeAndVal.v + 1;
3596 this.state = BinaryXMLStructureDecoder.READ_BYTES;
3597 // ccnb has rules about what must follow an attribute, but we are just scanning.
3598 }
3599 else if (type == XML_BLOB || type == XML_UDATA) {
3600 this.nBytesToRead = typeAndVal.v;
3601 this.state = BinaryXMLStructureDecoder.READ_BYTES;
3602 }
3603 else
3604 throw new Error("BinaryXMLStructureDecoder: Unrecognized header type " + type);
3605 break;
3606
3607 case BinaryXMLStructureDecoder.READ_BYTES:
3608 var nRemainingBytes = input.length - this.offset;
3609 if (nRemainingBytes < this.nBytesToRead) {
3610 // Need more.
3611 this.offset += nRemainingBytes;
3612 this.nBytesToRead -= nRemainingBytes;
3613 return false;
3614 }
3615 // Got the bytes. Read a new header or close.
3616 this.offset += this.nBytesToRead;
3617 this.startHeader();
3618 break;
3619
3620 default:
3621 // We don't expect this to happen.
3622 throw new Error("BinaryXMLStructureDecoder: Unrecognized state " + this.state);
3623 }
3624 }
3625};
3626
3627/*
3628 * Set the state to READ_HEADER_OR_CLOSE and set up to start reading the header
3629 */
3630BinaryXMLStructureDecoder.prototype.startHeader = function() {
3631 this.headerLength = 0;
3632 this.useHeaderBuffer = false;
3633 this.state = BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE;
3634}
3635
3636/*
3637 * Set the offset into the input, used for the next read.
3638 */
3639BinaryXMLStructureDecoder.prototype.seek = function(
3640 //int
3641 offset) {
3642 this.offset = offset;
3643}
3644
3645/*
3646 * Set call this.headerBuffer.set(subarray, bufferOffset), an reallocate the headerBuffer if needed.
3647 */
3648BinaryXMLStructureDecoder.prototype.setHeaderBuffer = function(subarray, bufferOffset) {
3649 var size = subarray.length + bufferOffset;
3650 if (size > this.headerBuffer.length) {
3651 // Reallocate the buffer.
3652 var newHeaderBuffer = new Uint8Array(size + 5);
3653 newHeaderBuffer.set(this.headerBuffer);
3654 this.headerBuffer = newHeaderBuffer;
3655 }
3656 this.headerBuffer.set(subarray, bufferOffset);
Wentao Shangbd63e462012-12-03 16:19:33 -08003657}/**
Wentao Shang0e291c82012-12-02 23:36:29 -08003658 * This class contains utilities to help parse the data
3659 * author: Meki Cheraoui, Jeff Thompson
3660 * See COPYING for copyright and distribution information.
3661 */
3662
3663var DataUtils = function DataUtils(){
3664
3665
3666};
3667
3668
3669/*
3670 * NOTE THIS IS CURRENTLY NOT BEHING USED
3671 *
3672 */
3673
3674DataUtils.keyStr = "ABCDEFGHIJKLMNOP" +
3675 "QRSTUVWXYZabcdef" +
3676 "ghijklmnopqrstuv" +
3677 "wxyz0123456789+/" +
3678 "=";
3679
3680
3681/**
3682 * Raw String to Base 64
3683 */
3684DataUtils.stringtoBase64=function stringtoBase64(input) {
3685 input = escape(input);
3686 var output = "";
3687 var chr1, chr2, chr3 = "";
3688 var enc1, enc2, enc3, enc4 = "";
3689 var i = 0;
3690
3691 do {
3692 chr1 = input.charCodeAt(i++);
3693 chr2 = input.charCodeAt(i++);
3694 chr3 = input.charCodeAt(i++);
3695
3696 enc1 = chr1 >> 2;
3697 enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
3698 enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
3699 enc4 = chr3 & 63;
3700
3701 if (isNaN(chr2)) {
3702 enc3 = enc4 = 64;
3703 } else if (isNaN(chr3)) {
3704 enc4 = 64;
3705 }
3706
3707 output = output +
3708 DataUtils.keyStr.charAt(enc1) +
3709 DataUtils.keyStr.charAt(enc2) +
3710 DataUtils.keyStr.charAt(enc3) +
3711 DataUtils.keyStr.charAt(enc4);
3712 chr1 = chr2 = chr3 = "";
3713 enc1 = enc2 = enc3 = enc4 = "";
3714 } while (i < input.length);
3715
3716 return output;
3717 }
3718
3719/**
3720 * Base 64 to Raw String
3721 */
3722DataUtils.base64toString = function base64toString(input) {
3723 var output = "";
3724 var chr1, chr2, chr3 = "";
3725 var enc1, enc2, enc3, enc4 = "";
3726 var i = 0;
3727
3728 // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
3729 var base64test = /[^A-Za-z0-9\+\/\=]/g;
3730 /* Test for invalid characters. */
3731 if (base64test.exec(input)) {
3732 alert("There were invalid base64 characters in the input text.\n" +
3733 "Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\n" +
3734 "Expect errors in decoding.");
3735 }
3736
3737 input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
3738
3739 do {
3740 enc1 = DataUtils.keyStr.indexOf(input.charAt(i++));
3741 enc2 = DataUtils.keyStr.indexOf(input.charAt(i++));
3742 enc3 = DataUtils.keyStr.indexOf(input.charAt(i++));
3743 enc4 = DataUtils.keyStr.indexOf(input.charAt(i++));
3744
3745 chr1 = (enc1 << 2) | (enc2 >> 4);
3746 chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
3747 chr3 = ((enc3 & 3) << 6) | enc4;
3748
3749 output = output + String.fromCharCode(chr1);
3750
3751 if (enc3 != 64) {
3752 output = output + String.fromCharCode(chr2);
3753 }
3754 if (enc4 != 64) {
3755 output = output + String.fromCharCode(chr3);
3756 }
3757
3758 chr1 = chr2 = chr3 = "";
3759 enc1 = enc2 = enc3 = enc4 = "";
3760
3761 } while (i < input.length);
3762
3763 return unescape(output);
3764 };
3765
3766//byte []
3767
3768/**
3769 * NOT WORKING!!!!!
3770 *
3771 * Unsiged Long Number to Byte Array
3772 */
3773
3774 /*
3775DataUtils.unsignedLongToByteArray= function( value) {
3776
3777 if(LOG>4)console.log('INPUT IS '+value);
3778
3779 if( 0 == value )
3780 return [0];
3781
3782 if( 0 <= value && value <= 0x00FF ) {
3783 //byte []
3784 var bb = new Array(1);
3785 bb[0] = (value & 0x00FF);
3786 return bb;
3787 }
3788
3789 if(LOG>4) console.log('type of value is '+typeof value);
3790 if(LOG>4) console.log('value is '+value);
3791 //byte []
3792 var out = null;
3793 //int
3794 var offset = -1;
3795 for(var i = 7; i >=0; --i) {
3796 //byte
3797 console.log(i);
3798 console.log('value is '+value);
3799 console.log('(value >> (i * 8)) '+ (value >> (i * 8)) );
3800 console.log(' ((value >> (i * 8)) & 0xFF) '+ ((value >> (i * 8)) & 0xFF) );
3801
3802 var b = ((value >> (i * 8)) & 0xFF) ;
3803
3804 if(LOG>4) console.log('b is '+b);
3805
3806 if( out == null && b != 0 ) {
3807 //out = new byte[i+1];
3808 out = new Array(i+1);
3809 offset = i;
3810 }
3811
3812 if( out != null )
3813 out[ offset - i ] = b;
3814 }
3815 if(LOG>4)console.log('OUTPUT IS ');
3816 if(LOG>4)console.log(out);
3817 return out;
3818}
3819*/
3820
3821/**
3822 * NOT WORKING!!!!!
3823 *
3824 * Unsiged Long Number to Byte Array
3825 *//*
3826DataUtils.byteArrayToUnsignedLong = function(//final byte []
3827 src) {
3828 if(LOG>4) console.log('INPUT IS ');
3829 if(LOG>4) console.log(src);
3830
3831 var value = 0;
3832 for(var i = 0; i < src.length; i++) {
3833 value = value << 8;
3834 // Java will assume the byte is signed, so extend it and trim it.
3835
3836
3837 var b = ((src[i]) & 0xFF );
3838 value |= b;
3839 }
3840
3841 if(LOG>4) console.log('OUTPUT IS ');
3842
3843 if(LOG>4) console.log(value);
3844
3845 return value;
3846 }*/
3847
3848
3849/**
3850 * Hex String to Byte Array
3851 */
3852 //THIS IS NOT WORKING
3853/*
3854DataUtils.HexStringtoByteArray = function(str) {
3855 var byteArray = [];
3856 for (var i = 0; i < str.length; i++)
3857 if (str.charCodeAt(i) <= 0x7F)
3858 byteArray.push(str.charCodeAt(i));
3859 else {
3860 var h = encodeURIComponent(str.charAt(i)).substr(1).split('%');
3861 for (var j = 0; j < h.length; j++)
3862 byteArray.push(parseInt(h[j], 16));
3863 }
3864 return byteArray;
3865};
3866*/
3867
3868/**
3869 * Uint8Array to Hex String
3870 */
3871//http://ejohn.org/blog/numbers-hex-and-colors/
3872DataUtils.toHex = function(args){
3873 if (LOG>4) console.log('ABOUT TO CONVERT '+ args);
3874 //console.log(args);
3875 var ret = "";
3876 for ( var i = 0; i < args.length; i++ )
3877 ret += (args[i] < 16 ? "0" : "") + args[i].toString(16);
3878 if (LOG>4) console.log('Converted to: ' + ret);
3879 return ret; //.toUpperCase();
3880}
3881
3882/**
3883 * Raw string to hex string.
3884 */
3885DataUtils.stringToHex = function(args){
3886 var ret = "";
3887 for (var i = 0; i < args.length; ++i) {
3888 var value = args.charCodeAt(i);
3889 ret += (value < 16 ? "0" : "") + value.toString(16);
3890 }
3891 return ret;
3892}
3893
3894/**
3895 * Uint8Array to raw string.
3896 */
3897DataUtils.toString = function(args){
3898 //console.log(arguments);
3899 var ret = "";
3900 for ( var i = 0; i < args.length; i++ )
3901 ret += String.fromCharCode(args[i]);
3902 return ret;
3903}
3904
3905/**
3906 * Hex String to Uint8Array.
3907 */
3908DataUtils.toNumbers = function(str) {
3909 if (typeof str == 'string') {
3910 var ret = new Uint8Array(Math.floor(str.length / 2));
3911 var i = 0;
3912 str.replace(/(..)/g, function(str) {
3913 ret[i++] = parseInt(str, 16);
3914 });
3915 return ret;
3916 }
3917}
3918
3919/**
3920 * Hex String to raw string.
3921 */
3922DataUtils.hexToRawString = function(str) {
3923 if(typeof str =='string') {
3924 var ret = "";
3925 str.replace(/(..)/g, function(s) {
3926 ret += String.fromCharCode(parseInt(s, 16));
3927 });
3928 return ret;
3929 }
3930}
3931
3932/**
3933 * Raw String to Uint8Array.
3934 */
3935DataUtils.toNumbersFromString = function( str ){
3936 var bytes = new Uint8Array(str.length);
3937 for(var i=0;i<str.length;i++)
3938 bytes[i] = str.charCodeAt(i);
3939 return bytes;
3940}
3941
3942/*
3943 * Encode str as utf8 and return as Uint8Array.
3944 * TODO: Use TextEncoder when available.
3945 */
3946DataUtils.stringToUtf8Array = function(str) {
3947 return DataUtils.toNumbersFromString(str2rstr_utf8(str));
3948}
3949
3950/*
3951 * arrays is an array of Uint8Array. Return a new Uint8Array which is the concatenation of all.
3952 */
3953DataUtils.concatArrays = function(arrays) {
3954 var totalLength = 0;
3955 for (var i = 0; i < arrays.length; ++i)
3956 totalLength += arrays[i].length;
3957
3958 var result = new Uint8Array(totalLength);
3959 var offset = 0;
3960 for (var i = 0; i < arrays.length; ++i) {
3961 result.set(arrays[i], offset);
3962 offset += arrays[i].length;
3963 }
3964 return result;
3965
3966}
3967
3968// TODO: Take Uint8Array and use TextDecoder when available.
3969DataUtils.decodeUtf8 = function (utftext) {
3970 var string = "";
3971 var i = 0;
3972 var c = 0;
3973 var c1 = 0;
3974 var c2 = 0;
3975
3976 while ( i < utftext.length ) {
3977
3978 c = utftext.charCodeAt(i);
3979
3980 if (c < 128) {
3981 string += String.fromCharCode(c);
3982 i++;
3983 }
3984 else if((c > 191) && (c < 224)) {
3985 c2 = utftext.charCodeAt(i+1);
3986 string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
3987 i += 2;
3988 }
3989 else {
3990 c2 = utftext.charCodeAt(i+1);
3991 var c3 = utftext.charCodeAt(i+2);
3992 string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
3993 i += 3;
3994 }
3995
3996 }
3997
3998 return string;
3999 };
4000
4001//NOT WORKING
4002/*
4003DataUtils.getUTF8StringFromBytes = function(bytes) {
4004
4005 bytes = toString(bytes);
4006
4007 var ix = 0;
4008
4009 if( bytes.slice(0,3) == "\xEF\xBB\xBF") {
4010 ix = 3;
4011 }
4012
4013 var string = "";
4014 for( ; ix < bytes.length; ix++ ) {
4015 var byte1 = bytes[ix].charCodeAt(0);
4016 if( byte1 < 0x80 ) {
4017 string += String.fromCharCode(byte1);
4018 } else if( byte1 >= 0xC2 && byte1 < 0xE0 ) {
4019 var byte2 = bytes[++ix].charCodeAt(0);
4020 string += String.fromCharCode(((byte1&0x1F)<<6) + (byte2&0x3F));
4021 } else if( byte1 >= 0xE0 && byte1 < 0xF0 ) {
4022 var byte2 = bytes[++ix].charCodeAt(0);
4023 var byte3 = bytes[++ix].charCodeAt(0);
4024 string += String.fromCharCode(((byte1&0xFF)<<12) + ((byte2&0x3F)<<6) + (byte3&0x3F));
4025 } else if( byte1 >= 0xF0 && byte1 < 0xF5) {
4026 var byte2 = bytes[++ix].charCodeAt(0);
4027 var byte3 = bytes[++ix].charCodeAt(0);
4028 var byte4 = bytes[++ix].charCodeAt(0);
4029 var codepoint = ((byte1&0x07)<<18) + ((byte2&0x3F)<<12)+ ((byte3&0x3F)<<6) + (byte4&0x3F);
4030 codepoint -= 0x10000;
4031 string += String.fromCharCode(
4032 (codepoint>>10) + 0xD800,
4033 (codepoint&0x3FF) + 0xDC00
4034 );
4035 }
4036 }
4037
4038 return string;
4039}*/
4040
4041/**
4042 * Return true if a1 and a2 are the same length with equal elements.
4043 */
4044DataUtils.arraysEqual = function(a1, a2){
4045 if (a1.length != a2.length)
4046 return false;
4047
4048 for (var i = 0; i < a1.length; ++i) {
4049 if (a1[i] != a2[i])
4050 return false;
4051 }
4052
4053 return true;
4054};
4055
4056/*
4057 * Convert the big endian Uint8Array to an unsigned int.
4058 * Don't check for overflow.
4059 */
4060DataUtils.bigEndianToUnsignedInt = function(bytes) {
4061 var result = 0;
4062 for (var i = 0; i < bytes.length; ++i) {
4063 result <<= 8;
4064 result += bytes[i];
4065 }
4066 return result;
4067};
4068
4069/*
4070 * Convert the int value to a new big endian Uint8Array and return.
4071 * If value is 0 or negative, return Uint8Array(0).
4072 */
4073DataUtils.nonNegativeIntToBigEndian = function(value) {
4074 value = Math.round(value);
4075 if (value <= 0)
4076 return new Uint8Array(0);
4077
4078 // Assume value is not over 64 bits.
4079 var size = 8;
4080 var result = new Uint8Array(size);
4081 var i = 0;
4082 while (value != 0) {
4083 ++i;
4084 result[size - i] = value & 0xff;
4085 value >>= 8;
4086 }
4087 return result.subarray(size - i, size);
4088};
Wentao Shangbd63e462012-12-03 16:19:33 -08004089/**
Wentao Shang0e291c82012-12-02 23:36:29 -08004090 * This file contains utilities to help encode and decode NDN objects.
4091 * author: Meki Cheraoui
4092 * See COPYING for copyright and distribution information.
4093 */
4094
4095function encodeToHexInterest(interest){
4096 return DataUtils.toHex(encodeToBinaryInterest(interest));
4097}
4098
4099
4100function encodeToBinaryInterest(interest) {
4101 var enc = new BinaryXMLEncoder();
4102 interest.to_ccnb(enc);
4103
4104 return enc.getReducedOstream();
4105}
4106
4107
4108function encodeToHexContentObject(co){
4109 return DataUtils.toHex(encodeToBinaryContentObject(co));
4110}
4111
4112function encodeToBinaryContentObject(co){
4113 var enc = new BinaryXMLEncoder();
4114 co.to_ccnb(enc);
4115
4116 return enc.getReducedOstream();
4117}
4118
4119function encodeForwardingEntry(co){
4120 var enc = new BinaryXMLEncoder();
4121
4122 co.to_ccnb(enc);
4123
4124 var bytes = enc.getReducedOstream();
4125
4126 return bytes;
4127
4128
4129}
4130
4131
4132
4133function decodeHexFaceInstance(result){
4134
4135 var numbers = DataUtils.toNumbers(result);
4136
4137
4138 decoder = new BinaryXMLDecoder(numbers);
4139
4140 if(LOG>3)console.log('DECODING HEX FACE INSTANCE \n'+numbers);
4141
4142 var faceInstance = new FaceInstance();
4143
4144 faceInstance.from_ccnb(decoder);
4145
4146 return faceInstance;
4147
4148}
4149
4150
4151
4152function decodeHexInterest(result){
4153 var numbers = DataUtils.toNumbers(result);
4154
4155 decoder = new BinaryXMLDecoder(numbers);
4156
4157 if(LOG>3)console.log('DECODING HEX INTERST \n'+numbers);
4158
4159 var interest = new Interest();
4160
4161 interest.from_ccnb(decoder);
4162
4163 return interest;
4164
4165}
4166
4167
4168
4169function decodeHexContentObject(result){
4170 var numbers = DataUtils.toNumbers(result);
4171
4172 decoder = new BinaryXMLDecoder(numbers);
4173
4174 if(LOG>3)console.log('DECODED HEX CONTENT OBJECT \n'+numbers);
4175
4176 co = new ContentObject();
4177
4178 co.from_ccnb(decoder);
4179
4180 return co;
4181
4182}
4183
4184
4185
4186function decodeHexForwardingEntry(result){
4187 var numbers = DataUtils.toNumbers(result);
4188
4189 decoder = new BinaryXMLDecoder(numbers);
4190
4191 if(LOG>3)console.log('DECODED HEX FORWARDING ENTRY \n'+numbers);
4192
4193 forwardingEntry = new ForwardingEntry();
4194
4195 forwardingEntry.from_ccnb(decoder);
4196
4197 return forwardingEntry;
4198
4199}
4200
4201/* Return a user friendly HTML string with the contents of co.
4202 This also outputs to console.log.
4203 */
4204function contentObjectToHtml(/* ContentObject */ co) {
4205 var output ="";
4206
4207 if(co==-1)
4208 output+= "NO CONTENT FOUND"
4209 else if (co==-2)
4210 output+= "CONTENT NAME IS EMPTY"
4211 else{
4212 if(co.name!=null && co.name.components!=null){
4213 output+= "NAME: " + co.name.to_uri();
4214
4215 output+= "<br />";
4216 output+= "<br />";
4217 }
4218
4219 if(co.content !=null){
4220 output += "CONTENT(ASCII): "+ DataUtils.toString(co.content);
4221
4222 output+= "<br />";
4223 output+= "<br />";
4224 }
4225 if(co.content !=null){
4226 output += "CONTENT(hex): "+ DataUtils.toHex(co.content);
4227
4228 output+= "<br />";
4229 output+= "<br />";
4230 }
4231 if(co.signature !=null && co.signature.signature!=null){
4232 output += "SIGNATURE(hex): "+ DataUtils.toHex(co.signature.signature);
4233
4234 output+= "<br />";
4235 output+= "<br />";
4236 }
4237 if(co.signedInfo !=null && co.signedInfo.publisher!=null && co.signedInfo.publisher.publisherPublicKeyDigest!=null){
4238 output += "Publisher Public Key Digest(hex): "+ DataUtils.toHex(co.signedInfo.publisher.publisherPublicKeyDigest);
4239
4240 output+= "<br />";
4241 output+= "<br />";
4242 }
4243 if(co.signedInfo !=null && co.signedInfo.timestamp!=null){
4244 var d = new Date();
4245 d.setTime( co.signedInfo.timestamp.msec );
4246
4247 var bytes = [217, 185, 12, 225, 217, 185, 12, 225];
4248
4249 output += "TimeStamp: "+d;
4250 output+= "<br />";
4251 output += "TimeStamp(number): "+ co.signedInfo.timestamp.msec;
4252
4253 output+= "<br />";
4254 }
4255 if(co.signedInfo !=null && co.signedInfo.finalBlockID!=null){
4256 output += "FinalBlockID: "+ DataUtils.toHex(co.signedInfo.finalBlockID);
4257 output+= "<br />";
4258 }
4259 if(co.signedInfo!=null && co.signedInfo.locator!=null && co.signedInfo.locator.certificate!=null){
4260 var tmp = DataUtils.toString(co.signedInfo.locator.certificate);
4261 var publickey = rstr2b64(tmp);
4262 var publickeyHex = DataUtils.toHex(co.signedInfo.locator.certificate).toLowerCase();
4263 var publickeyString = DataUtils.toString(co.signedInfo.locator.certificate);
4264 var signature = DataUtils.toHex(co.signature.signature).toLowerCase();
4265 var input = DataUtils.toString(co.rawSignatureData);
4266
4267 output += "DER Certificate: "+publickey ;
4268
4269 output+= "<br />";
4270 output+= "<br />";
4271
4272 if(LOG>2) console.log(" ContentName + SignedInfo + Content = "+input);
4273
4274 if(LOG>2) console.log("HEX OF ContentName + SignedInfo + Content = ");
4275 if(LOG>2) console.log(DataUtils.stringtoBase64(input));
4276
4277 if(LOG>2) console.log(" PublicKey = "+publickey );
4278 if(LOG>2) console.log(" PublicKeyHex = "+publickeyHex );
4279 if(LOG>2) console.log(" PublicKeyString = "+publickeyString );
4280
4281 if(LOG>2) console.log(" Signature is");
4282 if(LOG>2) console.log( signature );
4283 //if(LOG>2) console.log(" Signature NOW IS" );
4284 //if(LOG>2) console.log(co.signature.signature);
4285
4286 var x509 = new X509();
4287 x509.readCertPEM(publickey);
4288
4289 //x509.readCertPEMWithoutRSAInit(publickey);
4290
4291 var result = x509.subjectPublicKeyRSA.verifyByteArray(co.rawSignatureData, signature);
4292 if(LOG>2) console.log('result is '+result);
4293
4294 var n = x509.subjectPublicKeyRSA.n;
4295 var e = x509.subjectPublicKeyRSA.e;
4296
4297 if(LOG>2) console.log('PUBLIC KEY n after is ');
4298 if(LOG>2) console.log(n);
4299
4300 if(LOG>2) console.log('EXPONENT e after is ');
4301 if(LOG>2) console.log(e);
4302
4303 /*var rsakey = new RSAKey();
4304
4305 var kp = publickeyHex.slice(56,314);
4306
4307 output += "PUBLISHER KEY(hex): "+kp ;
4308
4309 output+= "<br />";
4310 output+= "<br />";
4311
4312 console.log('kp is '+kp);
4313
4314 var exp = publickeyHex.slice(318,324);
4315
4316 console.log('kp size is '+kp.length );
4317 output += "exponent: "+exp ;
4318
4319 output+= "<br />";
4320 output+= "<br />";
4321
4322 console.log('exp is '+exp);
4323
4324 rsakey.setPublic(kp,exp);
4325
4326 var result = rsakey.verifyString(input, signature);*/
4327
4328 if(result)
4329 output += 'SIGNATURE VALID';
4330 else
4331 output += 'SIGNATURE INVALID';
4332
4333 //output += "VALID: "+ toHex(co.signedInfo.locator.publicKey);
4334
4335 output+= "<br />";
4336 output+= "<br />";
4337
4338 //if(LOG>4) console.log('str'[1]);
4339 }
4340 if(co.signedInfo!=null && co.signedInfo.locator!=null && co.signedInfo.locator.publicKey!=null){
4341 var publickey = rstr2b64(DataUtils.toString(co.signedInfo.locator.publicKey));
4342 var publickeyHex = DataUtils.toHex(co.signedInfo.locator.publicKey).toLowerCase();
4343 var publickeyString = DataUtils.toString(co.signedInfo.locator.publicKey);
4344 var signature = DataUtils.toHex(co.signature.signature).toLowerCase();
4345 var input = DataUtils.toString(co.rawSignatureData);
4346
4347 output += "DER Certificate: "+publickey ;
4348
4349 output+= "<br />";
4350 output+= "<br />";
4351
4352 if(LOG>2) console.log(" ContentName + SignedInfo + Content = "+input);
4353 if(LOG>2) console.log(" PublicKey = "+publickey );
4354 if(LOG>2) console.log(" PublicKeyHex = "+publickeyHex );
4355 if(LOG>2) console.log(" PublicKeyString = "+publickeyString );
4356
4357 if(LOG>2) console.log(" Signature "+signature );
4358
4359 if(LOG>2) console.log(" Signature NOW IS" );
4360
4361 if(LOG>2) console.log(co.signature.signature);
4362
4363 /*var x509 = new X509();
4364
4365 x509.readCertPEM(publickey);
4366
4367
4368 //x509.readCertPEMWithoutRSAInit(publickey);
4369
4370 var result = x509.subjectPublicKeyRSA.verifyString(input, signature);*/
4371 //console.log('result is '+result);
4372
4373 var kp = publickeyHex.slice(56,314);
4374
4375 output += "PUBLISHER KEY(hex): "+kp ;
4376
4377 output+= "<br />";
4378 output+= "<br />";
4379
Wentao Shang2b740e62012-12-07 00:02:53 -08004380 if(LOG>2) console.log('PUBLIC KEY IN HEX is ');
4381 if(LOG>2) console.log(kp);
Wentao Shang0e291c82012-12-02 23:36:29 -08004382
4383 var exp = publickeyHex.slice(318,324);
4384
Wentao Shang2b740e62012-12-07 00:02:53 -08004385 if(LOG>2) console.log('kp size is '+kp.length );
Wentao Shang0e291c82012-12-02 23:36:29 -08004386 output += "exponent: "+exp ;
4387
4388 output+= "<br />";
4389 output+= "<br />";
4390
Wentao Shang2b740e62012-12-07 00:02:53 -08004391 if(LOG>2) console.log('EXPONENT is ');
4392 if(LOG>2) console.log(exp);
Wentao Shang0e291c82012-12-02 23:36:29 -08004393
4394 /*var c1 = hex_sha256(input);
4395 var c2 = signature;
4396
4397 if(LOG>4)console.log('input is ');
4398 if(LOG>4)console.log(input);
4399 if(LOG>4)console.log('C1 is ');
4400 if(LOG>4)console.log(c1);
4401 if(LOG>4)console.log('C2 is ');
4402 if(LOG>4)console.log(c2);
4403 var result = c1 == c2;*/
4404
4405 var rsakey = new RSAKey();
4406
4407 rsakey.setPublic(kp,exp);
4408
4409 var result = rsakey.verifyByteArray(co.rawSignatureData,signature);
4410 // var result = rsakey.verifyString(input, signature);
4411
Wentao Shang2b740e62012-12-07 00:02:53 -08004412 if(LOG>2) console.log('PUBLIC KEY n after is ');
4413 if(LOG>2) console.log(rsakey.n);
Wentao Shang0e291c82012-12-02 23:36:29 -08004414
Wentao Shang2b740e62012-12-07 00:02:53 -08004415 if(LOG>2) console.log('EXPONENT e after is ');
4416 if(LOG>2) console.log(rsakey.e);
Wentao Shang0e291c82012-12-02 23:36:29 -08004417
4418 if(result)
4419 output += 'SIGNATURE VALID';
4420 else
4421 output += 'SIGNATURE INVALID';
4422
4423 //output += "VALID: "+ toHex(co.signedInfo.locator.publicKey);
4424
4425 output+= "<br />";
4426 output+= "<br />";
4427
4428 //if(LOG>4) console.log('str'[1]);
4429 }
4430 }
4431
4432 return output;
4433}
Wentao Shangbd63e462012-12-03 16:19:33 -08004434/**
Wentao Shang0e291c82012-12-02 23:36:29 -08004435 * @author: Meki Cheraoui
4436 * See COPYING for copyright and distribution information.
4437 */
4438
4439var KeyManager = function KeyManager(){
4440
4441
4442//Certificate
4443
4444this.certificate = 'MIIBmzCCAQQCCQC32FyQa61S7jANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwd'+
4445
4446'heGVsY2R2MB4XDTEyMDQyODIzNDQzN1oXDTEyMDUyODIzNDQzN1owEjEQMA4GA1'+
4447
4448'UEAxMHYXhlbGNkdjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4X0wp9goq'+
4449
4450'xuECxdULcr2IHr9Ih4Iaypg0Wy39URIup8/CLzQmdsh3RYqd55hqonu5VTTpH3i'+
4451
4452'MLx6xZDVJAZ8OJi7pvXcQ2C4Re2kjL2c8SanI0RfDhlS1zJadfr1VhRPmpivcYa'+
4453
4454'wJ4aFuOLAi+qHFxtN7lhcGCgpW1OV60oXd58CAwEAATANBgkqhkiG9w0BAQUFAA'+
4455
4456'OBgQDLOrA1fXzSrpftUB5Ro6DigX1Bjkf7F5Bkd69hSVp+jYeJFBBlsILQAfSxU'+
4457
4458'ZPQtD+2Yc3iCmSYNyxqu9PcufDRJlnvB7PG29+L3y9lR37tetzUV9eTscJ7rdp8'+
4459
4460'Wt6AzpW32IJ/54yKNfP7S6ZIoIG+LP6EIxq6s8K1MXRt8uBJKw==';
4461
4462
4463//this.publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhfTCn2CirG4QLF1QtyvYgev0iHghrKmDRbLf1REi6nz8IvNCZ2yHdFip3nmGqie7lVNOkfeIwvHrFkNUkBnw4mLum9dxDYLhF7aSMvZzxJqcjRF8OGVLXMlp1+vVWFE+amK9xhrAnhoW44sCL6ocXG03uWFwYKClbU5XrShd3nwIDAQAB';
4464this.publicKey ='30819F300D06092A864886F70D010101050003818D0030818902818100E17D30A7D828AB1B840B17542DCAF6207AFD221E086B2A60D16CB7F54448BA9F3F08BCD099DB21DD162A779E61AA89EEE554D3A47DE230BC7AC590D524067C3898BBA6F5DC4360B845EDA48CBD9CF126A723445F0E1952D7325A75FAF556144F9A98AF7186B0278685B8E2C08BEA87171B4DEE585C1828295B5395EB4A17779F0203010001';
4465//Private Key
4466
4467this.privateKey ='MIICXQIBAAKBgQDhfTCn2CirG4QLF1QtyvYgev0iHghrKmDRbLf1REi6nz8IvNCZ2yHdFip3nmGqie7lVNOkfeIwvHrFkNUkBnw4mLum9dxDYLhF7aSMvZzxJqcjRF8OGVLXMlp1+vVWFE+amK9xhrAnhoW44sCL6ocXG03uWFwYKClbU5XrShd3nwIDAQABAoGAGkv6T6jC3WmhFZYL6CdCWvlc6gysmKrhjarrLTxgavtFY6R5g2ft5BXAsCCVbUkWxkIFSKqxpVNl0gKZCNGEzPDN6mHJOQI/h0rlxNIHAuGfoAbCzALnqmyZivhJAPGijAyKuU9tczsst5+Kpn+bn7ehzHQuj7iwJonS5WbojqECQQD851K8TpW2GrRizNgG4dx6orZxAaon/Jnl8lS7soXhllQty7qG+oDfzznmdMsiznCqEABzHUUKOVGE9RWPN3aRAkEA5D/w9N55d0ibnChFJlc8cUAoaqH+w+U3oQP2Lb6AZHJpLptN4y4b/uf5d4wYU5/i/gC7SSBH3wFhh9bjRLUDLwJAVOx8vN0Kqt7myfKNbCo19jxjVSlA8TKCn1Oznl/BU1I+rC4oUaEW25DjmX6IpAR8kq7S59ThVSCQPjxqY/A08QJBAIRaF2zGPITQk3r/VumemCvLWiRK/yG0noc9dtibqHOWbCtcXtOm/xDWjq+lis2i3ssOvYrvrv0/HcDY+Dv1An0CQQCLJtMsfSg4kvG/FRY5UMhtMuwo8ovYcMXt4Xv/LWaMhndD67b2UGawQCRqr5ghRTABWdDD/HuuMBjrkPsX0861';
4468
4469
4470/*
4471 this.certificate =
4472 'MIIBvTCCASYCCQD55fNzc0WF7TANBgkqhkiG9w0BAQUFADAjMQswCQYDVQQGEwJK'+
4473 'UDEUMBIGA1UEChMLMDAtVEVTVC1SU0EwHhcNMTAwNTI4MDIwODUxWhcNMjAwNTI1'+
4474 'MDIwODUxWjAjMQswCQYDVQQGEwJKUDEUMBIGA1UEChMLMDAtVEVTVC1SU0EwgZ8w'+
4475 'DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANGEYXtfgDRlWUSDn3haY4NVVQiKI9Cz'+
4476 'Thoua9+DxJuiseyzmBBe7Roh1RPqdvmtOHmEPbJ+kXZYhbozzPRbFGHCJyBfCLzQ'+
4477 'fVos9/qUQ88u83b0SFA2MGmQWQAlRtLy66EkR4rDRwTj2DzR4EEXgEKpIvo8VBs/'+
4478 '3+sHLF3ESgAhAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAEZ6mXFFq3AzfaqWHmCy1'+
4479 'ARjlauYAa8ZmUFnLm0emg9dkVBJ63aEqARhtok6bDQDzSJxiLpCEF6G4b/Nv/M/M'+
4480 'LyhP+OoOTmETMegAVQMq71choVJyOFE5BtQa6M/lCHEOya5QUfoRF2HF9EjRF44K'+
4481 '3OK+u3ivTSj3zwjtpudY5Xo=';
4482
4483 this.privateKey =
4484 'MIICWwIBAAKBgQDRhGF7X4A0ZVlEg594WmODVVUIiiPQs04aLmvfg8SborHss5gQ'+
4485 'Xu0aIdUT6nb5rTh5hD2yfpF2WIW6M8z0WxRhwicgXwi80H1aLPf6lEPPLvN29EhQ'+
4486 'NjBpkFkAJUbS8uuhJEeKw0cE49g80eBBF4BCqSL6PFQbP9/rByxdxEoAIQIDAQAB'+
4487 'AoGAA9/q3Zk6ib2GFRpKDLO/O2KMnAfR+b4XJ6zMGeoZ7Lbpi3MW0Nawk9ckVaX0'+
4488 'ZVGqxbSIX5Cvp/yjHHpww+QbUFrw/gCjLiiYjM9E8C3uAF5AKJ0r4GBPl4u8K4bp'+
4489 'bXeSxSB60/wPQFiQAJVcA5xhZVzqNuF3EjuKdHsw+dk+dPECQQDubX/lVGFgD/xY'+
4490 'uchz56Yc7VHX+58BUkNSewSzwJRbcueqknXRWwj97SXqpnYfKqZq78dnEF10SWsr'+
4491 '/NMKi+7XAkEA4PVqDv/OZAbWr4syXZNv/Mpl4r5suzYMMUD9U8B2JIRnrhmGZPzL'+
4492 'x23N9J4hEJ+Xh8tSKVc80jOkrvGlSv+BxwJAaTOtjA3YTV+gU7Hdza53sCnSw/8F'+
4493 'YLrgc6NOJtYhX9xqdevbyn1lkU0zPr8mPYg/F84m6MXixm2iuSz8HZoyzwJARi2p'+
4494 'aYZ5/5B2lwroqnKdZBJMGKFpUDn7Mb5hiSgocxnvMkv6NjT66Xsi3iYakJII9q8C'+
4495 'Ma1qZvT/cigmdbAh7wJAQNXyoizuGEltiSaBXx4H29EdXNYWDJ9SS5f070BRbAIl'+
4496 'dqRh3rcNvpY6BKJqFapda1DjdcncZECMizT/GMrc1w==';
4497
4498 */
4499};
4500
4501
4502KeyManager.prototype.verify = function verify(message,signature){
4503
4504 var input = message;
4505
4506 var _PEM_X509CERT_STRING_ = this.certificate;
4507
4508 var x509 = new X509();
4509
4510 x509.readCertPEM(_PEM_X509CERT_STRING_);
4511
4512 var result = x509.subjectPublicKeyRSA.verifyString(input, signature);
4513
4514 return result;
4515};
4516
4517KeyManager.prototype.sign= function sign(message){
4518
4519 var input = message;
4520
4521 var _PEM_PRIVATE_KEY_STRING_ = this.privateKey;
4522
4523 var rsa = new RSAKey();
4524
4525 rsa.readPrivateKeyFromPEMString(_PEM_PRIVATE_KEY_STRING_);
4526
4527 var hSig = rsa.signString(input, "sha256");
4528
4529 return hSig;
4530
4531};
4532
4533
4534
4535var globalKeyManager = new KeyManager();
4536//var KeyPair = { "public" : "PUBLIC KEY" , "private" : "PRIVATE KEY" };
4537
4538
4539/*
4540 * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined
4541 * in FIPS 180-2
4542 * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
4543 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
4544 * Distributed under the BSD License
4545 * See http://pajhome.org.uk/crypt/md5 for details.
4546 * Also http://anmar.eu.org/projects/jssha2/
4547 */
4548
4549/*
4550 * Configurable variables. You may need to tweak these to be compatible with
4551 * the server-side, but the defaults work in most cases.
4552 */
4553var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
4554var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
4555
4556/*
4557 * These are the functions you'll usually want to call
4558 * They take string arguments and return either hex or base-64 encoded strings
4559 */
4560
4561//@author axelcdv
4562/**
4563 * Computes the Sha-256 hash of the given byte array
4564 * @param {byte[]}
4565 * @return the hex string corresponding to the Sha-256 hash of the byte array
4566 */
4567function hex_sha256_from_bytes(byteArray){
4568 return rstr2hex(binb2rstr(binb_sha256( byteArray2binb(byteArray), byteArray.length * 8)));
4569}
4570
4571function hex_sha256(s) { return rstr2hex(rstr_sha256(str2rstr_utf8(s))); }
4572function b64_sha256(s) { return rstr2b64(rstr_sha256(str2rstr_utf8(s))); }
4573function any_sha256(s, e) { return rstr2any(rstr_sha256(str2rstr_utf8(s)), e); }
4574function hex_hmac_sha256(k, d)
4575 { return rstr2hex(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d))); }
4576function b64_hmac_sha256(k, d)
4577 { return rstr2b64(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d))); }
4578function any_hmac_sha256(k, d, e)
4579 { return rstr2any(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
4580
4581
4582/*
4583 function hex_sha256(s) { return rstr2hex(rstr_sha256(s)); }
4584function b64_sha256(s) { return rstr2b64(rstr_sha256(s)); }
4585function any_sha256(s, e) { return rstr2any(rstr_sha256(s), e); }
4586function hex_hmac_sha256(k, d)
4587 { return rstr2hex(rstr_hmac_sha256(str2rstr_utf8(k), d)); }
4588function b64_hmac_sha256(k, d)
4589 { return rstr2b64(rstr_hmac_sha256(str2rstr_utf8(k), d)); }
4590function any_hmac_sha256(k, d, e)
4591 { return rstr2any(rstr_hmac_sha256(str2rstr_utf8(k), d), e); }
4592*/
4593
4594/*
4595 * Perform a simple self-test to see if the VM is working
4596 */
4597function sha256_vm_test()
4598{
4599 return hex_sha256("abc").toLowerCase() ==
4600 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad";
4601}
4602
4603/**
4604 * Calculate the sha256 of a raw string
4605 * @param s: the raw string
4606 */
4607function rstr_sha256(s)
4608{
4609 return binb2rstr(binb_sha256(rstr2binb(s), s.length * 8));
4610}
4611
4612/**
4613 * Calculate the HMAC-sha256 of a key and some data (raw strings)
4614 */
4615function rstr_hmac_sha256(key, data)
4616{
4617 var bkey = rstr2binb(key);
4618 if(bkey.length > 16) bkey = binb_sha256(bkey, key.length * 8);
4619
4620 var ipad = Array(16), opad = Array(16);
4621 for(var i = 0; i < 16; i++)
4622 {
4623 ipad[i] = bkey[i] ^ 0x36363636;
4624 opad[i] = bkey[i] ^ 0x5C5C5C5C;
4625 }
4626
4627 var hash = binb_sha256(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
4628 return binb2rstr(binb_sha256(opad.concat(hash), 512 + 256));
4629}
4630
4631/**
4632 * Convert a raw string to a hex string
4633 */
4634function rstr2hex(input)
4635{
4636 try { hexcase } catch(e) { hexcase=0; }
4637 var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
4638 var output = "";
4639 var x;
4640 for(var i = 0; i < input.length; i++)
4641 {
4642 x = input.charCodeAt(i);
4643 output += hex_tab.charAt((x >>> 4) & 0x0F)
4644 + hex_tab.charAt( x & 0x0F);
4645 }
4646 return output;
4647}
4648
4649/*
4650 * Convert a raw string to a base-64 string
4651 */
4652function rstr2b64(input)
4653{
4654 try { b64pad } catch(e) { b64pad=''; }
4655 var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4656 var output = "";
4657 var len = input.length;
4658 for(var i = 0; i < len; i += 3)
4659 {
4660 var triplet = (input.charCodeAt(i) << 16)
4661 | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
4662 | (i + 2 < len ? input.charCodeAt(i+2) : 0);
4663 for(var j = 0; j < 4; j++)
4664 {
4665 if(i * 8 + j * 6 > input.length * 8) output += b64pad;
4666 else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
4667 }
4668 }
4669 return output;
4670}
4671
4672/*
4673 * Convert a raw string to an arbitrary string encoding
4674 */
4675function rstr2any(input, encoding)
4676{
4677 var divisor = encoding.length;
4678 var remainders = Array();
4679 var i, q, x, quotient;
4680
4681 /* Convert to an array of 16-bit big-endian values, forming the dividend */
4682 var dividend = Array(Math.ceil(input.length / 2));
4683 for(i = 0; i < dividend.length; i++)
4684 {
4685 dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
4686 }
4687
4688 /*
4689 * Repeatedly perform a long division. The binary array forms the dividend,
4690 * the length of the encoding is the divisor. Once computed, the quotient
4691 * forms the dividend for the next step. We stop when the dividend is zero.
4692 * All remainders are stored for later use.
4693 */
4694 while(dividend.length > 0)
4695 {
4696 quotient = Array();
4697 x = 0;
4698 for(i = 0; i < dividend.length; i++)
4699 {
4700 x = (x << 16) + dividend[i];
4701 q = Math.floor(x / divisor);
4702 x -= q * divisor;
4703 if(quotient.length > 0 || q > 0)
4704 quotient[quotient.length] = q;
4705 }
4706 remainders[remainders.length] = x;
4707 dividend = quotient;
4708 }
4709
4710 /* Convert the remainders to the output string */
4711 var output = "";
4712 for(i = remainders.length - 1; i >= 0; i--)
4713 output += encoding.charAt(remainders[i]);
4714
4715 /* Append leading zero equivalents */
4716 var full_length = Math.ceil(input.length * 8 /
4717 (Math.log(encoding.length) / Math.log(2)))
4718 for(i = output.length; i < full_length; i++)
4719 output = encoding[0] + output;
4720
4721 return output;
4722}
4723
4724/*
4725 * Encode a string as utf-8.
4726 * For efficiency, this assumes the input is valid utf-16.
4727 */
4728function str2rstr_utf8(input)
4729{
4730 var output = "";
4731 var i = -1;
4732 var x, y;
4733
4734 while(++i < input.length)
4735 {
4736 /* Decode utf-16 surrogate pairs */
4737 x = input.charCodeAt(i);
4738 y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
4739 if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
4740 {
4741 x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
4742 i++;
4743 }
4744
4745 /* Encode output as utf-8 */
4746 if(x <= 0x7F)
4747 output += String.fromCharCode(x);
4748 else if(x <= 0x7FF)
4749 output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
4750 0x80 | ( x & 0x3F));
4751 else if(x <= 0xFFFF)
4752 output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
4753 0x80 | ((x >>> 6 ) & 0x3F),
4754 0x80 | ( x & 0x3F));
4755 else if(x <= 0x1FFFFF)
4756 output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
4757 0x80 | ((x >>> 12) & 0x3F),
4758 0x80 | ((x >>> 6 ) & 0x3F),
4759 0x80 | ( x & 0x3F));
4760 }
4761 return output;
4762}
4763
4764/*
4765 * Encode a string as utf-16
4766 */
4767function str2rstr_utf16le(input)
4768{
4769 var output = "";
4770 for(var i = 0; i < input.length; i++)
4771 output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
4772 (input.charCodeAt(i) >>> 8) & 0xFF);
4773 return output;
4774}
4775
4776function str2rstr_utf16be(input)
4777{
4778 var output = "";
4779 for(var i = 0; i < input.length; i++)
4780 output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
4781 input.charCodeAt(i) & 0xFF);
4782 return output;
4783}
4784
4785/**
4786 * Convert a raw string to an array of big-endian words
4787 * Characters >255 have their high-byte silently ignored.
4788 */
4789function rstr2binb(input)
4790{
4791 //console.log('Raw string comming is '+input);
4792 var output = Array(input.length >> 2);
Wentao Shangc0311e52012-12-03 10:38:23 -08004793 /* JavaScript automatically zeroizes a new array.
Wentao Shang0e291c82012-12-02 23:36:29 -08004794 for(var i = 0; i < output.length; i++)
4795 output[i] = 0;
Wentao Shangc0311e52012-12-03 10:38:23 -08004796 */
Wentao Shang0e291c82012-12-02 23:36:29 -08004797 for(var i = 0; i < input.length * 8; i += 8)
4798 output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
4799 return output;
4800}
4801
4802/**
4803 * @author axelcdv
4804 * Convert a byte array to an array of big-endian words
4805 * @param {byte[]} input
4806 * @return the array of big-endian words
4807 */
4808function byteArray2binb(input){
4809 //console.log("Byte array coming is " + input);
4810 var output = Array(input.length >> 2);
Wentao Shangc0311e52012-12-03 10:38:23 -08004811 /* JavaScript automatically zeroizes a new array.
Wentao Shang0e291c82012-12-02 23:36:29 -08004812 for(var i = 0; i < output.length; i++)
4813 output[i] = 0;
Wentao Shangc0311e52012-12-03 10:38:23 -08004814 */
Wentao Shang0e291c82012-12-02 23:36:29 -08004815 for(var i = 0; i < input.length * 8; i += 8)
4816 output[i>>5] |= (input[i / 8] & 0xFF) << (24 - i % 32);
4817 return output;
4818}
4819
4820/*
4821 * Convert an array of big-endian words to a string
4822 */
4823function binb2rstr(input)
4824{
4825 var output = "";
4826 for(var i = 0; i < input.length * 32; i += 8)
4827 output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
4828 return output;
4829}
4830
4831/*
4832 * Main sha256 function, with its support functions
4833 */
4834function sha256_S (X, n) {return ( X >>> n ) | (X << (32 - n));}
4835function sha256_R (X, n) {return ( X >>> n );}
4836function sha256_Ch(x, y, z) {return ((x & y) ^ ((~x) & z));}
4837function sha256_Maj(x, y, z) {return ((x & y) ^ (x & z) ^ (y & z));}
4838function sha256_Sigma0256(x) {return (sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22));}
4839function sha256_Sigma1256(x) {return (sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25));}
4840function sha256_Gamma0256(x) {return (sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3));}
4841function sha256_Gamma1256(x) {return (sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10));}
4842function sha256_Sigma0512(x) {return (sha256_S(x, 28) ^ sha256_S(x, 34) ^ sha256_S(x, 39));}
4843function sha256_Sigma1512(x) {return (sha256_S(x, 14) ^ sha256_S(x, 18) ^ sha256_S(x, 41));}
4844function sha256_Gamma0512(x) {return (sha256_S(x, 1) ^ sha256_S(x, 8) ^ sha256_R(x, 7));}
4845function sha256_Gamma1512(x) {return (sha256_S(x, 19) ^ sha256_S(x, 61) ^ sha256_R(x, 6));}
4846
4847var sha256_K = new Array
4848(
4849 1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993,
4850 -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987,
4851 1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522,
4852 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986,
4853 -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585,
4854 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291,
4855 1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885,
4856 -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344,
4857 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218,
4858 1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872,
4859 -1866530822, -1538233109, -1090935817, -965641998
4860);
4861
4862function binb_sha256(m, l)
4863{
4864 var HASH = new Array(1779033703, -1150833019, 1013904242, -1521486534,
4865 1359893119, -1694144372, 528734635, 1541459225);
4866 var W = new Array(64);
Wentao Shang0e291c82012-12-02 23:36:29 -08004867
4868 /* append padding */
4869 m[l >> 5] |= 0x80 << (24 - l % 32);
4870 m[((l + 64 >> 9) << 4) + 15] = l;
Wentao Shangc0311e52012-12-03 10:38:23 -08004871
4872 for(var offset = 0; offset < m.length; offset += 16)
4873 processBlock_sha256(m, offset, HASH, W);
Wentao Shang0e291c82012-12-02 23:36:29 -08004874
Wentao Shangc0311e52012-12-03 10:38:23 -08004875 return HASH;
4876}
4877
4878/*
4879 * Process a block of 16 4-byte words in m starting at offset and update HASH.
4880 * offset must be a multiple of 16 and less than m.length. W is a scratchpad Array(64).
4881 */
4882function processBlock_sha256(m, offset, HASH, W) {
4883 var a, b, c, d, e, f, g, h;
4884 var j, T1, T2;
4885
Wentao Shang0e291c82012-12-02 23:36:29 -08004886 a = HASH[0];
4887 b = HASH[1];
4888 c = HASH[2];
4889 d = HASH[3];
4890 e = HASH[4];
4891 f = HASH[5];
4892 g = HASH[6];
4893 h = HASH[7];
4894
4895 for(j = 0; j < 64; j++)
4896 {
Wentao Shangc0311e52012-12-03 10:38:23 -08004897 if (j < 16) W[j] = m[j + offset];
Wentao Shang0e291c82012-12-02 23:36:29 -08004898 else W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]),
4899 sha256_Gamma0256(W[j - 15])), W[j - 16]);
4900
4901 T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)),
4902 sha256_K[j]), W[j]);
4903 T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
4904 h = g;
4905 g = f;
4906 f = e;
4907 e = safe_add(d, T1);
4908 d = c;
4909 c = b;
4910 b = a;
4911 a = safe_add(T1, T2);
4912 }
4913
4914 HASH[0] = safe_add(a, HASH[0]);
4915 HASH[1] = safe_add(b, HASH[1]);
4916 HASH[2] = safe_add(c, HASH[2]);
4917 HASH[3] = safe_add(d, HASH[3]);
4918 HASH[4] = safe_add(e, HASH[4]);
4919 HASH[5] = safe_add(f, HASH[5]);
4920 HASH[6] = safe_add(g, HASH[6]);
4921 HASH[7] = safe_add(h, HASH[7]);
Wentao Shang0e291c82012-12-02 23:36:29 -08004922}
4923
4924function safe_add (x, y)
4925{
4926 var lsw = (x & 0xFFFF) + (y & 0xFFFF);
4927 var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
4928 return (msw << 16) | (lsw & 0xFFFF);
4929}
Wentao Shangc0311e52012-12-03 10:38:23 -08004930
4931/*
4932 * Create a Sha256, call update(data) multiple times, then call finalize().
4933 */
4934var Sha256 = function Sha256() {
4935 this.W = new Array(64);
4936 this.hash = new Array(1779033703, -1150833019, 1013904242, -1521486534,
4937 1359893119, -1694144372, 528734635, 1541459225);
4938 this.nTotalBytes = 0;
4939 this.buffer = new Uint8Array(16 * 4);
4940 this.nBufferBytes = 0;
4941}
4942
4943/*
4944 * Update the hash with data, which is Uint8Array.
4945 */
4946Sha256.prototype.update = function(data) {
4947 this.nTotalBytes += data.length;
4948
4949 if (this.nBufferBytes > 0) {
4950 // Fill up the buffer and process it first.
4951 var bytesNeeded = this.buffer.length - this.nBufferBytes;
4952 if (data.length < bytesNeeded) {
4953 this.buffer.set(data, this.nBufferBytes);
4954 this.nBufferBytes += data.length;
4955 return;
4956 }
4957 else {
4958 this.buffer.set(data.subarray(0, bytesNeeded), this.nBufferBytes);
4959 processBlock_sha256(byteArray2binb(this.buffer), 0, this.hash, this.W);
4960 this.nBufferBytes = 0;
4961 // Consume the bytes from data.
4962 data = data.subarray(bytesNeeded, data.length);
4963 if (data.length == 0)
4964 return;
4965 }
4966 }
4967
4968 // 2^6 is 16 * 4.
4969 var nBlocks = data.length >> 6;
4970 if (nBlocks > 0) {
4971 var nBytes = nBlocks * 16 * 4;
4972 var m = byteArray2binb(data.subarray(0, nBytes));
4973 for(var offset = 0; offset < m.length; offset += 16)
4974 processBlock_sha256(m, offset, this.hash, this.W);
4975
4976 data = data.subarray(nBytes, data.length);
4977 }
4978
4979 if (data.length > 0) {
4980 // Save the remainder in the buffer.
4981 this.buffer.set(data);
4982 this.nBufferBytes = data.length;
4983 }
4984}
4985
4986/*
4987 * Finalize the hash and return the result as Uint8Array.
4988 * Only call this once. Return values on subsequent calls are undefined.
4989 */
4990Sha256.prototype.finalize = function() {
4991 var m = byteArray2binb(this.buffer.subarray(0, this.nBufferBytes));
4992 /* append padding */
4993 var l = this.nBufferBytes * 8;
4994 m[l >> 5] |= 0x80 << (24 - l % 32);
4995 m[((l + 64 >> 9) << 4) + 15] = this.nTotalBytes * 8;
4996
4997 for(var offset = 0; offset < m.length; offset += 16)
4998 processBlock_sha256(m, offset, this.hash, this.W);
4999
5000 return Sha256.binb2Uint8Array(this.hash);
5001}
5002
5003/*
5004 * Convert an array of big-endian words to Uint8Array.
5005 */
5006Sha256.binb2Uint8Array = function(input)
5007{
5008 var output = new Uint8Array(input.length * 4);
5009 var iOutput = 0;
5010 for (var i = 0; i < input.length * 32; i += 8)
5011 output[iOutput++] = (input[i>>5] >>> (24 - i % 32)) & 0xFF;
5012 return output;
5013}
Wentao Shang0e291c82012-12-02 23:36:29 -08005014var b64map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
5015var b64pad="=";
5016
5017function hex2b64(h) {
5018 var i;
5019 var c;
5020 var ret = "";
5021 for(i = 0; i+3 <= h.length; i+=3) {
5022 c = parseInt(h.substring(i,i+3),16);
5023 ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63);
5024 }
5025 if(i+1 == h.length) {
5026 c = parseInt(h.substring(i,i+1),16);
5027 ret += b64map.charAt(c << 2);
5028 }
5029 else if(i+2 == h.length) {
5030 c = parseInt(h.substring(i,i+2),16);
5031 ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4);
5032 }
5033 while((ret.length & 3) > 0) ret += b64pad;
5034 return ret;
5035}
5036
5037// convert a base64 string to hex
5038function b64tohex(s) {
5039 var ret = ""
5040 var i;
5041 var k = 0; // b64 state, 0-3
5042 var slop;
5043 for(i = 0; i < s.length; ++i) {
5044 if(s.charAt(i) == b64pad) break;
5045 v = b64map.indexOf(s.charAt(i));
5046 if(v < 0) continue;
5047 if(k == 0) {
5048 ret += int2char(v >> 2);
5049 slop = v & 3;
5050 k = 1;
5051 }
5052 else if(k == 1) {
5053 ret += int2char((slop << 2) | (v >> 4));
5054 slop = v & 0xf;
5055 k = 2;
5056 }
5057 else if(k == 2) {
5058 ret += int2char(slop);
5059 ret += int2char(v >> 2);
5060 slop = v & 3;
5061 k = 3;
5062 }
5063 else {
5064 ret += int2char((slop << 2) | (v >> 4));
5065 ret += int2char(v & 0xf);
5066 k = 0;
5067 }
5068 }
5069 if(k == 1)
5070 ret += int2char(slop << 2);
5071 return ret;
5072}
5073
5074// convert a base64 string to a byte/number array
5075function b64toBA(s) {
5076 //piggyback on b64tohex for now, optimize later
5077 var h = b64tohex(s);
5078 var i;
5079 var a = new Array();
5080 for(i = 0; 2*i < h.length; ++i) {
5081 a[i] = parseInt(h.substring(2*i,2*i+2),16);
5082 }
5083 return a;
5084}
5085// Depends on jsbn.js and rng.js
5086
5087// Version 1.1: support utf-8 encoding in pkcs1pad2
5088
5089// convert a (hex) string to a bignum object
5090function parseBigInt(str,r) {
5091 return new BigInteger(str,r);
5092}
5093
5094function linebrk(s,n) {
5095 var ret = "";
5096 var i = 0;
5097 while(i + n < s.length) {
5098 ret += s.substring(i,i+n) + "\n";
5099 i += n;
5100 }
5101 return ret + s.substring(i,s.length);
5102}
5103
5104function byte2Hex(b) {
5105 if(b < 0x10)
5106 return "0" + b.toString(16);
5107 else
5108 return b.toString(16);
5109}
5110
5111/**
5112 * PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint
5113 * @param s: the string to encode
5114 * @param n: the size in byte
5115 */
5116function pkcs1pad2(s,n) {
5117 if(n < s.length + 11) { // TODO: fix for utf-8
5118 alert("Message too long for RSA");
5119 return null;
5120 }
5121 var ba = new Array();
5122 var i = s.length - 1;
5123 while(i >= 0 && n > 0) {
5124 var c = s.charCodeAt(i--);
5125 if(c < 128) { // encode using utf-8
5126 ba[--n] = c;
5127 }
5128 else if((c > 127) && (c < 2048)) {
5129 ba[--n] = (c & 63) | 128;
5130 ba[--n] = (c >> 6) | 192;
5131 }
5132 else {
5133 ba[--n] = (c & 63) | 128;
5134 ba[--n] = ((c >> 6) & 63) | 128;
5135 ba[--n] = (c >> 12) | 224;
5136 }
5137 }
5138 ba[--n] = 0;
5139 var rng = new SecureRandom();
5140 var x = new Array();
5141 while(n > 2) { // random non-zero pad
5142 x[0] = 0;
5143 while(x[0] == 0) rng.nextBytes(x);
5144 ba[--n] = x[0];
5145 }
5146 ba[--n] = 2;
5147 ba[--n] = 0;
5148 return new BigInteger(ba);
5149}
5150
5151/**
5152 * "empty" RSA key constructor
5153 * @returns {RSAKey}
5154 */
5155function RSAKey() {
5156 this.n = null;
5157 this.e = 0;
5158 this.d = null;
5159 this.p = null;
5160 this.q = null;
5161 this.dmp1 = null;
5162 this.dmq1 = null;
5163 this.coeff = null;
5164}
5165
5166/**
5167 * Set the public key fields N and e from hex strings
5168 * @param N
5169 * @param E
5170 * @returns {RSASetPublic}
5171 */
5172function RSASetPublic(N,E) {
5173 if(N != null && E != null && N.length > 0 && E.length > 0) {
5174 this.n = parseBigInt(N,16);
5175 this.e = parseInt(E,16);
5176 }
5177 else
5178 alert("Invalid RSA public key");
5179}
5180
5181/**
5182 * Perform raw public operation on "x": return x^e (mod n)
5183 * @param x
5184 * @returns x^e (mod n)
5185 */
5186function RSADoPublic(x) {
5187 return x.modPowInt(this.e, this.n);
5188}
5189
5190/**
5191 * Return the PKCS#1 RSA encryption of "text" as an even-length hex string
5192 */
5193function RSAEncrypt(text) {
5194 var m = pkcs1pad2(text,(this.n.bitLength()+7)>>3);
5195 if(m == null) return null;
5196 var c = this.doPublic(m);
5197 if(c == null) return null;
5198 var h = c.toString(16);
5199 if((h.length & 1) == 0) return h; else return "0" + h;
5200}
5201
5202// Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string
5203//function RSAEncryptB64(text) {
5204// var h = this.encrypt(text);
5205// if(h) return hex2b64(h); else return null;
5206//}
5207
5208// protected
5209RSAKey.prototype.doPublic = RSADoPublic;
5210
5211// public
5212RSAKey.prototype.setPublic = RSASetPublic;
5213RSAKey.prototype.encrypt = RSAEncrypt;
5214//RSAKey.prototype.encrypt_b64 = RSAEncryptB64;
5215// Depends on rsa.js and jsbn2.js
5216
5217// Version 1.1: support utf-8 decoding in pkcs1unpad2
5218
5219// Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext
5220function pkcs1unpad2(d,n) {
5221 var b = d.toByteArray();
5222 var i = 0;
5223 while(i < b.length && b[i] == 0) ++i;
5224 if(b.length-i != n-1 || b[i] != 2)
5225 return null;
5226 ++i;
5227 while(b[i] != 0)
5228 if(++i >= b.length) return null;
5229 var ret = "";
5230 while(++i < b.length) {
5231 var c = b[i] & 255;
5232 if(c < 128) { // utf-8 decode
5233 ret += String.fromCharCode(c);
5234 }
5235 else if((c > 191) && (c < 224)) {
5236 ret += String.fromCharCode(((c & 31) << 6) | (b[i+1] & 63));
5237 ++i;
5238 }
5239 else {
5240 ret += String.fromCharCode(((c & 15) << 12) | ((b[i+1] & 63) << 6) | (b[i+2] & 63));
5241 i += 2;
5242 }
5243 }
5244 return ret;
5245}
5246
5247// Set the private key fields N, e, and d from hex strings
5248function RSASetPrivate(N,E,D) {
5249 if(N != null && E != null && N.length > 0 && E.length > 0) {
5250 this.n = parseBigInt(N,16);
5251 this.e = parseInt(E,16);
5252 this.d = parseBigInt(D,16);
5253 }
5254 else
5255 alert("Invalid RSA private key");
5256}
5257
5258// Set the private key fields N, e, d and CRT params from hex strings
5259function RSASetPrivateEx(N,E,D,P,Q,DP,DQ,C) {
5260 if(N != null && E != null && N.length > 0 && E.length > 0) {
5261 this.n = parseBigInt(N,16);
5262 this.e = parseInt(E,16);
5263 this.d = parseBigInt(D,16);
5264 this.p = parseBigInt(P,16);
5265 this.q = parseBigInt(Q,16);
5266 this.dmp1 = parseBigInt(DP,16);
5267 this.dmq1 = parseBigInt(DQ,16);
5268 this.coeff = parseBigInt(C,16);
5269 }
5270 else
5271 alert("Invalid RSA private key");
5272}
5273
5274/**
5275 * Generate a new random private key B bits long, using public expt E
5276 */
5277function RSAGenerate(B,E) {
5278 var rng = new SecureRandom();
5279 var qs = B>>1;
5280 this.e = parseInt(E,16);
5281 var ee = new BigInteger(E,16);
5282 for(;;) {
5283 for(;;) {
5284 this.p = new BigInteger(B-qs,1,rng);
5285 if(this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.p.isProbablePrime(10)) break;
5286 }
5287 for(;;) {
5288 this.q = new BigInteger(qs,1,rng);
5289 if(this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.q.isProbablePrime(10)) break;
5290 }
5291 if(this.p.compareTo(this.q) <= 0) {
5292 var t = this.p;
5293 this.p = this.q;
5294 this.q = t;
5295 }
5296 var p1 = this.p.subtract(BigInteger.ONE); // p1 = p - 1
5297 var q1 = this.q.subtract(BigInteger.ONE); // q1 = q - 1
5298 var phi = p1.multiply(q1);
5299 if(phi.gcd(ee).compareTo(BigInteger.ONE) == 0) {
5300 this.n = this.p.multiply(this.q); // this.n = p * q
5301 this.d = ee.modInverse(phi); // this.d =
5302 this.dmp1 = this.d.mod(p1); // this.dmp1 = d mod (p - 1)
5303 this.dmq1 = this.d.mod(q1); // this.dmq1 = d mod (q - 1)
5304 this.coeff = this.q.modInverse(this.p); // this.coeff = (q ^ -1) mod p
5305 break;
5306 }
5307 }
5308}
5309
5310/**
5311 * Perform raw private operation on "x": return x^d (mod n)
5312 * @return x^d (mod n)
5313 */
5314function RSADoPrivate(x) {
5315 if(this.p == null || this.q == null)
5316 return x.modPow(this.d, this.n);
5317
5318 // TODO: re-calculate any missing CRT params
5319 var xp = x.mod(this.p).modPow(this.dmp1, this.p); // xp=cp?
5320 var xq = x.mod(this.q).modPow(this.dmq1, this.q); // xq=cq?
5321
5322 while(xp.compareTo(xq) < 0)
5323 xp = xp.add(this.p);
5324 // NOTE:
5325 // xp.subtract(xq) => cp -cq
5326 // xp.subtract(xq).multiply(this.coeff).mod(this.p) => (cp - cq) * u mod p = h
5327 // xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq) => cq + (h * q) = M
5328 return xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq);
5329}
5330
5331// Return the PKCS#1 RSA decryption of "ctext".
5332// "ctext" is an even-length hex string and the output is a plain string.
5333function RSADecrypt(ctext) {
5334 var c = parseBigInt(ctext, 16);
5335 var m = this.doPrivate(c);
5336 if(m == null) return null;
5337 return pkcs1unpad2(m, (this.n.bitLength()+7)>>3);
5338}
5339
5340// Return the PKCS#1 RSA decryption of "ctext".
5341// "ctext" is a Base64-encoded string and the output is a plain string.
5342//function RSAB64Decrypt(ctext) {
5343// var h = b64tohex(ctext);
5344// if(h) return this.decrypt(h); else return null;
5345//}
5346
5347// protected
5348RSAKey.prototype.doPrivate = RSADoPrivate;
5349
5350// public
5351RSAKey.prototype.setPrivate = RSASetPrivate;
5352RSAKey.prototype.setPrivateEx = RSASetPrivateEx;
5353RSAKey.prototype.generate = RSAGenerate;
5354RSAKey.prototype.decrypt = RSADecrypt;
5355//RSAKey.prototype.b64_decrypt = RSAB64Decrypt;
5356/*! rsapem-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
5357 */
5358//
5359// rsa-pem.js - adding function for reading/writing PKCS#1 PEM private key
5360// to RSAKey class.
5361//
5362// version: 1.1 (2012-May-10)
5363//
5364// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
5365//
5366// This software is licensed under the terms of the MIT License.
5367// http://kjur.github.com/jsrsasign/license/
5368//
5369// The above copyright and license notice shall be
5370// included in all copies or substantial portions of the Software.
5371//
5372//
5373// Depends on:
5374//
5375//
5376//
5377// _RSApem_pemToBase64(sPEM)
5378//
5379// removing PEM header, PEM footer and space characters including
5380// new lines from PEM formatted RSA private key string.
5381//
5382
5383function _rsapem_pemToBase64(sPEMPrivateKey) {
5384 var s = sPEMPrivateKey;
5385 s = s.replace("-----BEGIN RSA PRIVATE KEY-----", "");
5386 s = s.replace("-----END RSA PRIVATE KEY-----", "");
5387 s = s.replace(/[ \n]+/g, "");
5388 return s;
5389}
5390
5391function _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey) {
5392 var a = new Array();
5393 var v1 = ASN1HEX.getStartPosOfV_AtObj(hPrivateKey, 0);
5394 var n1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, v1);
5395 var e1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, n1);
5396 var d1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, e1);
5397 var p1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, d1);
5398 var q1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, p1);
5399 var dp1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, q1);
5400 var dq1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dp1);
5401 var co1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dq1);
5402 a.push(v1, n1, e1, d1, p1, q1, dp1, dq1, co1);
5403 return a;
5404}
5405
5406function _rsapem_getHexValueArrayOfChildrenFromHex(hPrivateKey) {
5407 var posArray = _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey);
5408 var v = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[0]);
5409 var n = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[1]);
5410 var e = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[2]);
5411 var d = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[3]);
5412 var p = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[4]);
5413 var q = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[5]);
5414 var dp = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[6]);
5415 var dq = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[7]);
5416 var co = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[8]);
5417 var a = new Array();
5418 a.push(v, n, e, d, p, q, dp, dq, co);
5419 return a;
5420}
5421
5422/**
5423 * read PKCS#1 private key from a string
5424 * @name readPrivateKeyFromPEMString
5425 * @memberOf RSAKey#
5426 * @function
5427 * @param {String} keyPEM string of PKCS#1 private key.
5428 */
5429function _rsapem_readPrivateKeyFromPEMString(keyPEM) {
5430 var keyB64 = _rsapem_pemToBase64(keyPEM);
5431 var keyHex = b64tohex(keyB64) // depends base64.js
5432 var a = _rsapem_getHexValueArrayOfChildrenFromHex(keyHex);
5433 this.setPrivateEx(a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]);
5434}
5435
5436RSAKey.prototype.readPrivateKeyFromPEMString = _rsapem_readPrivateKeyFromPEMString;
5437/*! rsasign-1.2.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
5438 */
5439//
5440// rsa-sign.js - adding signing functions to RSAKey class.
5441//
5442//
5443// version: 1.2.1 (08 May 2012)
5444//
5445// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
5446//
5447// This software is licensed under the terms of the MIT License.
5448// http://kjur.github.com/jsrsasign/license/
5449//
5450// The above copyright and license notice shall be
5451// included in all copies or substantial portions of the Software.
5452
5453//
5454// Depends on:
5455// function sha1.hex(s) of sha1.js
5456// jsbn.js
5457// jsbn2.js
5458// rsa.js
5459// rsa2.js
5460//
5461
5462// keysize / pmstrlen
5463// 512 / 128
5464// 1024 / 256
5465// 2048 / 512
5466// 4096 / 1024
5467
5468/**
5469 * @property {Dictionary} _RSASIGN_DIHEAD
5470 * @description Array of head part of hexadecimal DigestInfo value for hash algorithms.
5471 * You can add any DigestInfo hash algorith for signing.
5472 * See PKCS#1 v2.1 spec (p38).
5473 */
5474var _RSASIGN_DIHEAD = [];
5475_RSASIGN_DIHEAD['sha1'] = "3021300906052b0e03021a05000414";
5476_RSASIGN_DIHEAD['sha256'] = "3031300d060960864801650304020105000420";
5477_RSASIGN_DIHEAD['sha384'] = "3041300d060960864801650304020205000430";
5478_RSASIGN_DIHEAD['sha512'] = "3051300d060960864801650304020305000440";
5479_RSASIGN_DIHEAD['md2'] = "3020300c06082a864886f70d020205000410";
5480_RSASIGN_DIHEAD['md5'] = "3020300c06082a864886f70d020505000410";
5481_RSASIGN_DIHEAD['ripemd160'] = "3021300906052b2403020105000414";
5482
5483/**
5484 * @property {Dictionary} _RSASIGN_HASHHEXFUNC
5485 * @description Array of functions which calculate hash and returns it as hexadecimal.
5486 * You can add any hash algorithm implementations.
5487 */
5488var _RSASIGN_HASHHEXFUNC = [];
5489_RSASIGN_HASHHEXFUNC['sha1'] = function(s){return hex_sha1(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
5490_RSASIGN_HASHHEXFUNC['sha256'] = function(s){return hex_sha256(s);} // http://pajhome.org.uk/crypt/md5/md5.html
5491_RSASIGN_HASHHEXFUNC['sha512'] = function(s){return hex_sha512(s);} // http://pajhome.org.uk/crypt/md5/md5.html
5492_RSASIGN_HASHHEXFUNC['md5'] = function(s){return hex_md5(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
5493_RSASIGN_HASHHEXFUNC['ripemd160'] = function(s){return hex_rmd160(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
5494
5495//@author axelcdv
5496var _RSASIGN_HASHBYTEFUNC = [];
5497_RSASIGN_HASHBYTEFUNC['sha256'] = function(byteArray){return hex_sha256_from_bytes(byteArray);};
5498
5499//_RSASIGN_HASHHEXFUNC['sha1'] = function(s){return sha1.hex(s);} // http://user1.matsumoto.ne.jp/~goma/js/hash.html
5500//_RSASIGN_HASHHEXFUNC['sha256'] = function(s){return sha256.hex;} // http://user1.matsumoto.ne.jp/~goma/js/hash.html
5501
5502var _RE_HEXDECONLY = new RegExp("");
5503_RE_HEXDECONLY.compile("[^0-9a-f]", "gi");
5504
5505// ========================================================================
5506// Signature Generation
5507// ========================================================================
5508
5509function _rsasign_getHexPaddedDigestInfoForString(s, keySize, hashAlg) {
5510 var pmStrLen = keySize / 4;
5511 var hashFunc = _RSASIGN_HASHHEXFUNC[hashAlg];
5512 var sHashHex = hashFunc(s);
5513
5514 var sHead = "0001";
5515 var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex;
5516 var sMid = "";
5517 var fLen = pmStrLen - sHead.length - sTail.length;
5518 for (var i = 0; i < fLen; i += 2) {
5519 sMid += "ff";
5520 }
5521 sPaddedMessageHex = sHead + sMid + sTail;
5522 return sPaddedMessageHex;
5523}
5524
5525
5526//@author: Meki Cheraoui
5527function _rsasign_getHexPaddedDigestInfoForStringHEX(s, keySize, hashAlg) {
5528 var pmStrLen = keySize / 4;
5529 var hashFunc = _RSASIGN_HASHHEXFUNC[hashAlg];
5530 var sHashHex = hashFunc(s);
5531
5532 var sHead = "0001";
5533 var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex;
5534 var sMid = "";
5535 var fLen = pmStrLen - sHead.length - sTail.length;
5536 for (var i = 0; i < fLen; i += 2) {
5537 sMid += "ff";
5538 }
5539 sPaddedMessageHex = sHead + sMid + sTail;
5540 return sPaddedMessageHex;
5541}
5542
5543/**
5544 * Apply padding, then computes the hash of the given byte array, according to the key size and with the hash algorithm
5545 * @param byteArray (byte[])
5546 * @param keySize (int)
5547 * @param hashAlg the hash algorithm to apply (string)
5548 * @return the hash of byteArray
5549 */
5550function _rsasign_getHexPaddedDigestInfoForByteArray(byteArray, keySize, hashAlg){
5551 var pmStrLen = keySize / 4;
5552 var hashFunc = _RSASIGN_HASHBYTEFUNC[hashAlg];
5553 var sHashHex = hashFunc(byteArray); //returns hex hash
5554
5555 var sHead = "0001";
5556 var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex;
5557 var sMid = "";
5558 var fLen = pmStrLen - sHead.length - sTail.length;
5559 for (var i = 0; i < fLen; i += 2) {
5560 sMid += "ff";
5561 }
5562 sPaddedMessageHex = sHead + sMid + sTail;
5563 return sPaddedMessageHex;
5564}
5565
5566function _zeroPaddingOfSignature(hex, bitLength) {
5567 var s = "";
5568 var nZero = bitLength / 4 - hex.length;
5569 for (var i = 0; i < nZero; i++) {
5570 s = s + "0";
5571 }
5572 return s + hex;
5573}
5574
5575/**
5576 * sign for a message string with RSA private key.<br/>
5577 * @name signString
5578 * @memberOf RSAKey#
5579 * @function
5580 * @param {String} s message string to be signed.
5581 * @param {String} hashAlg hash algorithm name for signing.<br/>
5582 * @return returns hexadecimal string of signature value.
5583 */
5584function _rsasign_signString(s, hashAlg) {
5585 //alert("this.n.bitLength() = " + this.n.bitLength());
5586 var hPM = _rsasign_getHexPaddedDigestInfoForString(s, this.n.bitLength(), hashAlg);
5587 var biPaddedMessage = parseBigInt(hPM, 16);
5588 var biSign = this.doPrivate(biPaddedMessage);
5589 var hexSign = biSign.toString(16);
5590 return _zeroPaddingOfSignature(hexSign, this.n.bitLength());
5591}
5592
5593//@author: ucla-cs
5594function _rsasign_signStringHEX(s, hashAlg) {
5595 //alert("this.n.bitLength() = " + this.n.bitLength());
5596 var hPM = _rsasign_getHexPaddedDigestInfoForString(s, this.n.bitLength(), hashAlg);
5597 var biPaddedMessage = parseBigInt(hPM, 16);
5598 var biSign = this.doPrivate(biPaddedMessage);
5599 var hexSign = biSign.toString(16);
5600 return _zeroPaddingOfSignature(hexSign, this.n.bitLength());
5601}
5602
5603
5604/**
5605 * Sign a message byteArray with an RSA private key
5606 * @name signByteArray
5607 * @memberOf RSAKey#
5608 * @function
5609 * @param {byte[]} byteArray
5610 * @param {Sring} hashAlg the hash algorithm to apply
5611 * @param {RSAKey} rsa key to sign with: hack because the context is lost here
5612 * @return hexadecimal string of signature value
5613 */
5614function _rsasign_signByteArray(byteArray, hashAlg, rsaKey) {
5615 var hPM = _rsasign_getHexPaddedDigestInfoForByteArray(byteArray, rsaKey.n.bitLength(), hashAlg); ///hack because the context is lost here
5616 var biPaddedMessage = parseBigInt(hPM, 16);
5617 var biSign = rsaKey.doPrivate(biPaddedMessage); //hack because the context is lost here
5618 var hexSign = biSign.toString(16);
5619 return _zeroPaddingOfSignature(hexSign, rsaKey.n.bitLength()); //hack because the context is lost here
5620}
5621
5622/**
5623 * Sign a byte array with the Sha-256 algorithm
5624 * @param {byte[]} byteArray
5625 * @return hexadecimal string of signature value
5626 */
5627function _rsasign_signByteArrayWithSHA256(byteArray){
5628 return _rsasign_signByteArray(byteArray, 'sha256', this); //Hack because the context is lost in the next function
5629}
5630
5631
5632function _rsasign_signStringWithSHA1(s) {
5633 return _rsasign_signString(s, 'sha1');
5634}
5635
5636function _rsasign_signStringWithSHA256(s) {
5637 return _rsasign_signString(s, 'sha256');
5638}
5639
5640// ========================================================================
5641// Signature Verification
5642// ========================================================================
5643
5644function _rsasign_getDecryptSignatureBI(biSig, hN, hE) {
5645 var rsa = new RSAKey();
5646 rsa.setPublic(hN, hE);
5647 var biDecryptedSig = rsa.doPublic(biSig);
5648 return biDecryptedSig;
5649}
5650
5651function _rsasign_getHexDigestInfoFromSig(biSig, hN, hE) {
5652 var biDecryptedSig = _rsasign_getDecryptSignatureBI(biSig, hN, hE);
5653 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
5654 return hDigestInfo;
5655}
5656
5657function _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo) {
5658 for (var algName in _RSASIGN_DIHEAD) {
5659 var head = _RSASIGN_DIHEAD[algName];
5660 var len = head.length;
5661 if (hDigestInfo.substring(0, len) == head) {
5662 var a = [algName, hDigestInfo.substring(len)];
5663 return a;
5664 }
5665 }
5666 return [];
5667}
5668
5669function _rsasign_verifySignatureWithArgs(sMsg, biSig, hN, hE) {
5670 var hDigestInfo = _rsasign_getHexDigestInfoFromSig(biSig, hN, hE);
5671 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
5672 if (digestInfoAry.length == 0) return false;
5673 var algName = digestInfoAry[0];
5674 var diHashValue = digestInfoAry[1];
5675 var ff = _RSASIGN_HASHHEXFUNC[algName];
5676 var msgHashValue = ff(sMsg);
5677 return (diHashValue == msgHashValue);
5678}
5679
5680function _rsasign_verifyHexSignatureForMessage(hSig, sMsg) {
5681 var biSig = parseBigInt(hSig, 16);
5682 var result = _rsasign_verifySignatureWithArgs(sMsg, biSig,
5683 this.n.toString(16),
5684 this.e.toString(16));
5685 return result;
5686}
5687
5688/**
5689 * verifies a sigature for a message string with RSA public key.<br/>
5690 * @name verifyString
5691 * @memberOf RSAKey#
5692 * @function
5693 * @param {String} sMsg message string to be verified.
5694 * @param {String} hSig hexadecimal string of siganture.<br/>
5695 * non-hexadecimal charactors including new lines will be ignored.
5696 * @return returns 1 if valid, otherwise 0
5697 */
5698function _rsasign_verifyString(sMsg, hSig) {
5699 hSig = hSig.replace(_RE_HEXDECONLY, '');
5700
5701 if(LOG>3)console.log('n is '+this.n);
5702 if(LOG>3)console.log('e is '+this.e);
5703
5704 if (hSig.length != this.n.bitLength() / 4) return 0;
5705 hSig = hSig.replace(/[ \n]+/g, "");
5706 var biSig = parseBigInt(hSig, 16);
5707 var biDecryptedSig = this.doPublic(biSig);
5708 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
5709 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
5710
5711 if (digestInfoAry.length == 0) return false;
5712 var algName = digestInfoAry[0];
5713 var diHashValue = digestInfoAry[1];
5714 var ff = _RSASIGN_HASHHEXFUNC[algName];
5715 var msgHashValue = ff(sMsg);
5716 return (diHashValue == msgHashValue);
5717}
5718
5719/**
5720 * verifies a sigature for a message byte array with RSA public key.<br/>
5721 * @name verifyByteArray
5722 * @memberOf RSAKey#
5723 * @function
5724 * @param {byte[]} byteArray message byte array to be verified.
5725 * @param {String} hSig hexadecimal string of signature.<br/>
5726 * non-hexadecimal charactors including new lines will be ignored.
5727 * @return returns 1 if valid, otherwise 0
5728 */
5729function _rsasign_verifyByteArray(byteArray, hSig) {
5730 hSig = hSig.replace(_RE_HEXDECONLY, '');
5731
5732 if(LOG>3)console.log('n is '+this.n);
5733 if(LOG>3)console.log('e is '+this.e);
5734
5735 if (hSig.length != this.n.bitLength() / 4) return 0;
5736 hSig = hSig.replace(/[ \n]+/g, "");
5737 var biSig = parseBigInt(hSig, 16);
5738 var biDecryptedSig = this.doPublic(biSig);
5739 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
5740 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
5741
5742 if (digestInfoAry.length == 0) return false;
5743 var algName = digestInfoAry[0];
5744 var diHashValue = digestInfoAry[1];
5745 var ff = _RSASIGN_HASHBYTEFUNC[algName];
5746 var msgHashValue = ff(byteArray);
5747 return (diHashValue == msgHashValue);
5748}
5749
5750RSAKey.prototype.signString = _rsasign_signString;
5751
5752RSAKey.prototype.signByteArray = _rsasign_signByteArray; //@author axelcdv
5753RSAKey.prototype.signByteArrayWithSHA256 = _rsasign_signByteArrayWithSHA256; //@author axelcdv
5754
5755RSAKey.prototype.signStringWithSHA1 = _rsasign_signStringWithSHA1;
5756RSAKey.prototype.signStringWithSHA256 = _rsasign_signStringWithSHA256;
5757RSAKey.prototype.sign = _rsasign_signString;
5758RSAKey.prototype.signWithSHA1 = _rsasign_signStringWithSHA1;
5759RSAKey.prototype.signWithSHA256 = _rsasign_signStringWithSHA256;
5760
5761
5762/*RSAKey.prototype.signStringHEX = _rsasign_signStringHEX;
5763RSAKey.prototype.signStringWithSHA1HEX = _rsasign_signStringWithSHA1HEX;
5764RSAKey.prototype.signStringWithSHA256HEX = _rsasign_signStringWithSHA256HEX;
5765RSAKey.prototype.signHEX = _rsasign_signStringHEX;
5766RSAKey.prototype.signWithSHA1HEX = _rsasign_signStringWithSHA1HEX;
5767RSAKey.prototype.signWithSHA256HEX = _rsasign_signStringWithSHA256HEX;
5768*/
5769
5770RSAKey.prototype.verifyByteArray = _rsasign_verifyByteArray;
5771RSAKey.prototype.verifyString = _rsasign_verifyString;
5772RSAKey.prototype.verifyHexSignatureForMessage = _rsasign_verifyHexSignatureForMessage;
5773RSAKey.prototype.verify = _rsasign_verifyString;
5774RSAKey.prototype.verifyHexSignatureForByteArrayMessage = _rsasign_verifyHexSignatureForMessage;
5775
5776/*
5777RSAKey.prototype.verifyStringHEX = _rsasign_verifyStringHEX;
5778RSAKey.prototype.verifyHexSignatureForMessageHEX = _rsasign_verifyHexSignatureForMessageHEX;
5779RSAKey.prototype.verifyHEX = _rsasign_verifyStringHEX;
5780RSAKey.prototype.verifyHexSignatureForByteArrayMessageHEX = _rsasign_verifyHexSignatureForMessageHEX;
5781*/
5782
5783
5784/**
5785 * @name RSAKey
5786 * @class
5787 * @description Tom Wu's RSA Key class and extension
5788 */
5789/*! asn1hex-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
5790 */
5791//
5792// asn1hex.js - Hexadecimal represented ASN.1 string library
5793//
5794// version: 1.1 (09-May-2012)
5795//
5796// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
5797//
5798// This software is licensed under the terms of the MIT License.
5799// http://kjur.github.com/jsrsasign/license/
5800//
5801// The above copyright and license notice shall be
5802// included in all copies or substantial portions of the Software.
5803//
5804// Depends on:
5805//
5806
5807// MEMO:
5808// f('3082025b02...', 2) ... 82025b ... 3bytes
5809// f('020100', 2) ... 01 ... 1byte
5810// f('0203001...', 2) ... 03 ... 1byte
5811// f('02818003...', 2) ... 8180 ... 2bytes
5812// f('3080....0000', 2) ... 80 ... -1
5813//
5814// Requirements:
5815// - ASN.1 type octet length MUST be 1.
5816// (i.e. ASN.1 primitives like SET, SEQUENCE, INTEGER, OCTETSTRING ...)
5817// -
5818/**
5819 * get byte length for ASN.1 L(length) bytes
5820 * @name getByteLengthOfL_AtObj
5821 * @memberOf ASN1HEX
5822 * @function
5823 * @param {String} s hexadecimal string of ASN.1 DER encoded data
5824 * @param {Number} pos string index
5825 * @return byte length for ASN.1 L(length) bytes
5826 */
5827function _asnhex_getByteLengthOfL_AtObj(s, pos) {
5828 if (s.substring(pos + 2, pos + 3) != '8') return 1;
5829 var i = parseInt(s.substring(pos + 3, pos + 4));
5830 if (i == 0) return -1; // length octet '80' indefinite length
5831 if (0 < i && i < 10) return i + 1; // including '8?' octet;
5832 return -2; // malformed format
5833}
5834
5835
5836/**
5837 * get hexadecimal string for ASN.1 L(length) bytes
5838 * @name getHexOfL_AtObj
5839 * @memberOf ASN1HEX
5840 * @function
5841 * @param {String} s hexadecimal string of ASN.1 DER encoded data
5842 * @param {Number} pos string index
5843 * @return {String} hexadecimal string for ASN.1 L(length) bytes
5844 */
5845function _asnhex_getHexOfL_AtObj(s, pos) {
5846 var len = _asnhex_getByteLengthOfL_AtObj(s, pos);
5847 if (len < 1) return '';
5848 return s.substring(pos + 2, pos + 2 + len * 2);
5849}
5850
5851//
5852// getting ASN.1 length value at the position 'idx' of
5853// hexa decimal string 's'.
5854//
5855// f('3082025b02...', 0) ... 82025b ... ???
5856// f('020100', 0) ... 01 ... 1
5857// f('0203001...', 0) ... 03 ... 3
5858// f('02818003...', 0) ... 8180 ... 128
5859/**
5860 * get integer value of ASN.1 length for ASN.1 data
5861 * @name getIntOfL_AtObj
5862 * @memberOf ASN1HEX
5863 * @function
5864 * @param {String} s hexadecimal string of ASN.1 DER encoded data
5865 * @param {Number} pos string index
5866 * @return ASN.1 L(length) integer value
5867 */
5868function _asnhex_getIntOfL_AtObj(s, pos) {
5869 var hLength = _asnhex_getHexOfL_AtObj(s, pos);
5870 if (hLength == '') return -1;
5871 var bi;
5872 if (parseInt(hLength.substring(0, 1)) < 8) {
5873 bi = parseBigInt(hLength, 16);
5874 } else {
5875 bi = parseBigInt(hLength.substring(2), 16);
5876 }
5877 return bi.intValue();
5878}
5879
5880/**
5881 * get ASN.1 value starting string position for ASN.1 object refered by index 'idx'.
5882 * @name getStartPosOfV_AtObj
5883 * @memberOf ASN1HEX
5884 * @function
5885 * @param {String} s hexadecimal string of ASN.1 DER encoded data
5886 * @param {Number} pos string index
5887 */
5888function _asnhex_getStartPosOfV_AtObj(s, pos) {
5889 var l_len = _asnhex_getByteLengthOfL_AtObj(s, pos);
5890 if (l_len < 0) return l_len;
5891 return pos + (l_len + 1) * 2;
5892}
5893
5894/**
5895 * get hexadecimal string of ASN.1 V(value)
5896 * @name getHexOfV_AtObj
5897 * @memberOf ASN1HEX
5898 * @function
5899 * @param {String} s hexadecimal string of ASN.1 DER encoded data
5900 * @param {Number} pos string index
5901 * @return {String} hexadecimal string of ASN.1 value.
5902 */
5903function _asnhex_getHexOfV_AtObj(s, pos) {
5904 var pos1 = _asnhex_getStartPosOfV_AtObj(s, pos);
5905 var len = _asnhex_getIntOfL_AtObj(s, pos);
5906 return s.substring(pos1, pos1 + len * 2);
5907}
5908
5909/**
5910 * get hexadecimal string of ASN.1 TLV at
5911 * @name getHexOfTLV_AtObj
5912 * @memberOf ASN1HEX
5913 * @function
5914 * @param {String} s hexadecimal string of ASN.1 DER encoded data
5915 * @param {Number} pos string index
5916 * @return {String} hexadecimal string of ASN.1 TLV.
5917 * @since 1.1
5918 */
5919function _asnhex_getHexOfTLV_AtObj(s, pos) {
5920 var hT = s.substr(pos, 2);
5921 var hL = _asnhex_getHexOfL_AtObj(s, pos);
5922 var hV = _asnhex_getHexOfV_AtObj(s, pos);
5923 return hT + hL + hV;
5924}
5925
5926/**
5927 * get next sibling starting index for ASN.1 object string
5928 * @name getPosOfNextSibling_AtObj
5929 * @memberOf ASN1HEX
5930 * @function
5931 * @param {String} s hexadecimal string of ASN.1 DER encoded data
5932 * @param {Number} pos string index
5933 * @return next sibling starting index for ASN.1 object string
5934 */
5935function _asnhex_getPosOfNextSibling_AtObj(s, pos) {
5936 var pos1 = _asnhex_getStartPosOfV_AtObj(s, pos);
5937 var len = _asnhex_getIntOfL_AtObj(s, pos);
5938 return pos1 + len * 2;
5939}
5940
5941/**
5942 * get array of indexes of child ASN.1 objects
5943 * @name getPosArrayOfChildren_AtObj
5944 * @memberOf ASN1HEX
5945 * @function
5946 * @param {String} s hexadecimal string of ASN.1 DER encoded data
5947 * @param {Number} start string index of ASN.1 object
5948 * @return {Array of Number} array of indexes for childen of ASN.1 objects
5949 */
5950function _asnhex_getPosArrayOfChildren_AtObj(h, pos) {
5951 var a = new Array();
5952 var p0 = _asnhex_getStartPosOfV_AtObj(h, pos);
5953 a.push(p0);
5954
5955 var len = _asnhex_getIntOfL_AtObj(h, pos);
5956 var p = p0;
5957 var k = 0;
5958 while (1) {
5959 var pNext = _asnhex_getPosOfNextSibling_AtObj(h, p);
5960 if (pNext == null || (pNext - p0 >= (len * 2))) break;
5961 if (k >= 200) break;
5962
5963 a.push(pNext);
5964 p = pNext;
5965
5966 k++;
5967 }
5968
5969 return a;
5970}
5971
5972/**
5973 * get string index of nth child object of ASN.1 object refered by h, idx
5974 * @name getNthChildIndex_AtObj
5975 * @memberOf ASN1HEX
5976 * @function
5977 * @param {String} h hexadecimal string of ASN.1 DER encoded data
5978 * @param {Number} idx start string index of ASN.1 object
5979 * @param {Number} nth for child
5980 * @return {Number} string index of nth child.
5981 * @since 1.1
5982 */
5983function _asnhex_getNthChildIndex_AtObj(h, idx, nth) {
5984 var a = _asnhex_getPosArrayOfChildren_AtObj(h, idx);
5985 return a[nth];
5986}
5987
5988// ========== decendant methods ==============================
5989
5990/**
5991 * get string index of nth child object of ASN.1 object refered by h, idx
5992 * @name getDecendantIndexByNthList
5993 * @memberOf ASN1HEX
5994 * @function
5995 * @param {String} h hexadecimal string of ASN.1 DER encoded data
5996 * @param {Number} currentIndex start string index of ASN.1 object
5997 * @param {Array of Number} nthList array list of nth
5998 * @return {Number} string index refered by nthList
5999 * @since 1.1
6000 */
6001function _asnhex_getDecendantIndexByNthList(h, currentIndex, nthList) {
6002 if (nthList.length == 0) {
6003 return currentIndex;
6004 }
6005 var firstNth = nthList.shift();
6006 var a = _asnhex_getPosArrayOfChildren_AtObj(h, currentIndex);
6007 return _asnhex_getDecendantIndexByNthList(h, a[firstNth], nthList);
6008}
6009
6010/**
6011 * get hexadecimal string of ASN.1 TLV refered by current index and nth index list.
6012 * @name getDecendantHexTLVByNthList
6013 * @memberOf ASN1HEX
6014 * @function
6015 * @param {String} h hexadecimal string of ASN.1 DER encoded data
6016 * @param {Number} currentIndex start string index of ASN.1 object
6017 * @param {Array of Number} nthList array list of nth
6018 * @return {Number} hexadecimal string of ASN.1 TLV refered by nthList
6019 * @since 1.1
6020 */
6021function _asnhex_getDecendantHexTLVByNthList(h, currentIndex, nthList) {
6022 var idx = _asnhex_getDecendantIndexByNthList(h, currentIndex, nthList);
6023 return _asnhex_getHexOfTLV_AtObj(h, idx);
6024}
6025
6026/**
6027 * get hexadecimal string of ASN.1 V refered by current index and nth index list.
6028 * @name getDecendantHexVByNthList
6029 * @memberOf ASN1HEX
6030 * @function
6031 * @param {String} h hexadecimal string of ASN.1 DER encoded data
6032 * @param {Number} currentIndex start string index of ASN.1 object
6033 * @param {Array of Number} nthList array list of nth
6034 * @return {Number} hexadecimal string of ASN.1 V refered by nthList
6035 * @since 1.1
6036 */
6037function _asnhex_getDecendantHexVByNthList(h, currentIndex, nthList) {
6038 var idx = _asnhex_getDecendantIndexByNthList(h, currentIndex, nthList);
6039 return _asnhex_getHexOfV_AtObj(h, idx);
6040}
6041
6042// ========== class definition ==============================
6043
6044/**
6045 * ASN.1 DER encoded hexadecimal string utility class
6046 * @class ASN.1 DER encoded hexadecimal string utility class
6047 * @author Kenji Urushima
6048 * @version 1.1 (09 May 2012)
6049 * @see <a href="http://kjur.github.com/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a>
6050 * @since 1.1
6051 */
6052function ASN1HEX() {
6053 return ASN1HEX;
6054}
6055
6056ASN1HEX.getByteLengthOfL_AtObj = _asnhex_getByteLengthOfL_AtObj;
6057ASN1HEX.getHexOfL_AtObj = _asnhex_getHexOfL_AtObj;
6058ASN1HEX.getIntOfL_AtObj = _asnhex_getIntOfL_AtObj;
6059ASN1HEX.getStartPosOfV_AtObj = _asnhex_getStartPosOfV_AtObj;
6060ASN1HEX.getHexOfV_AtObj = _asnhex_getHexOfV_AtObj;
6061ASN1HEX.getHexOfTLV_AtObj = _asnhex_getHexOfTLV_AtObj;
6062ASN1HEX.getPosOfNextSibling_AtObj = _asnhex_getPosOfNextSibling_AtObj;
6063ASN1HEX.getPosArrayOfChildren_AtObj = _asnhex_getPosArrayOfChildren_AtObj;
6064ASN1HEX.getNthChildIndex_AtObj = _asnhex_getNthChildIndex_AtObj;
6065ASN1HEX.getDecendantIndexByNthList = _asnhex_getDecendantIndexByNthList;
6066ASN1HEX.getDecendantHexVByNthList = _asnhex_getDecendantHexVByNthList;
6067ASN1HEX.getDecendantHexTLVByNthList = _asnhex_getDecendantHexTLVByNthList;
6068// Copyright (c) 2005 Tom Wu
6069// All Rights Reserved.
6070// See "LICENSE" for details.
6071
6072// Basic JavaScript BN library - subset useful for RSA encryption.
6073
6074// Bits per digit
6075var dbits;
6076
6077// JavaScript engine analysis
6078var canary = 0xdeadbeefcafe;
6079var j_lm = ((canary&0xffffff)==0xefcafe);
6080
6081// (public) Constructor
6082function BigInteger(a,b,c) {
6083 if(a != null)
6084 if("number" == typeof a) this.fromNumber(a,b,c);
6085 else if(b == null && "string" != typeof a) this.fromString(a,256);
6086 else this.fromString(a,b);
6087}
6088
6089// return new, unset BigInteger
6090function nbi() { return new BigInteger(null); }
6091
6092// am: Compute w_j += (x*this_i), propagate carries,
6093// c is initial carry, returns final carry.
6094// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
6095// We need to select the fastest one that works in this environment.
6096
6097// am1: use a single mult and divide to get the high bits,
6098// max digit bits should be 26 because
6099// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
6100function am1(i,x,w,j,c,n) {
6101 while(--n >= 0) {
6102 var v = x*this[i++]+w[j]+c;
6103 c = Math.floor(v/0x4000000);
6104 w[j++] = v&0x3ffffff;
6105 }
6106 return c;
6107}
6108// am2 avoids a big mult-and-extract completely.
6109// Max digit bits should be <= 30 because we do bitwise ops
6110// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
6111function am2(i,x,w,j,c,n) {
6112 var xl = x&0x7fff, xh = x>>15;
6113 while(--n >= 0) {
6114 var l = this[i]&0x7fff;
6115 var h = this[i++]>>15;
6116 var m = xh*l+h*xl;
6117 l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff);
6118 c = (l>>>30)+(m>>>15)+xh*h+(c>>>30);
6119 w[j++] = l&0x3fffffff;
6120 }
6121 return c;
6122}
6123// Alternately, set max digit bits to 28 since some
6124// browsers slow down when dealing with 32-bit numbers.
6125function am3(i,x,w,j,c,n) {
6126 var xl = x&0x3fff, xh = x>>14;
6127 while(--n >= 0) {
6128 var l = this[i]&0x3fff;
6129 var h = this[i++]>>14;
6130 var m = xh*l+h*xl;
6131 l = xl*l+((m&0x3fff)<<14)+w[j]+c;
6132 c = (l>>28)+(m>>14)+xh*h;
6133 w[j++] = l&0xfffffff;
6134 }
6135 return c;
6136}
6137if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
6138 BigInteger.prototype.am = am2;
6139 dbits = 30;
6140}
6141else if(j_lm && (navigator.appName != "Netscape")) {
6142 BigInteger.prototype.am = am1;
6143 dbits = 26;
6144}
6145else { // Mozilla/Netscape seems to prefer am3
6146 BigInteger.prototype.am = am3;
6147 dbits = 28;
6148}
6149
6150BigInteger.prototype.DB = dbits;
6151BigInteger.prototype.DM = ((1<<dbits)-1);
6152BigInteger.prototype.DV = (1<<dbits);
6153
6154var BI_FP = 52;
6155BigInteger.prototype.FV = Math.pow(2,BI_FP);
6156BigInteger.prototype.F1 = BI_FP-dbits;
6157BigInteger.prototype.F2 = 2*dbits-BI_FP;
6158
6159// Digit conversions
6160var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
6161var BI_RC = new Array();
6162var rr,vv;
6163rr = "0".charCodeAt(0);
6164for(vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
6165rr = "a".charCodeAt(0);
6166for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
6167rr = "A".charCodeAt(0);
6168for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
6169
6170function int2char(n) { return BI_RM.charAt(n); }
6171function intAt(s,i) {
6172 var c = BI_RC[s.charCodeAt(i)];
6173 return (c==null)?-1:c;
6174}
6175
6176// (protected) copy this to r
6177function bnpCopyTo(r) {
6178 for(var i = this.t-1; i >= 0; --i) r[i] = this[i];
6179 r.t = this.t;
6180 r.s = this.s;
6181}
6182
6183// (protected) set from integer value x, -DV <= x < DV
6184function bnpFromInt(x) {
6185 this.t = 1;
6186 this.s = (x<0)?-1:0;
6187 if(x > 0) this[0] = x;
6188 else if(x < -1) this[0] = x+DV;
6189 else this.t = 0;
6190}
6191
6192// return bigint initialized to value
6193function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
6194
6195// (protected) set from string and radix
6196function bnpFromString(s,b) {
6197 var k;
6198 if(b == 16) k = 4;
6199 else if(b == 8) k = 3;
6200 else if(b == 256) k = 8; // byte array
6201 else if(b == 2) k = 1;
6202 else if(b == 32) k = 5;
6203 else if(b == 4) k = 2;
6204 else { this.fromRadix(s,b); return; }
6205 this.t = 0;
6206 this.s = 0;
6207 var i = s.length, mi = false, sh = 0;
6208 while(--i >= 0) {
6209 var x = (k==8)?s[i]&0xff:intAt(s,i);
6210 if(x < 0) {
6211 if(s.charAt(i) == "-") mi = true;
6212 continue;
6213 }
6214 mi = false;
6215 if(sh == 0)
6216 this[this.t++] = x;
6217 else if(sh+k > this.DB) {
6218 this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<<sh;
6219 this[this.t++] = (x>>(this.DB-sh));
6220 }
6221 else
6222 this[this.t-1] |= x<<sh;
6223 sh += k;
6224 if(sh >= this.DB) sh -= this.DB;
6225 }
6226 if(k == 8 && (s[0]&0x80) != 0) {
6227 this.s = -1;
6228 if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh;
6229 }
6230 this.clamp();
6231 if(mi) BigInteger.ZERO.subTo(this,this);
6232}
6233
6234// (protected) clamp off excess high words
6235function bnpClamp() {
6236 var c = this.s&this.DM;
6237 while(this.t > 0 && this[this.t-1] == c) --this.t;
6238}
6239
6240// (public) return string representation in given radix
6241function bnToString(b) {
6242 if(this.s < 0) return "-"+this.negate().toString(b);
6243 var k;
6244 if(b == 16) k = 4;
6245 else if(b == 8) k = 3;
6246 else if(b == 2) k = 1;
6247 else if(b == 32) k = 5;
6248 else if(b == 4) k = 2;
6249 else return this.toRadix(b);
6250 var km = (1<<k)-1, d, m = false, r = "", i = this.t;
6251 var p = this.DB-(i*this.DB)%k;
6252 if(i-- > 0) {
6253 if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); }
6254 while(i >= 0) {
6255 if(p < k) {
6256 d = (this[i]&((1<<p)-1))<<(k-p);
6257 d |= this[--i]>>(p+=this.DB-k);
6258 }
6259 else {
6260 d = (this[i]>>(p-=k))&km;
6261 if(p <= 0) { p += this.DB; --i; }
6262 }
6263 if(d > 0) m = true;
6264 if(m) r += int2char(d);
6265 }
6266 }
6267 return m?r:"0";
6268}
6269
6270// (public) -this
6271function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }
6272
6273// (public) |this|
6274function bnAbs() { return (this.s<0)?this.negate():this; }
6275
6276// (public) return + if this > a, - if this < a, 0 if equal
6277function bnCompareTo(a) {
6278 var r = this.s-a.s;
6279 if(r != 0) return r;
6280 var i = this.t;
6281 r = i-a.t;
6282 if(r != 0) return r;
6283 while(--i >= 0) if((r=this[i]-a[i]) != 0) return r;
6284 return 0;
6285}
6286
6287// returns bit length of the integer x
6288function nbits(x) {
6289 var r = 1, t;
6290 if((t=x>>>16) != 0) { x = t; r += 16; }
6291 if((t=x>>8) != 0) { x = t; r += 8; }
6292 if((t=x>>4) != 0) { x = t; r += 4; }
6293 if((t=x>>2) != 0) { x = t; r += 2; }
6294 if((t=x>>1) != 0) { x = t; r += 1; }
6295 return r;
6296}
6297
6298// (public) return the number of bits in "this"
6299function bnBitLength() {
6300 if(this.t <= 0) return 0;
6301 return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM));
6302}
6303
6304// (protected) r = this << n*DB
6305function bnpDLShiftTo(n,r) {
6306 var i;
6307 for(i = this.t-1; i >= 0; --i) r[i+n] = this[i];
6308 for(i = n-1; i >= 0; --i) r[i] = 0;
6309 r.t = this.t+n;
6310 r.s = this.s;
6311}
6312
6313// (protected) r = this >> n*DB
6314function bnpDRShiftTo(n,r) {
6315 for(var i = n; i < this.t; ++i) r[i-n] = this[i];
6316 r.t = Math.max(this.t-n,0);
6317 r.s = this.s;
6318}
6319
6320// (protected) r = this << n
6321function bnpLShiftTo(n,r) {
6322 var bs = n%this.DB;
6323 var cbs = this.DB-bs;
6324 var bm = (1<<cbs)-1;
6325 var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i;
6326 for(i = this.t-1; i >= 0; --i) {
6327 r[i+ds+1] = (this[i]>>cbs)|c;
6328 c = (this[i]&bm)<<bs;
6329 }
6330 for(i = ds-1; i >= 0; --i) r[i] = 0;
6331 r[ds] = c;
6332 r.t = this.t+ds+1;
6333 r.s = this.s;
6334 r.clamp();
6335}
6336
6337// (protected) r = this >> n
6338function bnpRShiftTo(n,r) {
6339 r.s = this.s;
6340 var ds = Math.floor(n/this.DB);
6341 if(ds >= this.t) { r.t = 0; return; }
6342 var bs = n%this.DB;
6343 var cbs = this.DB-bs;
6344 var bm = (1<<bs)-1;
6345 r[0] = this[ds]>>bs;
6346 for(var i = ds+1; i < this.t; ++i) {
6347 r[i-ds-1] |= (this[i]&bm)<<cbs;
6348 r[i-ds] = this[i]>>bs;
6349 }
6350 if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs;
6351 r.t = this.t-ds;
6352 r.clamp();
6353}
6354
6355// (protected) r = this - a
6356function bnpSubTo(a,r) {
6357 var i = 0, c = 0, m = Math.min(a.t,this.t);
6358 while(i < m) {
6359 c += this[i]-a[i];
6360 r[i++] = c&this.DM;
6361 c >>= this.DB;
6362 }
6363 if(a.t < this.t) {
6364 c -= a.s;
6365 while(i < this.t) {
6366 c += this[i];
6367 r[i++] = c&this.DM;
6368 c >>= this.DB;
6369 }
6370 c += this.s;
6371 }
6372 else {
6373 c += this.s;
6374 while(i < a.t) {
6375 c -= a[i];
6376 r[i++] = c&this.DM;
6377 c >>= this.DB;
6378 }
6379 c -= a.s;
6380 }
6381 r.s = (c<0)?-1:0;
6382 if(c < -1) r[i++] = this.DV+c;
6383 else if(c > 0) r[i++] = c;
6384 r.t = i;
6385 r.clamp();
6386}
6387
6388// (protected) r = this * a, r != this,a (HAC 14.12)
6389// "this" should be the larger one if appropriate.
6390function bnpMultiplyTo(a,r) {
6391 var x = this.abs(), y = a.abs();
6392 var i = x.t;
6393 r.t = i+y.t;
6394 while(--i >= 0) r[i] = 0;
6395 for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t);
6396 r.s = 0;
6397 r.clamp();
6398 if(this.s != a.s) BigInteger.ZERO.subTo(r,r);
6399}
6400
6401// (protected) r = this^2, r != this (HAC 14.16)
6402function bnpSquareTo(r) {
6403 var x = this.abs();
6404 var i = r.t = 2*x.t;
6405 while(--i >= 0) r[i] = 0;
6406 for(i = 0; i < x.t-1; ++i) {
6407 var c = x.am(i,x[i],r,2*i,0,1);
6408 if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) {
6409 r[i+x.t] -= x.DV;
6410 r[i+x.t+1] = 1;
6411 }
6412 }
6413 if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1);
6414 r.s = 0;
6415 r.clamp();
6416}
6417
6418// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
6419// r != q, this != m. q or r may be null.
6420function bnpDivRemTo(m,q,r) {
6421 var pm = m.abs();
6422 if(pm.t <= 0) return;
6423 var pt = this.abs();
6424 if(pt.t < pm.t) {
6425 if(q != null) q.fromInt(0);
6426 if(r != null) this.copyTo(r);
6427 return;
6428 }
6429 if(r == null) r = nbi();
6430 var y = nbi(), ts = this.s, ms = m.s;
6431 var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus
6432 if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); }
6433 else { pm.copyTo(y); pt.copyTo(r); }
6434 var ys = y.t;
6435 var y0 = y[ys-1];
6436 if(y0 == 0) return;
6437 var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0);
6438 var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
6439 var i = r.t, j = i-ys, t = (q==null)?nbi():q;
6440 y.dlShiftTo(j,t);
6441 if(r.compareTo(t) >= 0) {
6442 r[r.t++] = 1;
6443 r.subTo(t,r);
6444 }
6445 BigInteger.ONE.dlShiftTo(ys,t);
6446 t.subTo(y,y); // "negative" y so we can replace sub with am later
6447 while(y.t < ys) y[y.t++] = 0;
6448 while(--j >= 0) {
6449 // Estimate quotient digit
6450 var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);
6451 if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out
6452 y.dlShiftTo(j,t);
6453 r.subTo(t,r);
6454 while(r[i] < --qd) r.subTo(t,r);
6455 }
6456 }
6457 if(q != null) {
6458 r.drShiftTo(ys,q);
6459 if(ts != ms) BigInteger.ZERO.subTo(q,q);
6460 }
6461 r.t = ys;
6462 r.clamp();
6463 if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder
6464 if(ts < 0) BigInteger.ZERO.subTo(r,r);
6465}
6466
6467// (public) this mod a
6468function bnMod(a) {
6469 var r = nbi();
6470 this.abs().divRemTo(a,null,r);
6471 if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r);
6472 return r;
6473}
6474
6475// Modular reduction using "classic" algorithm
6476function Classic(m) { this.m = m; }
6477function cConvert(x) {
6478 if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
6479 else return x;
6480}
6481function cRevert(x) { return x; }
6482function cReduce(x) { x.divRemTo(this.m,null,x); }
6483function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
6484function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
6485
6486Classic.prototype.convert = cConvert;
6487Classic.prototype.revert = cRevert;
6488Classic.prototype.reduce = cReduce;
6489Classic.prototype.mulTo = cMulTo;
6490Classic.prototype.sqrTo = cSqrTo;
6491
6492// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
6493// justification:
6494// xy == 1 (mod m)
6495// xy = 1+km
6496// xy(2-xy) = (1+km)(1-km)
6497// x[y(2-xy)] = 1-k^2m^2
6498// x[y(2-xy)] == 1 (mod m^2)
6499// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
6500// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
6501// JS multiply "overflows" differently from C/C++, so care is needed here.
6502function bnpInvDigit() {
6503 if(this.t < 1) return 0;
6504 var x = this[0];
6505 if((x&1) == 0) return 0;
6506 var y = x&3; // y == 1/x mod 2^2
6507 y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4
6508 y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8
6509 y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16
6510 // last step - calculate inverse mod DV directly;
6511 // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
6512 y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits
6513 // we really want the negative inverse, and -DV < y < DV
6514 return (y>0)?this.DV-y:-y;
6515}
6516
6517// Montgomery reduction
6518function Montgomery(m) {
6519 this.m = m;
6520 this.mp = m.invDigit();
6521 this.mpl = this.mp&0x7fff;
6522 this.mph = this.mp>>15;
6523 this.um = (1<<(m.DB-15))-1;
6524 this.mt2 = 2*m.t;
6525}
6526
6527// xR mod m
6528function montConvert(x) {
6529 var r = nbi();
6530 x.abs().dlShiftTo(this.m.t,r);
6531 r.divRemTo(this.m,null,r);
6532 if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r);
6533 return r;
6534}
6535
6536// x/R mod m
6537function montRevert(x) {
6538 var r = nbi();
6539 x.copyTo(r);
6540 this.reduce(r);
6541 return r;
6542}
6543
6544// x = x/R mod m (HAC 14.32)
6545function montReduce(x) {
6546 while(x.t <= this.mt2) // pad x so am has enough room later
6547 x[x.t++] = 0;
6548 for(var i = 0; i < this.m.t; ++i) {
6549 // faster way of calculating u0 = x[i]*mp mod DV
6550 var j = x[i]&0x7fff;
6551 var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM;
6552 // use am to combine the multiply-shift-add into one call
6553 j = i+this.m.t;
6554 x[j] += this.m.am(0,u0,x,i,0,this.m.t);
6555 // propagate carry
6556 while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; }
6557 }
6558 x.clamp();
6559 x.drShiftTo(this.m.t,x);
6560 if(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
6561}
6562
6563// r = "x^2/R mod m"; x != r
6564function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
6565
6566// r = "xy/R mod m"; x,y != r
6567function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
6568
6569Montgomery.prototype.convert = montConvert;
6570Montgomery.prototype.revert = montRevert;
6571Montgomery.prototype.reduce = montReduce;
6572Montgomery.prototype.mulTo = montMulTo;
6573Montgomery.prototype.sqrTo = montSqrTo;
6574
6575// (protected) true iff this is even
6576function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; }
6577
6578// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
6579function bnpExp(e,z) {
6580 if(e > 0xffffffff || e < 1) return BigInteger.ONE;
6581 var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1;
6582 g.copyTo(r);
6583 while(--i >= 0) {
6584 z.sqrTo(r,r2);
6585 if((e&(1<<i)) > 0) z.mulTo(r2,g,r);
6586 else { var t = r; r = r2; r2 = t; }
6587 }
6588 return z.revert(r);
6589}
6590
6591// (public) this^e % m, 0 <= e < 2^32
6592function bnModPowInt(e,m) {
6593 var z;
6594 if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
6595 return this.exp(e,z);
6596}
6597
6598// protected
6599BigInteger.prototype.copyTo = bnpCopyTo;
6600BigInteger.prototype.fromInt = bnpFromInt;
6601BigInteger.prototype.fromString = bnpFromString;
6602BigInteger.prototype.clamp = bnpClamp;
6603BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
6604BigInteger.prototype.drShiftTo = bnpDRShiftTo;
6605BigInteger.prototype.lShiftTo = bnpLShiftTo;
6606BigInteger.prototype.rShiftTo = bnpRShiftTo;
6607BigInteger.prototype.subTo = bnpSubTo;
6608BigInteger.prototype.multiplyTo = bnpMultiplyTo;
6609BigInteger.prototype.squareTo = bnpSquareTo;
6610BigInteger.prototype.divRemTo = bnpDivRemTo;
6611BigInteger.prototype.invDigit = bnpInvDigit;
6612BigInteger.prototype.isEven = bnpIsEven;
6613BigInteger.prototype.exp = bnpExp;
6614
6615// public
6616BigInteger.prototype.toString = bnToString;
6617BigInteger.prototype.negate = bnNegate;
6618BigInteger.prototype.abs = bnAbs;
6619BigInteger.prototype.compareTo = bnCompareTo;
6620BigInteger.prototype.bitLength = bnBitLength;
6621BigInteger.prototype.mod = bnMod;
6622BigInteger.prototype.modPowInt = bnModPowInt;
6623
6624// "constants"
6625BigInteger.ZERO = nbv(0);
6626BigInteger.ONE = nbv(1);
6627// Copyright (c) 2005-2009 Tom Wu
6628// All Rights Reserved.
6629// See "LICENSE" for details.
6630
6631// Extended JavaScript BN functions, required for RSA private ops.
6632
6633// Version 1.1: new BigInteger("0", 10) returns "proper" zero
6634
6635// (public)
6636function bnClone() { var r = nbi(); this.copyTo(r); return r; }
6637
6638// (public) return value as integer
6639function bnIntValue() {
6640 if(this.s < 0) {
6641 if(this.t == 1) return this[0]-this.DV;
6642 else if(this.t == 0) return -1;
6643 }
6644 else if(this.t == 1) return this[0];
6645 else if(this.t == 0) return 0;
6646 // assumes 16 < DB < 32
6647 return ((this[1]&((1<<(32-this.DB))-1))<<this.DB)|this[0];
6648}
6649
6650// (public) return value as byte
6651function bnByteValue() { return (this.t==0)?this.s:(this[0]<<24)>>24; }
6652
6653// (public) return value as short (assumes DB>=16)
6654function bnShortValue() { return (this.t==0)?this.s:(this[0]<<16)>>16; }
6655
6656// (protected) return x s.t. r^x < DV
6657function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); }
6658
6659// (public) 0 if this == 0, 1 if this > 0
6660function bnSigNum() {
6661 if(this.s < 0) return -1;
6662 else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
6663 else return 1;
6664}
6665
6666// (protected) convert to radix string
6667function bnpToRadix(b) {
6668 if(b == null) b = 10;
6669 if(this.signum() == 0 || b < 2 || b > 36) return "0";
6670 var cs = this.chunkSize(b);
6671 var a = Math.pow(b,cs);
6672 var d = nbv(a), y = nbi(), z = nbi(), r = "";
6673 this.divRemTo(d,y,z);
6674 while(y.signum() > 0) {
6675 r = (a+z.intValue()).toString(b).substr(1) + r;
6676 y.divRemTo(d,y,z);
6677 }
6678 return z.intValue().toString(b) + r;
6679}
6680
6681// (protected) convert from radix string
6682function bnpFromRadix(s,b) {
6683 this.fromInt(0);
6684 if(b == null) b = 10;
6685 var cs = this.chunkSize(b);
6686 var d = Math.pow(b,cs), mi = false, j = 0, w = 0;
6687 for(var i = 0; i < s.length; ++i) {
6688 var x = intAt(s,i);
6689 if(x < 0) {
6690 if(s.charAt(i) == "-" && this.signum() == 0) mi = true;
6691 continue;
6692 }
6693 w = b*w+x;
6694 if(++j >= cs) {
6695 this.dMultiply(d);
6696 this.dAddOffset(w,0);
6697 j = 0;
6698 w = 0;
6699 }
6700 }
6701 if(j > 0) {
6702 this.dMultiply(Math.pow(b,j));
6703 this.dAddOffset(w,0);
6704 }
6705 if(mi) BigInteger.ZERO.subTo(this,this);
6706}
6707
6708// (protected) alternate constructor
6709function bnpFromNumber(a,b,c) {
6710 if("number" == typeof b) {
6711 // new BigInteger(int,int,RNG)
6712 if(a < 2) this.fromInt(1);
6713 else {
6714 this.fromNumber(a,c);
6715 if(!this.testBit(a-1)) // force MSB set
6716 this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this);
6717 if(this.isEven()) this.dAddOffset(1,0); // force odd
6718 while(!this.isProbablePrime(b)) {
6719 this.dAddOffset(2,0);
6720 if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this);
6721 }
6722 }
6723 }
6724 else {
6725 // new BigInteger(int,RNG)
6726 var x = new Array(), t = a&7;
6727 x.length = (a>>3)+1;
6728 b.nextBytes(x);
6729 if(t > 0) x[0] &= ((1<<t)-1); else x[0] = 0;
6730 this.fromString(x,256);
6731 }
6732}
6733
6734// (public) convert to bigendian byte array
6735function bnToByteArray() {
6736 var i = this.t, r = new Array();
6737 r[0] = this.s;
6738 var p = this.DB-(i*this.DB)%8, d, k = 0;
6739 if(i-- > 0) {
6740 if(p < this.DB && (d = this[i]>>p) != (this.s&this.DM)>>p)
6741 r[k++] = d|(this.s<<(this.DB-p));
6742 while(i >= 0) {
6743 if(p < 8) {
6744 d = (this[i]&((1<<p)-1))<<(8-p);
6745 d |= this[--i]>>(p+=this.DB-8);
6746 }
6747 else {
6748 d = (this[i]>>(p-=8))&0xff;
6749 if(p <= 0) { p += this.DB; --i; }
6750 }
6751 if((d&0x80) != 0) d |= -256;
6752 if(k == 0 && (this.s&0x80) != (d&0x80)) ++k;
6753 if(k > 0 || d != this.s) r[k++] = d;
6754 }
6755 }
6756 return r;
6757}
6758
6759function bnEquals(a) { return(this.compareTo(a)==0); }
6760function bnMin(a) { return(this.compareTo(a)<0)?this:a; }
6761function bnMax(a) { return(this.compareTo(a)>0)?this:a; }
6762
6763// (protected) r = this op a (bitwise)
6764function bnpBitwiseTo(a,op,r) {
6765 var i, f, m = Math.min(a.t,this.t);
6766 for(i = 0; i < m; ++i) r[i] = op(this[i],a[i]);
6767 if(a.t < this.t) {
6768 f = a.s&this.DM;
6769 for(i = m; i < this.t; ++i) r[i] = op(this[i],f);
6770 r.t = this.t;
6771 }
6772 else {
6773 f = this.s&this.DM;
6774 for(i = m; i < a.t; ++i) r[i] = op(f,a[i]);
6775 r.t = a.t;
6776 }
6777 r.s = op(this.s,a.s);
6778 r.clamp();
6779}
6780
6781// (public) this & a
6782function op_and(x,y) { return x&y; }
6783function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; }
6784
6785// (public) this | a
6786function op_or(x,y) { return x|y; }
6787function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; }
6788
6789// (public) this ^ a
6790function op_xor(x,y) { return x^y; }
6791function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; }
6792
6793// (public) this & ~a
6794function op_andnot(x,y) { return x&~y; }
6795function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; }
6796
6797// (public) ~this
6798function bnNot() {
6799 var r = nbi();
6800 for(var i = 0; i < this.t; ++i) r[i] = this.DM&~this[i];
6801 r.t = this.t;
6802 r.s = ~this.s;
6803 return r;
6804}
6805
6806// (public) this << n
6807function bnShiftLeft(n) {
6808 var r = nbi();
6809 if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r);
6810 return r;
6811}
6812
6813// (public) this >> n
6814function bnShiftRight(n) {
6815 var r = nbi();
6816 if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r);
6817 return r;
6818}
6819
6820// return index of lowest 1-bit in x, x < 2^31
6821function lbit(x) {
6822 if(x == 0) return -1;
6823 var r = 0;
6824 if((x&0xffff) == 0) { x >>= 16; r += 16; }
6825 if((x&0xff) == 0) { x >>= 8; r += 8; }
6826 if((x&0xf) == 0) { x >>= 4; r += 4; }
6827 if((x&3) == 0) { x >>= 2; r += 2; }
6828 if((x&1) == 0) ++r;
6829 return r;
6830}
6831
6832// (public) returns index of lowest 1-bit (or -1 if none)
6833function bnGetLowestSetBit() {
6834 for(var i = 0; i < this.t; ++i)
6835 if(this[i] != 0) return i*this.DB+lbit(this[i]);
6836 if(this.s < 0) return this.t*this.DB;
6837 return -1;
6838}
6839
6840// return number of 1 bits in x
6841function cbit(x) {
6842 var r = 0;
6843 while(x != 0) { x &= x-1; ++r; }
6844 return r;
6845}
6846
6847// (public) return number of set bits
6848function bnBitCount() {
6849 var r = 0, x = this.s&this.DM;
6850 for(var i = 0; i < this.t; ++i) r += cbit(this[i]^x);
6851 return r;
6852}
6853
6854// (public) true iff nth bit is set
6855function bnTestBit(n) {
6856 var j = Math.floor(n/this.DB);
6857 if(j >= this.t) return(this.s!=0);
6858 return((this[j]&(1<<(n%this.DB)))!=0);
6859}
6860
6861// (protected) this op (1<<n)
6862function bnpChangeBit(n,op) {
6863 var r = BigInteger.ONE.shiftLeft(n);
6864 this.bitwiseTo(r,op,r);
6865 return r;
6866}
6867
6868// (public) this | (1<<n)
6869function bnSetBit(n) { return this.changeBit(n,op_or); }
6870
6871// (public) this & ~(1<<n)
6872function bnClearBit(n) { return this.changeBit(n,op_andnot); }
6873
6874// (public) this ^ (1<<n)
6875function bnFlipBit(n) { return this.changeBit(n,op_xor); }
6876
6877// (protected) r = this + a
6878function bnpAddTo(a,r) {
6879 var i = 0, c = 0, m = Math.min(a.t,this.t);
6880 while(i < m) {
6881 c += this[i]+a[i];
6882 r[i++] = c&this.DM;
6883 c >>= this.DB;
6884 }
6885 if(a.t < this.t) {
6886 c += a.s;
6887 while(i < this.t) {
6888 c += this[i];
6889 r[i++] = c&this.DM;
6890 c >>= this.DB;
6891 }
6892 c += this.s;
6893 }
6894 else {
6895 c += this.s;
6896 while(i < a.t) {
6897 c += a[i];
6898 r[i++] = c&this.DM;
6899 c >>= this.DB;
6900 }
6901 c += a.s;
6902 }
6903 r.s = (c<0)?-1:0;
6904 if(c > 0) r[i++] = c;
6905 else if(c < -1) r[i++] = this.DV+c;
6906 r.t = i;
6907 r.clamp();
6908}
6909
6910// (public) this + a
6911function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; }
6912
6913// (public) this - a
6914function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; }
6915
6916// (public) this * a
6917function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; }
6918
6919// (public) this / a
6920function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; }
6921
6922// (public) this % a
6923function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; }
6924
6925// (public) [this/a,this%a]
6926function bnDivideAndRemainder(a) {
6927 var q = nbi(), r = nbi();
6928 this.divRemTo(a,q,r);
6929 return new Array(q,r);
6930}
6931
6932// (protected) this *= n, this >= 0, 1 < n < DV
6933function bnpDMultiply(n) {
6934 this[this.t] = this.am(0,n-1,this,0,0,this.t);
6935 ++this.t;
6936 this.clamp();
6937}
6938
6939// (protected) this += n << w words, this >= 0
6940function bnpDAddOffset(n,w) {
6941 if(n == 0) return;
6942 while(this.t <= w) this[this.t++] = 0;
6943 this[w] += n;
6944 while(this[w] >= this.DV) {
6945 this[w] -= this.DV;
6946 if(++w >= this.t) this[this.t++] = 0;
6947 ++this[w];
6948 }
6949}
6950
6951// A "null" reducer
6952function NullExp() {}
6953function nNop(x) { return x; }
6954function nMulTo(x,y,r) { x.multiplyTo(y,r); }
6955function nSqrTo(x,r) { x.squareTo(r); }
6956
6957NullExp.prototype.convert = nNop;
6958NullExp.prototype.revert = nNop;
6959NullExp.prototype.mulTo = nMulTo;
6960NullExp.prototype.sqrTo = nSqrTo;
6961
6962// (public) this^e
6963function bnPow(e) { return this.exp(e,new NullExp()); }
6964
6965// (protected) r = lower n words of "this * a", a.t <= n
6966// "this" should be the larger one if appropriate.
6967function bnpMultiplyLowerTo(a,n,r) {
6968 var i = Math.min(this.t+a.t,n);
6969 r.s = 0; // assumes a,this >= 0
6970 r.t = i;
6971 while(i > 0) r[--i] = 0;
6972 var j;
6973 for(j = r.t-this.t; i < j; ++i) r[i+this.t] = this.am(0,a[i],r,i,0,this.t);
6974 for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a[i],r,i,0,n-i);
6975 r.clamp();
6976}
6977
6978// (protected) r = "this * a" without lower n words, n > 0
6979// "this" should be the larger one if appropriate.
6980function bnpMultiplyUpperTo(a,n,r) {
6981 --n;
6982 var i = r.t = this.t+a.t-n;
6983 r.s = 0; // assumes a,this >= 0
6984 while(--i >= 0) r[i] = 0;
6985 for(i = Math.max(n-this.t,0); i < a.t; ++i)
6986 r[this.t+i-n] = this.am(n-i,a[i],r,0,0,this.t+i-n);
6987 r.clamp();
6988 r.drShiftTo(1,r);
6989}
6990
6991// Barrett modular reduction
6992function Barrett(m) {
6993 // setup Barrett
6994 this.r2 = nbi();
6995 this.q3 = nbi();
6996 BigInteger.ONE.dlShiftTo(2*m.t,this.r2);
6997 this.mu = this.r2.divide(m);
6998 this.m = m;
6999}
7000
7001function barrettConvert(x) {
7002 if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m);
7003 else if(x.compareTo(this.m) < 0) return x;
7004 else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; }
7005}
7006
7007function barrettRevert(x) { return x; }
7008
7009// x = x mod m (HAC 14.42)
7010function barrettReduce(x) {
7011 x.drShiftTo(this.m.t-1,this.r2);
7012 if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); }
7013 this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3);
7014 this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);
7015 while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1);
7016 x.subTo(this.r2,x);
7017 while(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
7018}
7019
7020// r = x^2 mod m; x != r
7021function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
7022
7023// r = x*y mod m; x,y != r
7024function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
7025
7026Barrett.prototype.convert = barrettConvert;
7027Barrett.prototype.revert = barrettRevert;
7028Barrett.prototype.reduce = barrettReduce;
7029Barrett.prototype.mulTo = barrettMulTo;
7030Barrett.prototype.sqrTo = barrettSqrTo;
7031
7032// (public) this^e % m (HAC 14.85)
7033function bnModPow(e,m) {
7034 var i = e.bitLength(), k, r = nbv(1), z;
7035 if(i <= 0) return r;
7036 else if(i < 18) k = 1;
7037 else if(i < 48) k = 3;
7038 else if(i < 144) k = 4;
7039 else if(i < 768) k = 5;
7040 else k = 6;
7041 if(i < 8)
7042 z = new Classic(m);
7043 else if(m.isEven())
7044 z = new Barrett(m);
7045 else
7046 z = new Montgomery(m);
7047
7048 // precomputation
7049 var g = new Array(), n = 3, k1 = k-1, km = (1<<k)-1;
7050 g[1] = z.convert(this);
7051 if(k > 1) {
7052 var g2 = nbi();
7053 z.sqrTo(g[1],g2);
7054 while(n <= km) {
7055 g[n] = nbi();
7056 z.mulTo(g2,g[n-2],g[n]);
7057 n += 2;
7058 }
7059 }
7060
7061 var j = e.t-1, w, is1 = true, r2 = nbi(), t;
7062 i = nbits(e[j])-1;
7063 while(j >= 0) {
7064 if(i >= k1) w = (e[j]>>(i-k1))&km;
7065 else {
7066 w = (e[j]&((1<<(i+1))-1))<<(k1-i);
7067 if(j > 0) w |= e[j-1]>>(this.DB+i-k1);
7068 }
7069
7070 n = k;
7071 while((w&1) == 0) { w >>= 1; --n; }
7072 if((i -= n) < 0) { i += this.DB; --j; }
7073 if(is1) { // ret == 1, don't bother squaring or multiplying it
7074 g[w].copyTo(r);
7075 is1 = false;
7076 }
7077 else {
7078 while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; }
7079 if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; }
7080 z.mulTo(r2,g[w],r);
7081 }
7082
7083 while(j >= 0 && (e[j]&(1<<i)) == 0) {
7084 z.sqrTo(r,r2); t = r; r = r2; r2 = t;
7085 if(--i < 0) { i = this.DB-1; --j; }
7086 }
7087 }
7088 return z.revert(r);
7089}
7090
7091// (public) gcd(this,a) (HAC 14.54)
7092function bnGCD(a) {
7093 var x = (this.s<0)?this.negate():this.clone();
7094 var y = (a.s<0)?a.negate():a.clone();
7095 if(x.compareTo(y) < 0) { var t = x; x = y; y = t; }
7096 var i = x.getLowestSetBit(), g = y.getLowestSetBit();
7097 if(g < 0) return x;
7098 if(i < g) g = i;
7099 if(g > 0) {
7100 x.rShiftTo(g,x);
7101 y.rShiftTo(g,y);
7102 }
7103 while(x.signum() > 0) {
7104 if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x);
7105 if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y);
7106 if(x.compareTo(y) >= 0) {
7107 x.subTo(y,x);
7108 x.rShiftTo(1,x);
7109 }
7110 else {
7111 y.subTo(x,y);
7112 y.rShiftTo(1,y);
7113 }
7114 }
7115 if(g > 0) y.lShiftTo(g,y);
7116 return y;
7117}
7118
7119// (protected) this % n, n < 2^26
7120function bnpModInt(n) {
7121 if(n <= 0) return 0;
7122 var d = this.DV%n, r = (this.s<0)?n-1:0;
7123 if(this.t > 0)
7124 if(d == 0) r = this[0]%n;
7125 else for(var i = this.t-1; i >= 0; --i) r = (d*r+this[i])%n;
7126 return r;
7127}
7128
7129// (public) 1/this % m (HAC 14.61)
7130function bnModInverse(m) {
7131 var ac = m.isEven();
7132 if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
7133 var u = m.clone(), v = this.clone();
7134 var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
7135 while(u.signum() != 0) {
7136 while(u.isEven()) {
7137 u.rShiftTo(1,u);
7138 if(ac) {
7139 if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); }
7140 a.rShiftTo(1,a);
7141 }
7142 else if(!b.isEven()) b.subTo(m,b);
7143 b.rShiftTo(1,b);
7144 }
7145 while(v.isEven()) {
7146 v.rShiftTo(1,v);
7147 if(ac) {
7148 if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); }
7149 c.rShiftTo(1,c);
7150 }
7151 else if(!d.isEven()) d.subTo(m,d);
7152 d.rShiftTo(1,d);
7153 }
7154 if(u.compareTo(v) >= 0) {
7155 u.subTo(v,u);
7156 if(ac) a.subTo(c,a);
7157 b.subTo(d,b);
7158 }
7159 else {
7160 v.subTo(u,v);
7161 if(ac) c.subTo(a,c);
7162 d.subTo(b,d);
7163 }
7164 }
7165 if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
7166 if(d.compareTo(m) >= 0) return d.subtract(m);
7167 if(d.signum() < 0) d.addTo(m,d); else return d;
7168 if(d.signum() < 0) return d.add(m); else return d;
7169}
7170
7171var lowprimes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509];
7172var lplim = (1<<26)/lowprimes[lowprimes.length-1];
7173
7174// (public) test primality with certainty >= 1-.5^t
7175function bnIsProbablePrime(t) {
7176 var i, x = this.abs();
7177 if(x.t == 1 && x[0] <= lowprimes[lowprimes.length-1]) {
7178 for(i = 0; i < lowprimes.length; ++i)
7179 if(x[0] == lowprimes[i]) return true;
7180 return false;
7181 }
7182 if(x.isEven()) return false;
7183 i = 1;
7184 while(i < lowprimes.length) {
7185 var m = lowprimes[i], j = i+1;
7186 while(j < lowprimes.length && m < lplim) m *= lowprimes[j++];
7187 m = x.modInt(m);
7188 while(i < j) if(m%lowprimes[i++] == 0) return false;
7189 }
7190 return x.millerRabin(t);
7191}
7192
7193// (protected) true if probably prime (HAC 4.24, Miller-Rabin)
7194function bnpMillerRabin(t) {
7195 var n1 = this.subtract(BigInteger.ONE);
7196 var k = n1.getLowestSetBit();
7197 if(k <= 0) return false;
7198 var r = n1.shiftRight(k);
7199 t = (t+1)>>1;
7200 if(t > lowprimes.length) t = lowprimes.length;
7201 var a = nbi();
7202 for(var i = 0; i < t; ++i) {
7203 a.fromInt(lowprimes[i]);
7204 var y = a.modPow(r,this);
7205 if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {
7206 var j = 1;
7207 while(j++ < k && y.compareTo(n1) != 0) {
7208 y = y.modPowInt(2,this);
7209 if(y.compareTo(BigInteger.ONE) == 0) return false;
7210 }
7211 if(y.compareTo(n1) != 0) return false;
7212 }
7213 }
7214 return true;
7215}
7216
7217// protected
7218BigInteger.prototype.chunkSize = bnpChunkSize;
7219BigInteger.prototype.toRadix = bnpToRadix;
7220BigInteger.prototype.fromRadix = bnpFromRadix;
7221BigInteger.prototype.fromNumber = bnpFromNumber;
7222BigInteger.prototype.bitwiseTo = bnpBitwiseTo;
7223BigInteger.prototype.changeBit = bnpChangeBit;
7224BigInteger.prototype.addTo = bnpAddTo;
7225BigInteger.prototype.dMultiply = bnpDMultiply;
7226BigInteger.prototype.dAddOffset = bnpDAddOffset;
7227BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo;
7228BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo;
7229BigInteger.prototype.modInt = bnpModInt;
7230BigInteger.prototype.millerRabin = bnpMillerRabin;
7231
7232// public
7233BigInteger.prototype.clone = bnClone;
7234BigInteger.prototype.intValue = bnIntValue;
7235BigInteger.prototype.byteValue = bnByteValue;
7236BigInteger.prototype.shortValue = bnShortValue;
7237BigInteger.prototype.signum = bnSigNum;
7238BigInteger.prototype.toByteArray = bnToByteArray;
7239BigInteger.prototype.equals = bnEquals;
7240BigInteger.prototype.min = bnMin;
7241BigInteger.prototype.max = bnMax;
7242BigInteger.prototype.and = bnAnd;
7243BigInteger.prototype.or = bnOr;
7244BigInteger.prototype.xor = bnXor;
7245BigInteger.prototype.andNot = bnAndNot;
7246BigInteger.prototype.not = bnNot;
7247BigInteger.prototype.shiftLeft = bnShiftLeft;
7248BigInteger.prototype.shiftRight = bnShiftRight;
7249BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit;
7250BigInteger.prototype.bitCount = bnBitCount;
7251BigInteger.prototype.testBit = bnTestBit;
7252BigInteger.prototype.setBit = bnSetBit;
7253BigInteger.prototype.clearBit = bnClearBit;
7254BigInteger.prototype.flipBit = bnFlipBit;
7255BigInteger.prototype.add = bnAdd;
7256BigInteger.prototype.subtract = bnSubtract;
7257BigInteger.prototype.multiply = bnMultiply;
7258BigInteger.prototype.divide = bnDivide;
7259BigInteger.prototype.remainder = bnRemainder;
7260BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder;
7261BigInteger.prototype.modPow = bnModPow;
7262BigInteger.prototype.modInverse = bnModInverse;
7263BigInteger.prototype.pow = bnPow;
7264BigInteger.prototype.gcd = bnGCD;
7265BigInteger.prototype.isProbablePrime = bnIsProbablePrime;
7266
7267// BigInteger interfaces not implemented in jsbn:
7268
7269// BigInteger(int signum, byte[] magnitude)
7270// double doubleValue()
7271// float floatValue()
7272// int hashCode()
7273// long longValue()
7274// static BigInteger valueOf(long val)