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