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