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