blob: 0abf8d09755ccde2425f85925b12285454355e03 [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 Thompsonb094d2b2013-03-10 16:04:38 -0700978 if (decoder.peekTypeAndVal() == null)
979 this.content = null;
980 else
981 this.content = decoder.readBinaryElement(CCNProtocolDTags.Content);
Wentao Shang0e291c82012-12-02 23:36:29 -0800982
Wentao Shang0e291c82012-12-02 23:36:29 -0800983 this.endSIG = decoder.offset;
Wentao Shang0e291c82012-12-02 23:36:29 -0800984
985 decoder.readEndElement();
986
987 this.saveRawData(decoder.istream);
988};
989
990ContentObject.prototype.to_ccnb = function(/*XMLEncoder*/ encoder) {
991
992 //TODO verify name, SignedInfo and Signature is present
993
994
995 encoder.writeStartElement(this.getElementLabel());
996
997
998
999
1000 if(null!=this.signature) this.signature.to_ccnb(encoder);
1001
1002
1003 this.startSIG = encoder.offset;
1004
1005
1006 if(null!=this.name) this.name.to_ccnb(encoder);
1007
1008 //this.endSIG = encoder.offset;
1009 //this.startSignedInfo = encoder.offset;
1010
1011
1012 if(null!=this.signedInfo) this.signedInfo.to_ccnb(encoder);
1013
1014 encoder.writeElement(CCNProtocolDTags.Content, this.content);
1015
1016
1017 this.endSIG = encoder.offset;
1018
1019 //this.endContent = encoder.offset;
1020
1021
1022 encoder.writeEndElement();
1023
1024 this.saveRawData(encoder.ostream);
1025
1026};
1027
1028ContentObject.prototype.getElementLabel= function(){return CCNProtocolDTags.ContentObject;};
1029
1030/**
1031 * Signature
1032 */
1033var Signature = function Signature(_witness,_signature,_digestAlgorithm) {
1034
1035 this.Witness = _witness;//byte [] _witness;
1036 this.signature = _signature;//byte [] _signature;
1037 this.digestAlgorithm = _digestAlgorithm//String _digestAlgorithm;
1038};
1039
Wentao Shang0e291c82012-12-02 23:36:29 -08001040Signature.prototype.from_ccnb =function( decoder) {
1041 decoder.readStartElement(this.getElementLabel());
1042
Wentao Shang882e34e2013-01-05 02:49:51 -08001043 if(LOG>4)console.log('STARTED DECODING SIGNATURE');
Wentao Shang0e291c82012-12-02 23:36:29 -08001044
1045 if (decoder.peekStartElement(CCNProtocolDTags.DigestAlgorithm)) {
Wentao Shang0e291c82012-12-02 23:36:29 -08001046 if(LOG>4)console.log('DIGIEST ALGORITHM FOUND');
1047 this.digestAlgorithm = decoder.readUTF8Element(CCNProtocolDTags.DigestAlgorithm);
1048 }
1049 if (decoder.peekStartElement(CCNProtocolDTags.Witness)) {
Wentao Shang882e34e2013-01-05 02:49:51 -08001050 if(LOG>4)console.log('WITNESS FOUND');
Wentao Shang0e291c82012-12-02 23:36:29 -08001051 this.Witness = decoder.readBinaryElement(CCNProtocolDTags.Witness);
1052 }
1053
1054 //FORCE TO READ A SIGNATURE
1055
Wentao Shang882e34e2013-01-05 02:49:51 -08001056 if(LOG>4)console.log('SIGNATURE FOUND');
1057 this.signature = decoder.readBinaryElement(CCNProtocolDTags.SignatureBits);
Wentao Shang0e291c82012-12-02 23:36:29 -08001058
1059 decoder.readEndElement();
1060
1061};
1062
1063
1064Signature.prototype.to_ccnb= function( encoder){
1065
1066 if (!this.validate()) {
1067 throw new Error("Cannot encode: field values missing.");
1068 }
1069
1070 encoder.writeStartElement(this.getElementLabel());
1071
1072 if ((null != this.digestAlgorithm) && (!this.digestAlgorithm.equals(CCNDigestHelper.DEFAULT_DIGEST_ALGORITHM))) {
1073 encoder.writeElement(CCNProtocolDTags.DigestAlgorithm, OIDLookup.getDigestOID(this.DigestAlgorithm));
1074 }
1075
1076 if (null != this.Witness) {
1077 // needs to handle null witness
1078 encoder.writeElement(CCNProtocolDTags.Witness, this.Witness);
1079 }
1080
1081 encoder.writeElement(CCNProtocolDTags.SignatureBits, this.signature);
1082
1083 encoder.writeEndElement();
1084};
1085
1086Signature.prototype.getElementLabel = function() { return CCNProtocolDTags.Signature; };
1087
1088
1089Signature.prototype.validate = function() {
1090 return null != this.signature;
1091};
1092
1093
1094/**
1095 * SignedInfo
1096 */
1097var ContentType = {DATA:0, ENCR:1, GONE:2, KEY:3, LINK:4, NACK:5};
1098var ContentTypeValue = {0:0x0C04C0, 1:0x10D091,2:0x18E344,3:0x28463F,4:0x2C834A,5:0x34008A};
1099var ContentTypeValueReverse = {0x0C04C0:0, 0x10D091:1,0x18E344:2,0x28463F:3,0x2C834A:4,0x34008A:5};
1100
1101var SignedInfo = function SignedInfo(_publisher,_timestamp,_type,_locator,_freshnessSeconds,_finalBlockID){
1102
1103 //TODO, Check types
1104
1105 this.publisher = _publisher; //publisherPublicKeyDigest
1106 this.timestamp=_timestamp; // CCN Time
1107 this.type=_type; // ContentType
1108 this.locator =_locator;//KeyLocator
1109 this.freshnessSeconds =_freshnessSeconds; // Integer
1110 this.finalBlockID=_finalBlockID; //byte array
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08001111
1112 // SWT: merge setFields() method into constructor
1113 this.setFields();
Wentao Shang0e291c82012-12-02 23:36:29 -08001114
1115};
1116
1117SignedInfo.prototype.setFields = function(){
1118 //BASE64 -> RAW STRING
1119
1120 //this.locator = new KeyLocator( DataUtils.toNumbersFromString(stringCertificate) ,KeyLocatorType.CERTIFICATE );
1121
1122 var publicKeyHex = globalKeyManager.publicKey;
1123
1124 if(LOG>4)console.log('PUBLIC KEY TO WRITE TO CONTENT OBJECT IS ');
1125 if(LOG>4)console.log(publicKeyHex);
1126
1127 var publicKeyBytes = DataUtils.toNumbers(globalKeyManager.publicKey) ;
1128
1129
1130
1131 //var stringCertificate = DataUtils.base64toString(globalKeyManager.certificate);
1132
1133 //if(LOG>3)console.log('string Certificate is '+stringCertificate);
1134
1135 //HEX -> BYTE ARRAY
1136 //var publisherkey = DataUtils.toNumbers(hex_sha256(stringCertificate));
1137
1138 //if(LOG>3)console.log('publisher key is ');
1139 //if(LOG>3)console.log(publisherkey);
1140
1141 var publisherKeyDigest = hex_sha256_from_bytes(publicKeyBytes);
1142
1143 this.publisher = new PublisherPublicKeyDigest( DataUtils.toNumbers( publisherKeyDigest ) );
1144
1145 //this.publisher = new PublisherPublicKeyDigest(publisherkey);
1146
1147 var d = new Date();
1148
1149 var time = d.getTime();
1150
1151
1152 this.timestamp = new CCNTime( time );
1153
1154 if(LOG>4)console.log('TIME msec is');
1155
1156 if(LOG>4)console.log(this.timestamp.msec);
1157
1158 //DATA
1159 this.type = 0;//0x0C04C0;//ContentTypeValue[ContentType.DATA];
1160
1161 //if(LOG>4)console.log('toNumbersFromString(stringCertificate) '+DataUtils.toNumbersFromString(stringCertificate));
1162
1163 if(LOG>4)console.log('PUBLIC KEY TO WRITE TO CONTENT OBJECT IS ');
1164 if(LOG>4)console.log(publicKeyBytes);
1165
1166 this.locator = new KeyLocator( publicKeyBytes ,KeyLocatorType.KEY );
1167
1168 //this.locator = new KeyLocator( DataUtils.toNumbersFromString(stringCertificate) ,KeyLocatorType.CERTIFICATE );
1169
1170};
1171
1172SignedInfo.prototype.from_ccnb = function( decoder){
1173
1174 decoder.readStartElement( this.getElementLabel() );
1175
1176 if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
Wentao Shang882e34e2013-01-05 02:49:51 -08001177 if(LOG>4)console.log('DECODING PUBLISHER KEY');
Wentao Shang0e291c82012-12-02 23:36:29 -08001178 this.publisher = new PublisherPublicKeyDigest();
1179 this.publisher.from_ccnb(decoder);
1180 }
1181
1182 if (decoder.peekStartElement(CCNProtocolDTags.Timestamp)) {
Wentao Shang882e34e2013-01-05 02:49:51 -08001183 if(LOG>4)console.log('DECODING TIMESTAMP');
Wentao Shang0e291c82012-12-02 23:36:29 -08001184 this.timestamp = decoder.readDateTime(CCNProtocolDTags.Timestamp);
Wentao Shang0e291c82012-12-02 23:36:29 -08001185 }
1186
1187 if (decoder.peekStartElement(CCNProtocolDTags.Type)) {
Jeff Thompson48ff28a2013-02-18 22:53:29 -08001188 var binType = decoder.readBinaryElement(CCNProtocolDTags.Type);//byte []
Wentao Shang0e291c82012-12-02 23:36:29 -08001189
1190
1191 //TODO Implement type of Key Reading
1192
1193 if(LOG>4)console.log('Binary Type of of Signed Info is '+binType);
1194
1195 this.type = binType;
1196
1197
1198 //TODO Implement type of Key Reading
1199
1200
1201 if (null == this.type) {
1202 throw new Error("Cannot parse signedInfo type: bytes.");
1203 }
1204
1205 } else {
1206 this.type = ContentType.DATA; // default
1207 }
1208
1209 if (decoder.peekStartElement(CCNProtocolDTags.FreshnessSeconds)) {
1210 this.freshnessSeconds = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
Wentao Shang882e34e2013-01-05 02:49:51 -08001211 if(LOG>4)console.log('FRESHNESS IN SECONDS IS '+ this.freshnessSeconds);
Wentao Shang0e291c82012-12-02 23:36:29 -08001212 }
1213
1214 if (decoder.peekStartElement(CCNProtocolDTags.FinalBlockID)) {
Wentao Shang882e34e2013-01-05 02:49:51 -08001215 if(LOG>4)console.log('DECODING FINAL BLOCKID');
Wentao Shang0e291c82012-12-02 23:36:29 -08001216 this.finalBlockID = decoder.readBinaryElement(CCNProtocolDTags.FinalBlockID);
1217 }
1218
1219 if (decoder.peekStartElement(CCNProtocolDTags.KeyLocator)) {
Wentao Shang882e34e2013-01-05 02:49:51 -08001220 if(LOG>4)console.log('DECODING KEY LOCATOR');
Wentao Shang0e291c82012-12-02 23:36:29 -08001221 this.locator = new KeyLocator();
1222 this.locator.from_ccnb(decoder);
1223 }
1224
1225 decoder.readEndElement();
1226};
1227
1228SignedInfo.prototype.to_ccnb = function( encoder) {
1229 if (!this.validate()) {
1230 throw new Error("Cannot encode : field values missing.");
1231 }
1232 encoder.writeStartElement(this.getElementLabel());
1233
1234 if (null!=this.publisher) {
1235 if(LOG>3) console.log('ENCODING PUBLISHER KEY' + this.publisher.publisherPublicKeyDigest);
1236
1237 this.publisher.to_ccnb(encoder);
1238 }
1239
1240 if (null!=this.timestamp) {
1241 encoder.writeDateTime(CCNProtocolDTags.Timestamp, this.timestamp );
1242 }
1243
1244 if (null!=this.type && this.type !=0) {
1245
1246 encoder.writeElement(CCNProtocolDTags.type, this.type);
1247 }
1248
1249 if (null!=this.freshnessSeconds) {
1250 encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.freshnessSeconds);
1251 }
1252
1253 if (null!=this.finalBlockID) {
1254 encoder.writeElement(CCNProtocolDTags.FinalBlockID, this.finalBlockID);
1255 }
1256
1257 if (null!=this.locator) {
1258 this.locator.to_ccnb(encoder);
1259 }
1260
1261 encoder.writeEndElement();
1262};
1263
1264SignedInfo.prototype.valueToType = function(){
1265 //for (Entry<byte [], ContentType> entry : ContentValueTypes.entrySet()) {
1266 //if (Arrays.equals(value, entry.getKey()))
1267 //return entry.getValue();
1268 //}
1269 return null;
1270
1271};
1272
1273SignedInfo.prototype.getElementLabel = function() {
1274 return CCNProtocolDTags.SignedInfo;
1275};
1276
1277SignedInfo.prototype.validate = function() {
1278 // We don't do partial matches any more, even though encoder/decoder
1279 // is still pretty generous.
1280 if (null ==this.publisher || null==this.timestamp ||null== this.locator)
1281 return false;
1282 return true;
1283};
1284/*
1285 * Date Format 1.2.3
1286 * (c) 2007-2009 Steven Levithan <stevenlevithan.com>
1287 * MIT license
1288 *
1289 * Includes enhancements by Scott Trenda <scott.trenda.net>
1290 * and Kris Kowal <cixar.com/~kris.kowal/>
1291 *
1292 * Accepts a date, a mask, or a date and a mask.
1293 * Returns a formatted version of the given date.
1294 * The date defaults to the current date/time.
1295 * The mask defaults to dateFormat.masks.default.
1296 */
1297
1298var DateFormat = function () {
1299 var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
1300 timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
1301 timezoneClip = /[^-+\dA-Z]/g,
1302 pad = function (val, len) {
1303 val = String(val);
1304 len = len || 2;
1305 while (val.length < len) val = "0" + val;
1306 return val;
1307 };
1308
1309 // Regexes and supporting functions are cached through closure
1310 return function (date, mask, utc) {
1311 var dF = dateFormat;
1312
1313 // You can't provide utc if you skip other args (use the "UTC:" mask prefix)
1314 if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) {
1315 mask = date;
1316 date = undefined;
1317 }
1318
1319 // Passing date through Date applies Date.parse, if necessary
1320 date = date ? new Date(date) : new Date;
1321 if (isNaN(date)) throw SyntaxError("invalid date");
1322
1323 mask = String(dF.masks[mask] || mask || dF.masks["default"]);
1324
1325 // Allow setting the utc argument via the mask
1326 if (mask.slice(0, 4) == "UTC:") {
1327 mask = mask.slice(4);
1328 utc = true;
1329 }
1330
1331 var _ = utc ? "getUTC" : "get",
1332 d = date[_ + "Date"](),
1333 D = date[_ + "Day"](),
1334 m = date[_ + "Month"](),
1335 y = date[_ + "FullYear"](),
1336 H = date[_ + "Hours"](),
1337 M = date[_ + "Minutes"](),
1338 s = date[_ + "Seconds"](),
1339 L = date[_ + "Milliseconds"](),
1340 o = utc ? 0 : date.getTimezoneOffset(),
1341 flags = {
1342 d: d,
1343 dd: pad(d),
1344 ddd: dF.i18n.dayNames[D],
1345 dddd: dF.i18n.dayNames[D + 7],
1346 m: m + 1,
1347 mm: pad(m + 1),
1348 mmm: dF.i18n.monthNames[m],
1349 mmmm: dF.i18n.monthNames[m + 12],
1350 yy: String(y).slice(2),
1351 yyyy: y,
1352 h: H % 12 || 12,
1353 hh: pad(H % 12 || 12),
1354 H: H,
1355 HH: pad(H),
1356 M: M,
1357 MM: pad(M),
1358 s: s,
1359 ss: pad(s),
1360 l: pad(L, 3),
1361 L: pad(L > 99 ? Math.round(L / 10) : L),
1362 t: H < 12 ? "a" : "p",
1363 tt: H < 12 ? "am" : "pm",
1364 T: H < 12 ? "A" : "P",
1365 TT: H < 12 ? "AM" : "PM",
1366 Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
1367 o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
1368 S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
1369 };
1370
1371 return mask.replace(token, function ($0) {
1372 return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
1373 });
1374 };
1375}();
1376
1377// Some common format strings
1378DateFormat.masks = {
1379 "default": "ddd mmm dd yyyy HH:MM:ss",
1380 shortDate: "m/d/yy",
1381 mediumDate: "mmm d, yyyy",
1382 longDate: "mmmm d, yyyy",
1383 fullDate: "dddd, mmmm d, yyyy",
1384 shortTime: "h:MM TT",
1385 mediumTime: "h:MM:ss TT",
1386 longTime: "h:MM:ss TT Z",
1387 isoDate: "yyyy-mm-dd",
1388 isoTime: "HH:MM:ss",
1389 isoDateTime: "yyyy-mm-dd'T'HH:MM:ss",
1390 isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
1391};
1392
1393// Internationalization strings
1394DateFormat.i18n = {
1395 dayNames: [
1396 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
1397 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
1398 ],
1399 monthNames: [
1400 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
1401 "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
1402 ]
1403};
1404
1405// For convenience...
1406Date.prototype.format = function (mask, utc) {
1407 return dateFormat(this, mask, utc);
1408};
Wentao Shangbd63e462012-12-03 16:19:33 -08001409/**
Wentao Shang0e291c82012-12-02 23:36:29 -08001410 * @author: Meki Cheraoui
1411 * See COPYING for copyright and distribution information.
1412 * This class represents Interest Objects
1413 */
1414
Jeff Thompson42806a12012-12-29 18:19:39 -08001415// _interestLifetime is in milliseconds.
Jeff Thompson65a11e42013-02-18 17:47:59 -08001416var Interest = function Interest
1417 (_name, _faceInstance, _minSuffixComponents, _maxSuffixComponents, _publisherPublicKeyDigest, _exclude,
1418 _childSelector, _answerOriginKind, _scope, _interestLifetime, _nonce) {
Wentao Shang0e291c82012-12-02 23:36:29 -08001419
1420 this.name = _name;
1421 this.faceInstance = _faceInstance;
1422 this.maxSuffixComponents = _maxSuffixComponents;
1423 this.minSuffixComponents = _minSuffixComponents;
1424
1425 this.publisherPublicKeyDigest = _publisherPublicKeyDigest;
1426 this.exclude = _exclude;
1427 this.childSelector = _childSelector;
1428 this.answerOriginKind = _answerOriginKind;
1429 this.scope = _scope;
Jeff Thompson42806a12012-12-29 18:19:39 -08001430 this.interestLifetime = _interestLifetime; // milli seconds
Wentao Shang0e291c82012-12-02 23:36:29 -08001431 this.nonce = _nonce;
1432};
1433
1434Interest.RECURSIVE_POSTFIX = "*";
1435
1436Interest.CHILD_SELECTOR_LEFT = 0;
1437Interest.CHILD_SELECTOR_RIGHT = 1;
1438Interest.ANSWER_CONTENT_STORE = 1;
1439Interest.ANSWER_GENERATED = 2;
1440Interest.ANSWER_STALE = 4; // Stale answer OK
1441Interest.MARK_STALE = 16; // Must have scope 0. Michael calls this a "hack"
1442
1443Interest.DEFAULT_ANSWER_ORIGIN_KIND = Interest.ANSWER_CONTENT_STORE | Interest.ANSWER_GENERATED;
1444
1445
1446Interest.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
1447
1448 decoder.readStartElement(CCNProtocolDTags.Interest);
1449
1450 this.name = new Name();
1451 this.name.from_ccnb(decoder);
1452
1453 if (decoder.peekStartElement(CCNProtocolDTags.MinSuffixComponents))
1454 this.minSuffixComponents = decoder.readIntegerElement(CCNProtocolDTags.MinSuffixComponents);
1455
1456 if (decoder.peekStartElement(CCNProtocolDTags.MaxSuffixComponents))
1457 this.maxSuffixComponents = decoder.readIntegerElement(CCNProtocolDTags.MaxSuffixComponents);
1458
1459 if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
1460 this.publisherPublicKeyDigest = new PublisherPublicKeyDigest();
1461 this.publisherPublicKeyDigest.from_ccnb(decoder);
1462 }
1463
1464 if (decoder.peekStartElement(CCNProtocolDTags.Exclude)) {
1465 this.exclude = new Exclude();
1466 this.exclude.from_ccnb(decoder);
1467 }
1468
1469 if (decoder.peekStartElement(CCNProtocolDTags.ChildSelector))
1470 this.childSelector = decoder.readIntegerElement(CCNProtocolDTags.ChildSelector);
1471
1472 if (decoder.peekStartElement(CCNProtocolDTags.AnswerOriginKind))
1473 this.answerOriginKind = decoder.readIntegerElement(CCNProtocolDTags.AnswerOriginKind);
1474
1475 if (decoder.peekStartElement(CCNProtocolDTags.Scope))
1476 this.scope = decoder.readIntegerElement(CCNProtocolDTags.Scope);
1477
1478 if (decoder.peekStartElement(CCNProtocolDTags.InterestLifetime))
Jeff Thompson42806a12012-12-29 18:19:39 -08001479 this.interestLifetime = 1000.0 * DataUtils.bigEndianToUnsignedInt
Wentao Shang0e291c82012-12-02 23:36:29 -08001480 (decoder.readBinaryElement(CCNProtocolDTags.InterestLifetime)) / 4096;
1481
1482 if (decoder.peekStartElement(CCNProtocolDTags.Nonce))
1483 this.nonce = decoder.readBinaryElement(CCNProtocolDTags.Nonce);
1484
1485 decoder.readEndElement();
1486};
1487
1488Interest.prototype.to_ccnb = function(/*XMLEncoder*/ encoder){
1489 //Could check if name is present
1490
1491 encoder.writeStartElement(CCNProtocolDTags.Interest);
1492
1493 this.name.to_ccnb(encoder);
1494
1495 if (null != this.minSuffixComponents)
1496 encoder.writeElement(CCNProtocolDTags.MinSuffixComponents, this.minSuffixComponents);
1497
1498 if (null != this.maxSuffixComponents)
1499 encoder.writeElement(CCNProtocolDTags.MaxSuffixComponents, this.maxSuffixComponents);
1500
1501 if (null != this.publisherPublicKeyDigest)
1502 this.publisherPublicKeyDigest.to_ccnb(encoder);
1503
1504 if (null != this.exclude)
1505 this.exclude.to_ccnb(encoder);
1506
1507 if (null != this.childSelector)
1508 encoder.writeElement(CCNProtocolDTags.ChildSelector, this.childSelector);
1509
1510 if (this.DEFAULT_ANSWER_ORIGIN_KIND != this.answerOriginKind && this.answerOriginKind!=null)
1511 encoder.writeElement(CCNProtocolDTags.AnswerOriginKind, this.answerOriginKind);
1512
1513 if (null != this.scope)
1514 encoder.writeElement(CCNProtocolDTags.Scope, this.scope);
1515
1516 if (null != this.interestLifetime)
1517 encoder.writeElement(CCNProtocolDTags.InterestLifetime,
Jeff Thompson42806a12012-12-29 18:19:39 -08001518 DataUtils.nonNegativeIntToBigEndian((this.interestLifetime / 1000.0) * 4096));
Wentao Shang0e291c82012-12-02 23:36:29 -08001519
1520 if (null != this.nonce)
1521 encoder.writeElement(CCNProtocolDTags.Nonce, this.nonce);
1522
1523 encoder.writeEndElement();
1524
1525};
1526
Jeff Thompson202728a2013-02-10 22:20:08 -08001527/*
1528 * Return true if this.name.match(name) and the name conforms to the interest selectors.
1529 */
Wentao Shangd4bef8d2013-01-17 12:03:06 -08001530Interest.prototype.matches_name = function(/*Name*/ name) {
Jeff Thompson202728a2013-02-10 22:20:08 -08001531 if (!this.name.match(name))
1532 return false;
1533
1534 if (this.minSuffixComponents != null &&
1535 // Add 1 for the implicit digest.
1536 !(name.components.length + 1 - this.name.components.length >= this.minSuffixComponents))
1537 return false;
1538 if (this.maxSuffixComponents != null &&
1539 // Add 1 for the implicit digest.
1540 !(name.components.length + 1 - this.name.components.length <= this.maxSuffixComponents))
1541 return false;
1542 if (this.exclude != null && name.components.length > this.name.components.length &&
1543 this.exclude.matches(name.components[this.name.components.length]))
1544 return false;
1545
1546 return true;
Jeff Thompson65a11e42013-02-18 17:47:59 -08001547};
1548
1549/*
1550 * Return a new Interest with the same fields as this Interest.
1551 * Note: This does NOT make a deep clone of the name, exclue or other objects.
1552 */
1553Interest.prototype.clone = function() {
1554 return new Interest
1555 (this.name, this.faceInstance, this.minSuffixComponents, this.maxSuffixComponents,
1556 this.publisherPublicKeyDigest, this.exclude, this.childSelector, this.answerOriginKind,
1557 this.scope, this.interestLifetime, this.nonce);
1558};
Wentao Shang0e291c82012-12-02 23:36:29 -08001559
Jeff Thompson08d41b72013-02-03 23:09:29 -08001560/*
1561 * Handle the interest Exclude element.
1562 * _values is an array where each element is either Uint8Array component or Exclude.ANY.
Wentao Shang0e291c82012-12-02 23:36:29 -08001563 */
Jeff Thompson08d41b72013-02-03 23:09:29 -08001564var Exclude = function Exclude(_values) {
1565 this.values = (_values || []);
Wentao Shang0e291c82012-12-02 23:36:29 -08001566}
1567
Jeff Thompson08d41b72013-02-03 23:09:29 -08001568Exclude.ANY = "*";
1569
Wentao Shang0e291c82012-12-02 23:36:29 -08001570Exclude.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
Jeff Thompson08d41b72013-02-03 23:09:29 -08001571 decoder.readStartElement(CCNProtocolDTags.Exclude);
Wentao Shang0e291c82012-12-02 23:36:29 -08001572
Jeff Thompson08d41b72013-02-03 23:09:29 -08001573 while (true) {
1574 if (decoder.peekStartElement(CCNProtocolDTags.Component))
1575 this.values.push(decoder.readBinaryElement(CCNProtocolDTags.Component));
1576 else if (decoder.peekStartElement(CCNProtocolDTags.Any)) {
1577 decoder.readStartElement(CCNProtocolDTags.Any);
1578 decoder.readEndElement();
1579 this.values.push(Exclude.ANY);
1580 }
1581 else if (decoder.peekStartElement(CCNProtocolDTags.Bloom)) {
1582 // Skip the Bloom and treat it as Any.
1583 decoder.readBinaryElement(CCNProtocolDTags.Bloom);
1584 this.values.push(Exclude.ANY);
1585 }
1586 else
1587 break;
1588 }
1589
1590 decoder.readEndElement();
1591};
1592
1593Exclude.prototype.to_ccnb = function(/*XMLEncoder*/ encoder) {
1594 if (this.values == null || this.values.length == 0)
1595 return;
1596
1597 encoder.writeStartElement(CCNProtocolDTags.Exclude);
1598
1599 // TODO: Do we want to order the components (except for ANY)?
1600 for (var i = 0; i < this.values.length; ++i) {
1601 if (this.values[i] == Exclude.ANY) {
1602 encoder.writeStartElement(CCNProtocolDTags.Any);
1603 encoder.writeEndElement();
1604 }
1605 else
1606 encoder.writeElement(CCNProtocolDTags.Component, this.values[i]);
1607 }
1608
1609 encoder.writeEndElement();
1610};
1611
Jeff Thompson202728a2013-02-10 22:20:08 -08001612/*
1613 * Return a string with elements separated by "," and Exclude.ANY shown as "*".
1614 */
Jeff Thompson08d41b72013-02-03 23:09:29 -08001615Exclude.prototype.to_uri = function() {
1616 if (this.values == null || this.values.length == 0)
1617 return "";
1618
1619 var result = "";
1620 for (var i = 0; i < this.values.length; ++i) {
1621 if (i > 0)
1622 result += ",";
Jeff Thompsonfced4c22013-01-27 16:34:13 -08001623
Jeff Thompson08d41b72013-02-03 23:09:29 -08001624 if (this.values[i] == Exclude.ANY)
1625 result += "*";
1626 else
1627 result += Name.toEscapedString(this.values[i]);
1628 }
1629 return result;
Wentao Shang0e291c82012-12-02 23:36:29 -08001630};
Jeff Thompson202728a2013-02-10 22:20:08 -08001631
1632/*
1633 * Return true if the component matches any of the exclude criteria.
1634 */
1635Exclude.prototype.matches = function(/*Uint8Array*/ component) {
1636 for (var i = 0; i < this.values.length; ++i) {
1637 if (this.values[i] == Exclude.ANY) {
1638 var lowerBound = null;
1639 if (i > 0)
1640 lowerBound = this.values[i - 1];
1641
1642 // Find the upper bound, possibly skipping over multiple ANY in a row.
1643 var iUpperBound;
1644 var upperBound = null;
1645 for (iUpperBound = i + 1; iUpperBound < this.values.length; ++iUpperBound) {
1646 if (this.values[iUpperBound] != Exclude.ANY) {
1647 upperBound = this.values[iUpperBound];
1648 break;
1649 }
1650 }
1651
1652 // If lowerBound != null, we already checked component equals lowerBound on the last pass.
1653 // If upperBound != null, we will check component equals upperBound on the next pass.
1654 if (upperBound != null) {
1655 if (lowerBound != null) {
1656 if (Exclude.compareComponents(component, lowerBound) > 0 &&
1657 Exclude.compareComponents(component, upperBound) < 0)
1658 return true;
1659 }
1660 else {
1661 if (Exclude.compareComponents(component, upperBound) < 0)
1662 return true;
1663 }
1664
1665 // Make i equal iUpperBound on the next pass.
1666 i = iUpperBound - 1;
1667 }
1668 else {
1669 if (lowerBound != null) {
1670 if (Exclude.compareComponents(component, lowerBound) > 0)
1671 return true;
1672 }
1673 else
1674 // this.values has only ANY.
1675 return true;
1676 }
1677 }
1678 else {
1679 if (DataUtils.arraysEqual(component, this.values[i]))
1680 return true;
1681 }
1682 }
1683
1684 return false;
1685};
1686
1687/*
1688 * Return -1 if component1 is less than component2, 1 if greater or 0 if equal.
1689 * A component is less if it is shorter, otherwise if equal length do a byte comparison.
1690 */
1691Exclude.compareComponents = function(/*Uint8Array*/ component1, /*Uint8Array*/ component2) {
1692 if (component1.length < component2.length)
1693 return -1;
1694 if (component1.length > component2.length)
1695 return 1;
1696
1697 for (var i = 0; i < component1.length; ++i) {
1698 if (component1[i] < component2[i])
1699 return -1;
1700 if (component1[i] > component2[i])
1701 return 1;
1702 }
1703
1704 return 0;
1705};
Wentao Shangbd63e462012-12-03 16:19:33 -08001706/**
Wentao Shang0e291c82012-12-02 23:36:29 -08001707 * @author: Meki Cheraoui
1708 * See COPYING for copyright and distribution information.
1709 * This class represents Key Objects
1710 */
1711
1712var Key = function Key(){
1713 /* TODO: Port from PyCCN:
1714 generateRSA()
1715 privateToDER()
1716 publicToDER()
1717 privateToPEM()
1718 publicToPEM()
1719 fromDER()
1720 fromPEM()
1721 */
1722}
1723
1724/**
1725 * KeyLocator
1726 */
1727var KeyLocatorType = {
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08001728 KEY:1,
1729 CERTIFICATE:2,
1730 KEYNAME:3
Wentao Shang0e291c82012-12-02 23:36:29 -08001731};
1732
1733var KeyLocator = function KeyLocator(_input,_type){
1734
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08001735 this.type = _type;
Wentao Shang0e291c82012-12-02 23:36:29 -08001736
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08001737 if (_type == KeyLocatorType.KEYNAME){
1738 if (LOG>3) console.log('KeyLocator: SET KEYNAME');
Wentao Shang0e291c82012-12-02 23:36:29 -08001739 this.keyName = _input;
1740 }
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08001741 else if (_type == KeyLocatorType.KEY){
1742 if (LOG>3) console.log('KeyLocator: SET KEY');
Wentao Shang0e291c82012-12-02 23:36:29 -08001743 this.publicKey = _input;
1744 }
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08001745 else if (_type == KeyLocatorType.CERTIFICATE){
1746 if (LOG>3) console.log('KeyLocator: SET CERTIFICATE');
Wentao Shang0e291c82012-12-02 23:36:29 -08001747 this.certificate = _input;
1748 }
1749
1750};
1751
1752KeyLocator.prototype.from_ccnb = function(decoder) {
1753
Wentao Shang82854bd2012-12-27 14:14:41 -08001754 decoder.readStartElement(this.getElementLabel());
Wentao Shang0e291c82012-12-02 23:36:29 -08001755
Wentao Shang82854bd2012-12-27 14:14:41 -08001756 if (decoder.peekStartElement(CCNProtocolDTags.Key)) {
1757 try {
Jeff Thompson48ff28a2013-02-18 22:53:29 -08001758 var encodedKey = decoder.readBinaryElement(CCNProtocolDTags.Key);
Wentao Shang82854bd2012-12-27 14:14:41 -08001759 // This is a DER-encoded SubjectPublicKeyInfo.
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08001760
Wentao Shang82854bd2012-12-27 14:14:41 -08001761 //TODO FIX THIS, This should create a Key Object instead of keeping bytes
1762
1763 this.publicKey = encodedKey;//CryptoUtil.getPublicKey(encodedKey);
1764 this.type = KeyLocatorType.KEY;
1765
1766
1767 if(LOG>4) console.log('PUBLIC KEY FOUND: '+ this.publicKey);
1768 //this.publicKey = encodedKey;
1769
1770
1771 } catch (e) {
1772 throw new Error("Cannot parse key: ", e);
1773 }
1774
1775 if (null == this.publicKey) {
1776 throw new Error("Cannot parse key: ");
Wentao Shang0e291c82012-12-02 23:36:29 -08001777 }
Wentao Shang82854bd2012-12-27 14:14:41 -08001778
1779 } else if ( decoder.peekStartElement(CCNProtocolDTags.Certificate)) {
1780 try {
Jeff Thompson48ff28a2013-02-18 22:53:29 -08001781 var encodedCert = decoder.readBinaryElement(CCNProtocolDTags.Certificate);
Wentao Shang82854bd2012-12-27 14:14:41 -08001782
1783 /*
1784 * Certificates not yet working
1785 */
1786
1787 //CertificateFactory factory = CertificateFactory.getInstance("X.509");
1788 //this.certificate = (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(encodedCert));
1789
1790
1791 this.certificate = encodedCert;
1792 this.type = KeyLocatorType.CERTIFICATE;
1793
1794 if(LOG>4) console.log('CERTIFICATE FOUND: '+ this.certificate);
1795
1796 } catch ( e) {
1797 throw new Error("Cannot decode certificate: " + e);
1798 }
1799 if (null == this.certificate) {
1800 throw new Error("Cannot parse certificate! ");
1801 }
1802 } else {
1803 this.type = KeyLocatorType.KEYNAME;
1804
1805 this.keyName = new KeyName();
1806 this.keyName.from_ccnb(decoder);
Wentao Shang0e291c82012-12-02 23:36:29 -08001807 }
Wentao Shang82854bd2012-12-27 14:14:41 -08001808 decoder.readEndElement();
1809};
Wentao Shang0e291c82012-12-02 23:36:29 -08001810
1811
Wentao Shang82854bd2012-12-27 14:14:41 -08001812KeyLocator.prototype.to_ccnb = function( encoder) {
1813
1814 if(LOG>4) console.log('type is is ' + this.type);
1815 //TODO Check if Name is missing
1816 if (!this.validate()) {
1817 throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
1818 }
Wentao Shang0e291c82012-12-02 23:36:29 -08001819
Wentao Shang82854bd2012-12-27 14:14:41 -08001820
1821 //TODO FIX THIS TOO
1822 encoder.writeStartElement(this.getElementLabel());
1823
1824 if (this.type == KeyLocatorType.KEY) {
1825 if(LOG>5)console.log('About to encode a public key' +this.publicKey);
1826 encoder.writeElement(CCNProtocolDTags.Key, this.publicKey);
Wentao Shang0e291c82012-12-02 23:36:29 -08001827
Wentao Shang82854bd2012-12-27 14:14:41 -08001828 } else if (this.type == KeyLocatorType.CERTIFICATE) {
Wentao Shang0e291c82012-12-02 23:36:29 -08001829
Wentao Shang82854bd2012-12-27 14:14:41 -08001830 try {
1831 encoder.writeElement(CCNProtocolDTags.Certificate, this.certificate);
1832 } catch ( e) {
1833 throw new Error("CertificateEncodingException attempting to write key locator: " + e);
Wentao Shang0e291c82012-12-02 23:36:29 -08001834 }
Wentao Shang0e291c82012-12-02 23:36:29 -08001835
Wentao Shang82854bd2012-12-27 14:14:41 -08001836 } else if (this.type == KeyLocatorType.KEYNAME) {
1837
1838 this.keyName.to_ccnb(encoder);
1839 }
1840 encoder.writeEndElement();
1841
Wentao Shang0e291c82012-12-02 23:36:29 -08001842};
1843
1844KeyLocator.prototype.getElementLabel = function() {
1845 return CCNProtocolDTags.KeyLocator;
1846};
1847
1848KeyLocator.prototype.validate = function() {
1849 return ( (null != this.keyName) || (null != this.publicKey) || (null != this.certificate) );
1850};
1851
1852/**
1853 * KeyName is only used by KeyLocator.
1854 */
1855var KeyName = function KeyName() {
Wentao Shang98b595c2012-12-30 10:14:26 -08001856 this.contentName = this.contentName; //contentName
1857 this.publisherID = this.publisherID; //publisherID
Wentao Shang0e291c82012-12-02 23:36:29 -08001858
1859};
1860
1861KeyName.prototype.from_ccnb=function( decoder){
1862
1863
1864 decoder.readStartElement(this.getElementLabel());
1865
1866 this.contentName = new Name();
1867 this.contentName.from_ccnb(decoder);
1868
1869 if(LOG>4) console.log('KEY NAME FOUND: ');
1870
1871 if ( PublisherID.peek(decoder) ) {
1872 this.publisherID = new PublisherID();
1873 this.publisherID.from_ccnb(decoder);
1874 }
1875
1876 decoder.readEndElement();
1877};
1878
1879KeyName.prototype.to_ccnb = function( encoder) {
1880 if (!this.validate()) {
1881 throw new Error("Cannot encode : field values missing.");
1882 }
1883
1884 encoder.writeStartElement(this.getElementLabel());
1885
1886 this.contentName.to_ccnb(encoder);
1887 if (null != this.publisherID)
1888 this.publisherID.to_ccnb(encoder);
1889
1890 encoder.writeEndElement();
1891};
1892
1893KeyName.prototype.getElementLabel = function() { return CCNProtocolDTags.KeyName; };
1894
1895KeyName.prototype.validate = function() {
1896 // DKS -- do we do recursive validation?
1897 // null signedInfo ok
1898 return (null != this.contentName);
1899};
Wentao Shang82854bd2012-12-27 14:14:41 -08001900
Wentao Shangbd63e462012-12-03 16:19:33 -08001901/**
Wentao Shang0e291c82012-12-02 23:36:29 -08001902 * @author: Meki Cheraoui
1903 * See COPYING for copyright and distribution information.
1904 * This class represents Publisher and PublisherType Objects
1905 */
1906
1907
1908var PublisherType = function PublisherType(_tag){
1909 this.KEY =(CCNProtocolDTags.PublisherPublicKeyDigest);
1910 this.CERTIFICATE= (CCNProtocolDTags.PublisherCertificateDigest);
1911 this.ISSUER_KEY= (CCNProtocolDTags.PublisherIssuerKeyDigest);
1912 this.ISSUER_CERTIFICATE =(CCNProtocolDTags.PublisherIssuerCertificateDigest);
1913
1914 this.Tag = _tag;
1915};
1916
1917var isTypeTagVal = function(tagVal) {
1918 if ((tagVal == CCNProtocolDTags.PublisherPublicKeyDigest) ||
1919 (tagVal == CCNProtocolDTags.PublisherCertificateDigest) ||
1920 (tagVal == CCNProtocolDTags.PublisherIssuerKeyDigest) ||
1921 (tagVal == CCNProtocolDTags.PublisherIssuerCertificateDigest)) {
1922 return true;
1923 }
1924 return false;
1925};
1926
1927
1928
1929
1930var PublisherID = function PublisherID() {
1931
1932 this.PUBLISHER_ID_DIGEST_ALGORITHM = "SHA-256";
1933 this.PUBLISHER_ID_LEN = 256/8;
1934
1935 //TODO, implement publisherID creation and key creation
1936
1937 //TODO implement generatePublicKeyDigest
1938 this.publisherID =null;//= generatePublicKeyDigest(key);//ByteArray
1939
1940 //TODO implement generate key
1941 //CryptoUtil.generateKeyID(PUBLISHER_ID_DIGEST_ALGORITHM, key);
1942 this.publisherType = null;//isIssuer ? PublisherType.ISSUER_KEY : PublisherType.KEY;//publisher Type
1943
1944};
1945
1946
1947PublisherID.prototype.from_ccnb = function(decoder) {
1948
1949 // We have a choice here of one of 4 binary element types.
1950 var nextTag = decoder.peekStartElementAsLong();
1951
1952 if (null == nextTag) {
1953 throw new Error("Cannot parse publisher ID.");
1954 }
1955
1956 this.publisherType = new PublisherType(nextTag);
1957
1958 if (!isTypeTagVal(nextTag)) {
1959 throw new Error("Invalid publisher ID, got unexpected type: " + nextTag);
1960 }
1961 this.publisherID = decoder.readBinaryElement(nextTag);
1962 if (null == this.publisherID) {
1963 throw new ContentDecodingException(new Error("Cannot parse publisher ID of type : " + nextTag + "."));
1964 }
1965};
1966
1967PublisherID.prototype.to_ccnb = function(encoder) {
1968 if (!this.validate()) {
1969 throw new Error("Cannot encode " + this.getClass().getName() + ": field values missing.");
1970 }
1971
1972 encoder.writeElement(this.getElementLabel(), this.publisherID);
1973};
1974
1975PublisherID.peek = function(/* XMLDecoder */ decoder) {
1976
1977 //Long
Jeff Thompson48ff28a2013-02-18 22:53:29 -08001978 var nextTag = decoder.peekStartElementAsLong();
Wentao Shang0e291c82012-12-02 23:36:29 -08001979
1980 if (null == nextTag) {
1981 // on end element
1982 return false;
1983 }
1984 return (isTypeTagVal(nextTag));
1985 };
1986
1987PublisherID.prototype.getElementLabel = function() {
1988 return this.publisherType.Tag;
1989};
1990
1991PublisherID.prototype.validate = function(){
1992 return ((null != id() && (null != type())));
1993};
1994
1995
1996
Wentao Shangbd63e462012-12-03 16:19:33 -08001997/**
Wentao Shang0e291c82012-12-02 23:36:29 -08001998 * @author: Meki Cheraoui
1999 * See COPYING for copyright and distribution information.
2000 * This class represents PublisherPublicKeyDigest Objects
2001 */
2002var PublisherPublicKeyDigest = function PublisherPublicKeyDigest(_pkd){
2003
2004 //this.PUBLISHER_ID_LEN = 256/8;
2005 this.PUBLISHER_ID_LEN = 512/8;
2006
2007
2008 this.publisherPublicKeyDigest = _pkd;
2009 //if( typeof _pkd == "object") this.publisherPublicKeyDigest = _pkd; // Byte Array
2010 //else if( typeof _pkd == "PublicKey") ;//TODO...
2011
2012};
2013
2014PublisherPublicKeyDigest.prototype.from_ccnb = function( decoder) {
2015
2016 this.publisherPublicKeyDigest = decoder.readBinaryElement(this.getElementLabel());
2017
2018 if(LOG>4)console.log('Publisher public key digest is ' + this.publisherPublicKeyDigest);
2019
2020 if (null == this.publisherPublicKeyDigest) {
2021 throw new Error("Cannot parse publisher key digest.");
2022 }
2023
2024 //TODO check if the length of the PublisherPublicKeyDigest is correct ( Security reason)
2025
2026 if (this.publisherPublicKeyDigest.length != this.PUBLISHER_ID_LEN) {
2027 if (LOG > 0)
2028 console.log('LENGTH OF PUBLISHER ID IS WRONG! Expected ' + this.PUBLISHER_ID_LEN + ", got " + this.publisherPublicKeyDigest.length);
2029
2030 //this.publisherPublicKeyDigest = new PublisherPublicKeyDigest(this.PublisherPublicKeyDigest).PublisherKeyDigest;
2031 }
2032 };
2033
2034PublisherPublicKeyDigest.prototype.to_ccnb= function( encoder) {
2035 //TODO Check that the ByteArray for the key is present
2036 if (!this.validate()) {
2037 throw new Error("Cannot encode : field values missing.");
2038 }
2039 if(LOG>3) console.log('PUBLISHER KEY DIGEST IS'+this.publisherPublicKeyDigest);
2040 encoder.writeElement(this.getElementLabel(), this.publisherPublicKeyDigest);
2041};
2042
2043PublisherPublicKeyDigest.prototype.getElementLabel = function() { return CCNProtocolDTags.PublisherPublicKeyDigest; };
2044
2045PublisherPublicKeyDigest.prototype.validate =function() {
2046 return (null != this.publisherPublicKeyDigest);
2047};
Wentao Shangbd63e462012-12-03 16:19:33 -08002048/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002049 * @author: Meki Cheraoui
2050 * See COPYING for copyright and distribution information.
2051 * This class represents Face Instances
2052 */
2053
2054var NetworkProtocol = { TCP:6, UDP:17};
2055
2056var FaceInstance = function FaceInstance(
2057 _action,
2058 _publisherPublicKeyDigest,
2059 _faceID,
2060 _ipProto,
2061 _host,
2062 _port,
2063 _multicastInterface,
2064 _multicastTTL,
2065 _freshnessSeconds){
2066
2067
2068 this.action = _action;
2069 this.publisherPublicKeyDigest = _publisherPublicKeyDigest;
2070 this.faceID = _faceID;
2071 this.ipProto = _ipProto;
2072 this.host = _host;
2073 this.Port = _port;
2074 this.multicastInterface =_multicastInterface;
2075 this.multicastTTL =_multicastTTL;
2076 this.freshnessSeconds = _freshnessSeconds;
2077
2078 //action ::= ("newface" | "destroyface" | "queryface")
2079 //publisherPublicKeyDigest ::= SHA-256 digest
2080 //faceID ::= nonNegativeInteger
2081 //ipProto ::= nonNegativeInteger [IANA protocol number, 6=TCP, 17=UDP]
2082 //Host ::= textual representation of numeric IPv4 or IPv6 address
2083 //Port ::= nonNegativeInteger [1..65535]
2084 //MulticastInterface ::= textual representation of numeric IPv4 or IPv6 address
2085 //MulticastTTL ::= nonNegativeInteger [1..255]
2086 //freshnessSeconds ::= nonNegativeInteger
2087
2088};
2089
2090/**
2091 * Used by NetworkObject to decode the object from a network stream.
2092 */
2093FaceInstance.prototype.from_ccnb = function(//XMLDecoder
2094 decoder) {
2095
2096 decoder.readStartElement(this.getElementLabel());
2097
2098 if (decoder.peekStartElement(CCNProtocolDTags.Action)) {
2099
2100 this.action = decoder.readUTF8Element(CCNProtocolDTags.Action);
2101
2102 }
2103 if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
2104
2105 this.publisherPublicKeyDigest = new PublisherPublicKeyDigest();
2106 this.publisherPublicKeyDigest.from_ccnb(decoder);
2107
2108 }
2109 if (decoder.peekStartElement(CCNProtocolDTags.FaceID)) {
2110
2111 this.faceID = decoder.readIntegerElement(CCNProtocolDTags.FaceID);
2112
2113 }
2114 if (decoder.peekStartElement(CCNProtocolDTags.IPProto)) {
2115
2116 //int
2117 var pI = decoder.readIntegerElement(CCNProtocolDTags.IPProto);
2118
2119 this.ipProto = null;
2120
2121 if (NetworkProtocol.TCP == pI) {
2122
2123 this.ipProto = NetworkProtocol.TCP;
2124
2125 } else if (NetworkProtocol.UDP == pI) {
2126
2127 this.ipProto = NetworkProtocol.UDP;
2128
2129 } else {
2130
2131 throw new Error("FaceInstance.decoder. Invalid " +
2132 CCNProtocolDTags.tagToString(CCNProtocolDTags.IPProto) + " field: " + pI);
2133
2134 }
2135 }
2136
2137 if (decoder.peekStartElement(CCNProtocolDTags.Host)) {
2138
2139 this.host = decoder.readUTF8Element(CCNProtocolDTags.Host);
2140
2141 }
2142
2143 if (decoder.peekStartElement(CCNProtocolDTags.Port)) {
2144 this.Port = decoder.readIntegerElement(CCNProtocolDTags.Port);
2145 }
2146
2147 if (decoder.peekStartElement(CCNProtocolDTags.MulticastInterface)) {
2148 this.multicastInterface = decoder.readUTF8Element(CCNProtocolDTags.MulticastInterface);
2149 }
2150
2151 if (decoder.peekStartElement(CCNProtocolDTags.MulticastTTL)) {
2152 this.multicastTTL = decoder.readIntegerElement(CCNProtocolDTags.MulticastTTL);
2153 }
2154
2155 if (decoder.peekStartElement(CCNProtocolDTags.FreshnessSeconds)) {
2156 this.freshnessSeconds = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
2157 }
2158 decoder.readEndElement();
2159}
2160
2161/**
2162 * Used by NetworkObject to encode the object to a network stream.
2163 */
2164FaceInstance.prototype.to_ccnb = function(//XMLEncoder
2165 encoder){
2166
2167 //if (!this.validate()) {
2168 //throw new Error("Cannot encode : field values missing.");
2169 //throw new Error("")
2170 //}
2171 encoder.writeStartElement(this.getElementLabel());
2172
2173 if (null != this.action && this.action.length != 0)
2174 encoder.writeElement(CCNProtocolDTags.Action, this.action);
2175
2176 if (null != this.publisherPublicKeyDigest) {
2177 this.publisherPublicKeyDigest.to_ccnb(encoder);
2178 }
2179 if (null != this.faceID) {
2180 encoder.writeElement(CCNProtocolDTags.FaceID, this.faceID);
2181 }
2182 if (null != this.ipProto) {
2183 //encoder.writeElement(CCNProtocolDTags.IPProto, this.IpProto.value());
2184 encoder.writeElement(CCNProtocolDTags.IPProto, this.ipProto);
2185 }
2186 if (null != this.host && this.host.length != 0) {
2187 encoder.writeElement(CCNProtocolDTags.Host, this.host);
2188 }
2189 if (null != this.Port) {
2190 encoder.writeElement(CCNProtocolDTags.Port, this.Port);
2191 }
2192 if (null != this.multicastInterface && this.multicastInterface.length != 0) {
2193 encoder.writeElement(CCNProtocolDTags.MulticastInterface, this.multicastInterface);
2194 }
2195 if (null != this.multicastTTL) {
2196 encoder.writeElement(CCNProtocolDTags.MulticastTTL, this.multicastTTL);
2197 }
2198 if (null != this.freshnessSeconds) {
2199 encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.freshnessSeconds);
2200 }
2201 encoder.writeEndElement();
2202}
2203
2204
2205FaceInstance.prototype.getElementLabel= function(){return CCNProtocolDTags.FaceInstance;};
2206
Wentao Shangbd63e462012-12-03 16:19:33 -08002207/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002208 * @author: Meki Cheraoui
2209 * See COPYING for copyright and distribution information.
2210 * This class represents Forwarding Entries
2211 */
2212
2213var ForwardingEntry = function ForwardingEntry(
2214 //ActionType
2215 _action,
2216 //Name
2217 _prefixName,
2218 //PublisherPublicKeyDigest
2219 _ccndId,
2220 //Integer
2221 _faceID,
2222 //Integer
2223 _flags,
2224 //Integer
2225 _lifetime){
2226
2227
2228
2229 //String
2230 this.action = _action;
2231 //Name\
2232 this.prefixName = _prefixName;
2233 //PublisherPublicKeyDigest
2234 this.ccndID = _ccndId;
2235 //Integer
2236 this.faceID = _faceID;
2237 //Integer
2238 this.flags = _flags;
2239 //Integer
2240 this.lifetime = _lifetime; // in seconds
2241
2242};
2243
2244ForwardingEntry.prototype.from_ccnb =function(
2245 //XMLDecoder
2246 decoder)
2247 //throws ContentDecodingException
2248 {
2249 decoder.readStartElement(this.getElementLabel());
2250 if (decoder.peekStartElement(CCNProtocolDTags.Action)) {
2251 this.action = decoder.readUTF8Element(CCNProtocolDTags.Action);
2252 }
2253 if (decoder.peekStartElement(CCNProtocolDTags.Name)) {
2254 this.prefixName = new Name();
2255 this.prefixName.from_ccnb(decoder) ;
2256 }
2257 if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
2258 this.CcndId = new PublisherPublicKeyDigest();
2259 this.CcndId.from_ccnb(decoder);
2260 }
2261 if (decoder.peekStartElement(CCNProtocolDTags.FaceID)) {
2262 this.faceID = decoder.readIntegerElement(CCNProtocolDTags.FaceID);
2263 }
2264 if (decoder.peekStartElement(CCNProtocolDTags.ForwardingFlags)) {
2265 this.flags = decoder.readIntegerElement(CCNProtocolDTags.ForwardingFlags);
2266 }
2267 if (decoder.peekStartElement(CCNProtocolDTags.FreshnessSeconds)) {
2268 this.lifetime = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
2269 }
2270 decoder.readEndElement();
2271 };
2272
2273 /**
2274 * Used by NetworkObject to encode the object to a network stream.
2275 */
2276ForwardingEntry.prototype.to_ccnb =function(
2277 //XMLEncoder
2278encoder)
2279{
2280
2281
2282 //if (!validate()) {
2283 //throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
2284 //}
2285 encoder.writeStartElement(this.getElementLabel());
2286 if (null != this.action && this.action.length != 0)
2287 encoder.writeElement(CCNProtocolDTags.Action, this.action);
2288 if (null != this.prefixName) {
2289 this.prefixName.to_ccnb(encoder);
2290 }
2291 if (null != this.CcndId) {
2292 this.CcndId.to_ccnb(encoder);
2293 }
2294 if (null != this.faceID) {
2295 encoder.writeElement(CCNProtocolDTags.FaceID, this.faceID);
2296 }
2297 if (null != this.flags) {
2298 encoder.writeElement(CCNProtocolDTags.ForwardingFlags, this.flags);
2299 }
2300 if (null != this.lifetime) {
2301 encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.lifetime);
2302 }
2303 encoder.writeEndElement();
2304 };
2305
2306ForwardingEntry.prototype.getElementLabel = function() { return CCNProtocolDTags.ForwardingEntry; }
Wentao Shangbd63e462012-12-03 16:19:33 -08002307/**
Jeff Thompson96978b42012-12-29 21:59:54 -08002308 * @author: Jeff Thompson
2309 * See COPYING for copyright and distribution information.
2310 * Encapsulate an Uint8Array and support dynamic reallocation.
2311 */
2312
2313/*
2314 * Create a DynamicUint8Array where this.array is a Uint8Array of size length.
2315 * If length is not supplied, use a default initial length.
2316 * The methods will update this.length.
2317 * To access the array, use this.array or call subarray.
2318 */
2319var DynamicUint8Array = function DynamicUint8Array(length) {
2320 if (!length)
2321 length = 16;
2322
2323 this.array = new Uint8Array(length);
2324 this.length = length;
2325};
2326
2327/*
2328 * Ensure that this.array has the length, reallocate and copy if necessary.
2329 * Update this.length which may be greater than length.
2330 */
2331DynamicUint8Array.prototype.ensureLength = function(length) {
2332 if (this.array.length >= length)
2333 return;
2334
2335 // See if double is enough.
2336 var newLength = this.array.length * 2;
2337 if (length > newLength)
2338 // The needed length is much greater, so use it.
2339 newLength = length;
2340
2341 var newArray = new Uint8Array(newLength);
2342 newArray.set(this.array);
2343 this.array = newArray;
2344 this.length = newLength;
2345};
2346
2347/*
2348 * Call this.array.set(value, offset), reallocating if necessary.
2349 */
2350DynamicUint8Array.prototype.set = function(value, offset) {
2351 this.ensureLength(value.length + offset);
2352 this.array.set(value, offset);
2353};
2354
2355/*
2356 * Return this.array.subarray(begin, end);
2357 */
2358DynamicUint8Array.prototype.subarray = function(begin, end) {
2359 return this.array.subarray(begin, end);
2360}
2361/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002362 * This class is used to encode ccnb binary elements (blob, type/value pairs).
2363 *
2364 * @author: Meki Cheraoui
2365 * See COPYING for copyright and distribution information.
2366 */
2367
2368var XML_EXT = 0x00;
2369
2370var XML_TAG = 0x01;
2371
2372var XML_DTAG = 0x02;
2373
2374var XML_ATTR = 0x03;
2375
2376var XML_DATTR = 0x04;
2377
2378var XML_BLOB = 0x05;
2379
2380var XML_UDATA = 0x06;
2381
2382var XML_CLOSE = 0x0;
2383
2384var XML_SUBTYPE_PROCESSING_INSTRUCTIONS = 16;
2385
2386
2387var XML_TT_BITS = 3;
2388var XML_TT_MASK = ((1 << XML_TT_BITS) - 1);
2389var XML_TT_VAL_BITS = XML_TT_BITS + 1;
2390var XML_TT_VAL_MASK = ((1 << (XML_TT_VAL_BITS)) - 1);
2391var XML_REG_VAL_BITS = 7;
2392var XML_REG_VAL_MASK = ((1 << XML_REG_VAL_BITS) - 1);
2393var XML_TT_NO_MORE = (1 << XML_REG_VAL_BITS); // 0x80
2394var BYTE_MASK = 0xFF;
2395var LONG_BYTES = 8;
2396var LONG_BITS = 64;
2397
2398var bits_11 = 0x0000007FF;
2399var bits_18 = 0x00003FFFF;
2400var bits_32 = 0x0FFFFFFFF;
2401
2402
2403var BinaryXMLEncoder = function BinaryXMLEncoder(){
Jeff Thompson96978b42012-12-29 21:59:54 -08002404 this.ostream = new DynamicUint8Array(100);
Wentao Shang0e291c82012-12-02 23:36:29 -08002405 this.offset =0;
2406 this.CODEC_NAME = "Binary";
2407};
2408
2409/*
2410 * Encode utf8Content as utf8.
2411 */
2412BinaryXMLEncoder.prototype.writeUString = function(/*String*/ utf8Content) {
2413 this.encodeUString(utf8Content, XML_UDATA);
2414};
2415
2416
2417BinaryXMLEncoder.prototype.writeBlob = function(
2418 /*Uint8Array*/ binaryContent
2419 ) {
2420
2421 if(LOG >3) console.log(binaryContent);
2422
2423 this.encodeBlob(binaryContent, binaryContent.length);
2424};
2425
2426
2427BinaryXMLEncoder.prototype.writeStartElement = function(
2428 /*String*/ tag,
2429 /*TreeMap<String,String>*/ attributes
2430 ) {
2431
2432 /*Long*/ var dictionaryVal = tag; //stringToTag(tag);
2433
2434 if (null == dictionaryVal) {
2435 this.encodeUString(tag, XML_TAG);
2436 } else {
2437 this.encodeTypeAndVal(XML_DTAG, dictionaryVal);
2438 }
2439
2440 if (null != attributes) {
2441 this.writeAttributes(attributes);
2442 }
2443};
2444
2445
2446BinaryXMLEncoder.prototype.writeEndElement = function() {
Jeff Thompson96978b42012-12-29 21:59:54 -08002447 this.ostream.ensureLength(this.offset + 1);
2448 this.ostream.array[this.offset] = XML_CLOSE;
Wentao Shang0e291c82012-12-02 23:36:29 -08002449 this.offset += 1;
2450}
2451
2452
2453BinaryXMLEncoder.prototype.writeAttributes = function(/*TreeMap<String,String>*/ attributes) {
2454 if (null == attributes) {
2455 return;
2456 }
2457
2458 // the keySet of a TreeMap is sorted.
2459
2460 for(var i=0; i<attributes.length;i++){
2461 var strAttr = attributes[i].k;
2462 var strValue = attributes[i].v;
2463
2464 var dictionaryAttr = stringToTag(strAttr);
2465 if (null == dictionaryAttr) {
2466 // not in dictionary, encode as attr
2467 // compressed format wants length of tag represented as length-1
2468 // to save that extra bit, as tag cannot be 0 length.
2469 // encodeUString knows to do that.
2470 this.encodeUString(strAttr, XML_ATTR);
2471 } else {
2472 this.encodeTypeAndVal(XML_DATTR, dictionaryAttr);
2473 }
2474 // Write value
2475 this.encodeUString(strValue);
2476
2477 }
2478}
2479
2480
2481//returns a string
2482stringToTag = function(/*long*/ tagVal) {
2483 if ((tagVal >= 0) && (tagVal < CCNProtocolDTagsStrings.length)) {
2484 return CCNProtocolDTagsStrings[tagVal];
2485 } else if (tagVal == CCNProtocolDTags.CCNProtocolDataUnit) {
2486 return CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT;
2487 }
2488 return null;
2489};
2490
2491//returns a Long
2492tagToString = function(/*String*/ tagName) {
2493 // the slow way, but right now we don't care.... want a static lookup for the forward direction
2494 for (var i=0; i < CCNProtocolDTagsStrings.length; ++i) {
2495 if ((null != CCNProtocolDTagsStrings[i]) && (CCNProtocolDTagsStrings[i] == tagName)) {
2496 return i;
2497 }
2498 }
2499 if (CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT == tagName) {
2500 return CCNProtocolDTags.CCNProtocolDataUnit;
2501 }
2502 return null;
2503};
2504
2505/*
2506 * If Content is a string, then encode as utf8 and write UDATA.
2507 */
2508BinaryXMLEncoder.prototype.writeElement = function(
2509 //long
2510 tag,
2511 //byte[]
2512 Content,
2513 //TreeMap<String, String>
2514 attributes
2515 ) {
2516 this.writeStartElement(tag, attributes);
2517 // Will omit if 0-length
2518
2519 if(typeof Content === 'number') {
2520 if(LOG>4) console.log('GOING TO WRITE THE NUMBER .charCodeAt(0) ' + Content.toString().charCodeAt(0) );
2521 if(LOG>4) console.log('GOING TO WRITE THE NUMBER ' + Content.toString() );
2522 if(LOG>4) console.log('type of number is ' + typeof Content.toString() );
2523
2524 this.writeUString(Content.toString());
2525 //whatever
2526 }
2527 else if(typeof Content === 'string'){
2528 if(LOG>4) console.log('GOING TO WRITE THE STRING ' + Content );
2529 if(LOG>4) console.log('type of STRING is ' + typeof Content );
2530
2531 this.writeUString(Content);
2532 }
2533 else{
2534 if(LOG>4) console.log('GOING TO WRITE A BLOB ' + Content );
2535
2536 this.writeBlob(Content);
2537 }
2538
2539 this.writeEndElement();
2540}
2541
2542
2543
2544var TypeAndVal = function TypeAndVal(_type,_val) {
2545 this.type = _type;
2546 this.val = _val;
2547
2548};
2549
2550
2551BinaryXMLEncoder.prototype.encodeTypeAndVal = function(
2552 //int
2553 type,
2554 //long
2555 val
2556 ) {
2557
2558 if(LOG>4) console.log('Encoding type '+ type+ ' and value '+ val);
2559
2560 if(LOG>4) console.log('OFFSET IS ' + this.offset);
2561
2562 if ((type > XML_UDATA) || (type < 0) || (val < 0)) {
2563 throw new Error("Tag and value must be positive, and tag valid.");
2564 }
2565
2566 // Encode backwards. Calculate how many bytes we need:
2567 var numEncodingBytes = this.numEncodingBytes(val);
Jeff Thompson96978b42012-12-29 21:59:54 -08002568 this.ostream.ensureLength(this.offset + numEncodingBytes);
Wentao Shang0e291c82012-12-02 23:36:29 -08002569
2570 // Bottom 4 bits of val go in last byte with tag.
Jeff Thompson96978b42012-12-29 21:59:54 -08002571 this.ostream.array[this.offset + numEncodingBytes - 1] =
Wentao Shang0e291c82012-12-02 23:36:29 -08002572 //(byte)
2573 (BYTE_MASK &
2574 (((XML_TT_MASK & type) |
2575 ((XML_TT_VAL_MASK & val) << XML_TT_BITS))) |
2576 XML_TT_NO_MORE); // set top bit for last byte
Jeff Thompson96978b42012-12-29 21:59:54 -08002577 val = val >>> XML_TT_VAL_BITS;
Wentao Shang0e291c82012-12-02 23:36:29 -08002578
2579 // Rest of val goes into preceding bytes, 7 bits per byte, top bit
2580 // is "more" flag.
2581 var i = this.offset + numEncodingBytes - 2;
2582 while ((0 != val) && (i >= this.offset)) {
Jeff Thompson96978b42012-12-29 21:59:54 -08002583 this.ostream.array[i] = //(byte)
Wentao Shang0e291c82012-12-02 23:36:29 -08002584 (BYTE_MASK & (val & XML_REG_VAL_MASK)); // leave top bit unset
2585 val = val >>> XML_REG_VAL_BITS;
2586 --i;
2587 }
2588 if (val != 0) {
2589 throw new Error( "This should not happen: miscalculated encoding");
2590 //Log.warning(Log.FAC_ENCODING, "This should not happen: miscalculated encoding length, have " + val + " left.");
2591 }
2592 this.offset+= numEncodingBytes;
2593
2594 return numEncodingBytes;
2595};
2596
2597/*
2598 * Encode ustring as utf8.
2599 */
2600BinaryXMLEncoder.prototype.encodeUString = function(
2601 //String
2602 ustring,
2603 //byte
2604 type) {
2605
2606 if (null == ustring)
2607 return;
2608 if (type == XML_TAG || type == XML_ATTR && ustring.length == 0)
2609 return;
2610
2611 if(LOG>3) console.log("The string to write is ");
2612 if(LOG>3) console.log(ustring);
2613
2614 var strBytes = DataUtils.stringToUtf8Array(ustring);
2615
2616 this.encodeTypeAndVal(type,
2617 (((type == XML_TAG) || (type == XML_ATTR)) ?
2618 (strBytes.length-1) :
2619 strBytes.length));
2620
2621 if(LOG>3) console.log("THE string to write is ");
2622
2623 if(LOG>3) console.log(strBytes);
2624
Jeff Thompson96978b42012-12-29 21:59:54 -08002625 this.writeString(strBytes);
Wentao Shang0e291c82012-12-02 23:36:29 -08002626 this.offset+= strBytes.length;
2627};
2628
2629
2630
2631BinaryXMLEncoder.prototype.encodeBlob = function(
2632 //Uint8Array
2633 blob,
2634 //int
2635 length) {
2636
2637
2638 if (null == blob)
2639 return;
2640
2641 if(LOG>4) console.log('LENGTH OF XML_BLOB IS '+length);
2642
2643 /*blobCopy = new Array(blob.Length);
2644
2645 for (i = 0; i < blob.length; i++) //in InStr.ToCharArray())
2646 {
2647 blobCopy[i] = blob[i];
2648 }*/
2649
2650 this.encodeTypeAndVal(XML_BLOB, length);
2651
Jeff Thompson96978b42012-12-29 21:59:54 -08002652 this.writeBlobArray(blob);
Wentao Shang0e291c82012-12-02 23:36:29 -08002653 this.offset += length;
2654};
2655
2656var ENCODING_LIMIT_1_BYTE = ((1 << (XML_TT_VAL_BITS)) - 1);
2657var ENCODING_LIMIT_2_BYTES = ((1 << (XML_TT_VAL_BITS + XML_REG_VAL_BITS)) - 1);
2658var ENCODING_LIMIT_3_BYTES = ((1 << (XML_TT_VAL_BITS + 2 * XML_REG_VAL_BITS)) - 1);
2659
2660BinaryXMLEncoder.prototype.numEncodingBytes = function(
2661 //long
2662 x) {
2663 if (x <= ENCODING_LIMIT_1_BYTE) return (1);
2664 if (x <= ENCODING_LIMIT_2_BYTES) return (2);
2665 if (x <= ENCODING_LIMIT_3_BYTES) return (3);
2666
2667 var numbytes = 1;
2668
2669 // Last byte gives you XML_TT_VAL_BITS
2670 // Remainder each give you XML_REG_VAL_BITS
2671 x = x >>> XML_TT_VAL_BITS;
2672 while (x != 0) {
2673 numbytes++;
2674 x = x >>> XML_REG_VAL_BITS;
2675 }
2676 return (numbytes);
2677};
2678
2679BinaryXMLEncoder.prototype.writeDateTime = function(
2680 //String
2681 tag,
2682 //CCNTime
2683 dateTime) {
2684
2685 if(LOG>4)console.log('ENCODING DATE with LONG VALUE');
2686 if(LOG>4)console.log(dateTime.msec);
2687
2688 //var binarydate = DataUtils.unsignedLongToByteArray( Math.round((dateTime.msec/1000) * 4096) );
2689
2690
2691 //parse to hex
2692 var binarydate = Math.round((dateTime.msec/1000) * 4096).toString(16) ;
2693
2694 //HACK
2695 var binarydate = DataUtils.toNumbers( '0'.concat(binarydate,'0')) ;
2696
2697
2698 if(LOG>4)console.log('ENCODING DATE with BINARY VALUE');
2699 if(LOG>4)console.log(binarydate);
2700 if(LOG>4)console.log('ENCODING DATE with BINARY VALUE(HEX)');
2701 if(LOG>4)console.log(DataUtils.toHex(binarydate));
2702
2703 this.writeElement(tag, binarydate);
2704};
2705
Jeff Thompson96978b42012-12-29 21:59:54 -08002706// This does not update this.offset.
2707BinaryXMLEncoder.prototype.writeString = function(input) {
Wentao Shang0e291c82012-12-02 23:36:29 -08002708
2709 if(typeof input === 'string'){
2710 //console.log('went here');
2711 if(LOG>4) console.log('GOING TO WRITE A STRING');
2712 if(LOG>4) console.log(input);
2713
Jeff Thompson96978b42012-12-29 21:59:54 -08002714 this.ostream.ensureLength(this.offset + input.length);
2715 for (var i = 0; i < input.length; i++) {
Wentao Shang0e291c82012-12-02 23:36:29 -08002716 if(LOG>4) console.log('input.charCodeAt(i)=' + input.charCodeAt(i));
Jeff Thompson96978b42012-12-29 21:59:54 -08002717 this.ostream.array[this.offset + i] = (input.charCodeAt(i));
Wentao Shang0e291c82012-12-02 23:36:29 -08002718 }
2719 }
2720 else{
2721 if(LOG>4) console.log('GOING TO WRITE A STRING IN BINARY FORM');
2722 if(LOG>4) console.log(input);
2723
2724 this.writeBlobArray(input);
2725 }
2726 /*
2727 else if(typeof input === 'object'){
2728
2729 }
2730 */
2731};
2732
2733
2734BinaryXMLEncoder.prototype.writeBlobArray = function(
2735 //Uint8Array
Jeff Thompson96978b42012-12-29 21:59:54 -08002736 blob) {
Wentao Shang0e291c82012-12-02 23:36:29 -08002737
2738 if(LOG>4) console.log('GOING TO WRITE A BLOB');
2739
Wentao Shang0e291c82012-12-02 23:36:29 -08002740 this.ostream.set(blob, this.offset);
2741};
2742
2743
2744BinaryXMLEncoder.prototype.getReducedOstream = function() {
2745 return this.ostream.subarray(0, this.offset);
2746};
2747
Wentao Shangbd63e462012-12-03 16:19:33 -08002748/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002749 * This class is used to decode ccnb binary elements (blob, type/value pairs).
2750 *
2751 * @author: Meki Cheraoui
2752 * See COPYING for copyright and distribution information.
2753 */
2754
2755var XML_EXT = 0x00;
2756
2757var XML_TAG = 0x01;
2758
2759var XML_DTAG = 0x02;
2760
2761var XML_ATTR = 0x03;
2762
2763var XML_DATTR = 0x04;
2764
2765var XML_BLOB = 0x05;
2766
2767var XML_UDATA = 0x06;
2768
2769var XML_CLOSE = 0x0;
2770
2771var XML_SUBTYPE_PROCESSING_INSTRUCTIONS = 16;
2772
2773
2774var XML_TT_BITS = 3;
2775var XML_TT_MASK = ((1 << XML_TT_BITS) - 1);
2776var XML_TT_VAL_BITS = XML_TT_BITS + 1;
2777var XML_TT_VAL_MASK = ((1 << (XML_TT_VAL_BITS)) - 1);
2778var XML_REG_VAL_BITS = 7;
2779var XML_REG_VAL_MASK = ((1 << XML_REG_VAL_BITS) - 1);
2780var XML_TT_NO_MORE = (1 << XML_REG_VAL_BITS); // 0x80
2781var BYTE_MASK = 0xFF;
2782var LONG_BYTES = 8;
2783var LONG_BITS = 64;
2784
2785var bits_11 = 0x0000007FF;
2786var bits_18 = 0x00003FFFF;
2787var bits_32 = 0x0FFFFFFFF;
2788
2789
2790
2791//returns a string
2792tagToString = function(/*long*/ tagVal) {
2793 if ((tagVal >= 0) && (tagVal < CCNProtocolDTagsStrings.length)) {
2794 return CCNProtocolDTagsStrings[tagVal];
2795 } else if (tagVal == CCNProtocolDTags.CCNProtocolDataUnit) {
2796 return CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT;
2797 }
2798 return null;
2799};
2800
2801//returns a Long
2802stringToTag = function(/*String*/ tagName) {
2803 // the slow way, but right now we don't care.... want a static lookup for the forward direction
2804 for (var i=0; i < CCNProtocolDTagsStrings.length; ++i) {
2805 if ((null != CCNProtocolDTagsStrings[i]) && (CCNProtocolDTagsStrings[i] == tagName)) {
2806 return i;
2807 }
2808 }
2809 if (CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT == tagName) {
2810 return CCNProtocolDTags.CCNProtocolDataUnit;
2811 }
2812 return null;
2813};
2814
2815//console.log(stringToTag(64));
2816var BinaryXMLDecoder = function BinaryXMLDecoder(istream){
2817 var MARK_LEN=512;
2818 var DEBUG_MAX_LEN = 32768;
2819
2820 this.istream = istream;
2821 this.offset = 0;
2822};
2823
Wentao Shang0e291c82012-12-02 23:36:29 -08002824BinaryXMLDecoder.prototype.initializeDecoding = function() {
2825 //if (!this.istream.markSupported()) {
2826 //throw new IllegalArgumentException(this.getClass().getName() + ": input stream must support marking!");
2827 //}
2828}
2829
2830BinaryXMLDecoder.prototype.readStartDocument = function(){
2831 // Currently no start document in binary encoding.
2832 }
2833
2834BinaryXMLDecoder.prototype.readEndDocument = function() {
2835 // Currently no end document in binary encoding.
2836 };
2837
2838BinaryXMLDecoder.prototype.readStartElement = function(
2839 //String
2840 startTag,
2841 //TreeMap<String, String>
2842 attributes) {
2843
2844
2845 //NOT SURE
2846 //if(typeof startTag == 'number')
2847 //startTag = tagToString(startTag);
2848
2849 //TypeAndVal
Jeff Thompson48ff28a2013-02-18 22:53:29 -08002850 var tv = this.decodeTypeAndVal();
Wentao Shang0e291c82012-12-02 23:36:29 -08002851
2852 if (null == tv) {
2853 throw new ContentDecodingException(new Error("Expected start element: " + startTag + " got something not a tag."));
2854 }
2855
2856 //String
2857 var decodedTag = null;
2858 //console.log(tv);
2859 //console.log(typeof tv);
2860
2861 //console.log(XML_TAG);
2862 if (tv.type() == XML_TAG) {
2863 //console.log('got here');
2864 //Log.info(Log.FAC_ENCODING, "Unexpected: got tag in readStartElement; looking for tag " + startTag + " got length: " + (int)tv.val()+1);
2865 // Tag value represents length-1 as tags can never be empty.
2866 var valval ;
2867 if(typeof tv.val() == 'string'){
2868 valval = (parseInt(tv.val())) + 1;
2869 }
2870 else
2871 valval = (tv.val())+ 1;
2872
2873 //console.log('valval is ' +valval);
2874
2875 decodedTag = this.decodeUString(valval);
2876
2877 } else if (tv.type() == XML_DTAG) {
2878 //console.log('gothere');
2879 //console.log(tv.val());
2880 //decodedTag = tagToString(tv.val());
2881 //console.log()
2882 decodedTag = tv.val();
2883 }
2884
2885 //console.log(decodedTag);
2886 //console.log('startTag is '+startTag);
2887
2888
2889 if ((null == decodedTag) || decodedTag != startTag ) {
2890 console.log('expecting '+ startTag + ' but got '+ decodedTag);
2891 throw new ContentDecodingException(new Error("Expected start element: " + startTag + " got: " + decodedTag + "(" + tv.val() + ")"));
2892 }
2893
2894 // DKS: does not read attributes out of stream if caller doesn't
2895 // ask for them. Should possibly peek and skip over them regardless.
2896 // TODO: fix this
2897 if (null != attributes) {
2898 readAttributes(attributes);
2899 }
2900 }
2901
2902
2903BinaryXMLDecoder.prototype.readAttributes = function(
Jeff Thompson48ff28a2013-02-18 22:53:29 -08002904 // array of [attributeName, attributeValue]
Wentao Shang0e291c82012-12-02 23:36:29 -08002905 attributes) {
2906
2907 if (null == attributes) {
2908 return;
2909 }
2910
2911 try {
2912 // Now need to get attributes.
2913 //TypeAndVal
2914 var nextTV = this.peekTypeAndVal();
2915
2916 while ((null != nextTV) && ((XML_ATTR == nextTV.type()) ||
2917 (XML_DATTR == nextTV.type()))) {
2918
2919 // Decode this attribute. First, really read the type and value.
2920 //this.TypeAndVal
2921 var thisTV = this.decodeTypeAndVal();
2922
2923 //String
2924 var attributeName = null;
2925 if (XML_ATTR == thisTV.type()) {
2926 // Tag value represents length-1 as attribute names cannot be empty.
2927 var valval ;
Jeff Thompson48ff28a2013-02-18 22:53:29 -08002928 if(typeof thisTV.val() == 'string'){
2929 valval = (parseInt(thisTV.val())) + 1;
Wentao Shang0e291c82012-12-02 23:36:29 -08002930 }
2931 else
Jeff Thompson48ff28a2013-02-18 22:53:29 -08002932 valval = (thisTV.val())+ 1;
Wentao Shang0e291c82012-12-02 23:36:29 -08002933
2934 attributeName = this.decodeUString(valval);
2935
2936 } else if (XML_DATTR == thisTV.type()) {
2937 // DKS TODO are attributes same or different dictionary?
2938 attributeName = tagToString(thisTV.val());
2939 if (null == attributeName) {
2940 throw new ContentDecodingException(new Error("Unknown DATTR value" + thisTV.val()));
2941 }
2942 }
2943 // Attribute values are always UDATA
2944 //String
2945 var attributeValue = this.decodeUString();
2946
2947 //
2948 attributes.push([attributeName, attributeValue]);
2949
2950 nextTV = this.peekTypeAndVal();
2951 }
2952 } catch ( e) {
2953 throw new ContentDecodingException(new Error("readStartElement", e));
2954 }
2955};
2956
2957//returns a string
2958BinaryXMLDecoder.prototype.peekStartElementAsString = function() {
2959 //this.istream.mark(MARK_LEN);
2960
2961 //String
2962 var decodedTag = null;
2963 var previousOffset = this.offset;
2964 try {
2965 // Have to distinguish genuine errors from wrong tags. Could either use
2966 // a special exception subtype, or redo the work here.
2967 //this.TypeAndVal
2968 var tv = this.decodeTypeAndVal();
2969
2970 if (null != tv) {
2971
2972 if (tv.type() == XML_TAG) {
2973 /*if (tv.val()+1 > DEBUG_MAX_LEN) {
2974 throw new ContentDecodingException(new Error("Decoding error: length " + tv.val()+1 + " longer than expected maximum length!")(;
2975 }*/
2976
2977 // Tag value represents length-1 as tags can never be empty.
2978 var valval ;
2979 if(typeof tv.val() == 'string'){
2980 valval = (parseInt(tv.val())) + 1;
2981 }
2982 else
2983 valval = (tv.val())+ 1;
2984
2985 decodedTag = this.decodeUString(valval);
2986
2987 //Log.info(Log.FAC_ENCODING, "Unexpected: got text tag in peekStartElement; length: " + valval + " decoded tag = " + decodedTag);
2988
2989 } else if (tv.type() == XML_DTAG) {
2990 decodedTag = tagToString(tv.val());
2991 }
2992
2993 } // else, not a type and val, probably an end element. rewind and return false.
2994
2995 } catch ( e) {
2996
2997 } finally {
2998 try {
2999 this.offset = previousOffset;
3000 } catch ( e) {
3001 Log.logStackTrace(Log.FAC_ENCODING, Level.WARNING, e);
3002 throw new ContentDecodingException(new Error("Cannot reset stream! " + e.getMessage(), e));
3003 }
3004 }
3005 return decodedTag;
3006};
3007
3008BinaryXMLDecoder.prototype.peekStartElement = function(
3009 //String
3010 startTag) {
3011 //String
3012 if(typeof startTag == 'string'){
3013 var decodedTag = this.peekStartElementAsString();
3014
3015 if ((null != decodedTag) && decodedTag == startTag) {
3016 return true;
3017 }
3018 return false;
3019 }
3020 else if(typeof startTag == 'number'){
3021 var decodedTag = this.peekStartElementAsLong();
3022 if ((null != decodedTag) && decodedTag == startTag) {
3023 return true;
3024 }
3025 return false;
3026 }
3027 else{
3028 throw new ContentDecodingException(new Error("SHOULD BE STRING OR NUMBER"));
3029 }
3030}
3031//returns Long
3032BinaryXMLDecoder.prototype.peekStartElementAsLong = function() {
3033 //this.istream.mark(MARK_LEN);
3034
3035 //Long
3036 var decodedTag = null;
3037
3038 var previousOffset = this.offset;
3039
3040 try {
3041 // Have to distinguish genuine errors from wrong tags. Could either use
3042 // a special exception subtype, or redo the work here.
3043 //this.TypeAndVal
3044 var tv = this.decodeTypeAndVal();
3045
3046 if (null != tv) {
3047
3048 if (tv.type() == XML_TAG) {
3049 if (tv.val()+1 > DEBUG_MAX_LEN) {
3050 throw new ContentDecodingException(new Error("Decoding error: length " + tv.val()+1 + " longer than expected maximum length!"));
3051 }
3052
3053 var valval ;
3054 if(typeof tv.val() == 'string'){
3055 valval = (parseInt(tv.val())) + 1;
3056 }
3057 else
3058 valval = (tv.val())+ 1;
3059
3060 // Tag value represents length-1 as tags can never be empty.
3061 //String
3062 var strTag = this.decodeUString(valval);
3063
3064 decodedTag = stringToTag(strTag);
3065
3066 //Log.info(Log.FAC_ENCODING, "Unexpected: got text tag in peekStartElement; length: " + valval + " decoded tag = " + decodedTag);
3067
3068 } else if (tv.type() == XML_DTAG) {
3069 decodedTag = tv.val();
3070 }
3071
3072 } // else, not a type and val, probably an end element. rewind and return false.
3073
3074 } catch ( e) {
3075
3076 } finally {
3077 try {
3078 //this.istream.reset();
3079 this.offset = previousOffset;
3080 } catch ( e) {
3081 Log.logStackTrace(Log.FAC_ENCODING, Level.WARNING, e);
3082 throw new Error("Cannot reset stream! " + e.getMessage(), e);
3083 }
3084 }
3085 return decodedTag;
3086 };
3087
3088
3089// returns a byte[]
3090BinaryXMLDecoder.prototype.readBinaryElement = function(
3091 //long
3092 startTag,
3093 //TreeMap<String, String>
3094 attributes){
3095 //byte []
3096 var blob = null;
3097
3098 this.readStartElement(startTag, attributes);
3099 blob = this.readBlob();
3100
3101 return blob;
3102};
3103
3104
3105BinaryXMLDecoder.prototype.readEndElement = function(){
3106 if(LOG>4)console.log('this.offset is '+this.offset);
3107
3108 var next = this.istream[this.offset];
3109
3110 this.offset++;
3111 //read();
3112
3113 if(LOG>4)console.log('XML_CLOSE IS '+XML_CLOSE);
3114 if(LOG>4)console.log('next is '+next);
3115
3116 if (next != XML_CLOSE) {
3117 console.log("Expected end element, got: " + next);
3118 throw new ContentDecodingException(new Error("Expected end element, got: " + next));
3119 }
3120 };
3121
3122
3123//String
3124BinaryXMLDecoder.prototype.readUString = function(){
3125 //String
3126 var ustring = this.decodeUString();
3127 this.readEndElement();
3128 return ustring;
3129
3130 };
3131
3132
Wentao Shang882e34e2013-01-05 02:49:51 -08003133//returns a uint8array
Wentao Shang0e291c82012-12-02 23:36:29 -08003134BinaryXMLDecoder.prototype.readBlob = function() {
Wentao Shang882e34e2013-01-05 02:49:51 -08003135 //uint8array
Wentao Shang0e291c82012-12-02 23:36:29 -08003136
3137 var blob = this.decodeBlob();
3138 this.readEndElement();
3139 return blob;
3140
3141 };
3142
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() {
7775 if (LOG > 3) 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) {
7787 if (LOG > 3) console.log("Re-express interest: " + interest.name.to_uri());
7788 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 Thompsona5668d52013-01-26 16:23:27 -08008075 if (LOG>3) console.log("Connect: 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 Thompsona5668d52013-01-26 16:23:27 -08008083 if (LOG>3) console.log("Connect: 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 Thompsona5668d52013-01-26 16:23:27 -08008114 this.onConnected();
Wentao Shangb42483a2013-01-03 15:32:32 -08008115
8116 return Closure.RESULT_OK;
8117};
8118
Jeff Thompsona46083c2013-01-20 23:55:21 -08008119/*
8120 * A BinaryXmlElementReader lets you call onReceivedData multiple times which uses a
8121 * BinaryXMLStructureDecoder to detect the end of a binary XML element and calls
8122 * elementListener.onReceivedElement(element) with the element.
8123 * This handles the case where a single call to onReceivedData may contain multiple elements.
8124 */
8125var BinaryXmlElementReader = function BinaryXmlElementReader(elementListener) {
8126 this.elementListener = elementListener;
8127 this.dataParts = [];
8128 this.structureDecoder = new BinaryXMLStructureDecoder();
8129};
8130
8131BinaryXmlElementReader.prototype.onReceivedData = function(/* Uint8Array */ rawData) {
8132 // Process multiple objects in the data.
8133 while(true) {
8134 // Scan the input to check if a whole ccnb object has been read.
8135 this.structureDecoder.seek(0);
8136 if (this.structureDecoder.findElementEnd(rawData)) {
8137 // Got the remainder of an object. Report to the caller.
8138 this.dataParts.push(rawData.subarray(0, this.structureDecoder.offset));
Jeff Thompson537ce142013-01-26 20:02:48 -08008139 var element = DataUtils.concatArrays(this.dataParts);
8140 this.dataParts = [];
8141 try {
8142 this.elementListener.onReceivedElement(element);
8143 } catch (ex) {
8144 console.log("BinaryXmlElementReader: ignoring exception from onReceivedElement: " + ex);
8145 }
Jeff Thompsona46083c2013-01-20 23:55:21 -08008146
8147 // Need to read a new object.
8148 rawData = rawData.subarray(this.structureDecoder.offset, rawData.length);
Jeff Thompsona46083c2013-01-20 23:55:21 -08008149 this.structureDecoder = new BinaryXMLStructureDecoder();
8150 if (rawData.length == 0)
8151 // No more data in the packet.
8152 return;
8153
8154 // else loop back to decode.
8155 }
8156 else {
8157 // Save for a later call to concatArrays so that we only copy data once.
8158 this.dataParts.push(rawData);
8159 if (LOG>3) console.log('Incomplete packet received. Length ' + rawData.length + '. Wait for more input.');
8160 return;
8161 }
8162 }
8163}