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