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