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