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