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