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