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