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