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