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