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