blob: 04700e798134b3b6c7d107fb189f56f2c3662cf3 [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){
Wentao Shang0e291c82012-12-02 23:36:29 -08001432 this.OPTIMUM_FILTER_SIZE = 100;
Wentao Shang0e291c82012-12-02 23:36:29 -08001433 this.values = _values; //array of elements
Wentao Shang0e291c82012-12-02 23:36:29 -08001434}
1435
1436Exclude.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
Wentao Shang0e291c82012-12-02 23:36:29 -08001437 decoder.readStartElement(this.getElementLabel());
1438
Jeff Thompsonfced4c22013-01-27 16:34:13 -08001439 //TODO APPLY FILTERS/EXCLUDE. For now, just skip the element.
1440 var structureDecoder = new BinaryXMLStructureDecoder();
1441 structureDecoder.seek(decoder.offset);
1442 if (!structureDecoder.findElementEnd(decoder.istream))
1443 throw new ContentDecodingException(new Error("Cannot find the end of interest Exclude element"));
1444 decoder.seek(structureDecoder.offset);
1445
Wentao Shang0e291c82012-12-02 23:36:29 -08001446 //TODO
1447 /*var component;
1448 var any = false;
1449 while ((component = decoder.peekStartElement(CCNProtocolDTags.Component)) ||
1450 (any = decoder.peekStartElement(CCNProtocolDTags.Any)) ||
1451 decoder.peekStartElement(CCNProtocolDTags.Bloom)) {
1452 var ee = component?new ExcludeComponent(): any ? new ExcludeAny() : new BloomFilter();
1453 ee.decode(decoder);
1454 _values.add(ee);
1455 }*/
Wentao Shang0e291c82012-12-02 23:36:29 -08001456};
1457
1458Exclude.prototype.to_ccnb=function(/*XMLEncoder*/ encoder) {
1459 if (!validate()) {
1460 throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
1461 }
1462
1463 if (empty())
1464 return;
1465
1466 encoder.writeStartElement(getElementLabel());
1467
1468 encoder.writeEndElement();
1469
1470 };
1471
1472Exclude.prototype.getElementLabel = function() { return CCNProtocolDTags.Exclude; };
1473
1474
1475/**
1476 * ExcludeAny
1477 */
1478var ExcludeAny = function ExcludeAny() {
1479
1480};
1481
1482ExcludeAny.prototype.from_ccnb = function(decoder) {
1483 decoder.readStartElement(this.getElementLabel());
1484 decoder.readEndElement();
1485};
1486
1487
1488ExcludeAny.prototype.to_ccnb = function( encoder) {
1489 encoder.writeStartElement(this.getElementLabel());
1490 encoder.writeEndElement();
1491};
1492
1493ExcludeAny.prototype.getElementLabel=function() { return CCNProtocolDTags.Any; };
1494
1495
1496/**
1497 * ExcludeComponent
1498 */
1499var ExcludeComponent = function ExcludeComponent(_body) {
1500
1501 //TODO Check BODY is an Array of componenets.
1502
1503 this.body = _body
1504};
1505
1506ExcludeComponent.prototype.from_ccnb = function( decoder) {
1507 this.body = decoder.readBinaryElement(this.getElementLabel());
1508};
1509
1510ExcludeComponent.prototype.to_ccnb = function(encoder) {
1511 encoder.writeElement(this.getElementLabel(), this.body);
1512};
1513
1514ExcludeComponent.prototype.getElementLabel = function() { return CCNProtocolDTags.Component; };
Wentao Shangbd63e462012-12-03 16:19:33 -08001515/**
Wentao Shang0e291c82012-12-02 23:36:29 -08001516 * @author: Meki Cheraoui
1517 * See COPYING for copyright and distribution information.
1518 * This class represents Key Objects
1519 */
1520
1521var Key = function Key(){
1522 /* TODO: Port from PyCCN:
1523 generateRSA()
1524 privateToDER()
1525 publicToDER()
1526 privateToPEM()
1527 publicToPEM()
1528 fromDER()
1529 fromPEM()
1530 */
1531}
1532
1533/**
1534 * KeyLocator
1535 */
1536var KeyLocatorType = {
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08001537 KEY:1,
1538 CERTIFICATE:2,
1539 KEYNAME:3
Wentao Shang0e291c82012-12-02 23:36:29 -08001540};
1541
1542var KeyLocator = function KeyLocator(_input,_type){
1543
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08001544 this.type = _type;
Wentao Shang0e291c82012-12-02 23:36:29 -08001545
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08001546 if (_type == KeyLocatorType.KEYNAME){
1547 if (LOG>3) console.log('KeyLocator: SET KEYNAME');
Wentao Shang0e291c82012-12-02 23:36:29 -08001548 this.keyName = _input;
1549 }
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08001550 else if (_type == KeyLocatorType.KEY){
1551 if (LOG>3) console.log('KeyLocator: SET KEY');
Wentao Shang0e291c82012-12-02 23:36:29 -08001552 this.publicKey = _input;
1553 }
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08001554 else if (_type == KeyLocatorType.CERTIFICATE){
1555 if (LOG>3) console.log('KeyLocator: SET CERTIFICATE');
Wentao Shang0e291c82012-12-02 23:36:29 -08001556 this.certificate = _input;
1557 }
1558
1559};
1560
1561KeyLocator.prototype.from_ccnb = function(decoder) {
1562
Wentao Shang82854bd2012-12-27 14:14:41 -08001563 decoder.readStartElement(this.getElementLabel());
Wentao Shang0e291c82012-12-02 23:36:29 -08001564
Wentao Shang82854bd2012-12-27 14:14:41 -08001565 if (decoder.peekStartElement(CCNProtocolDTags.Key)) {
1566 try {
1567 encodedKey = decoder.readBinaryElement(CCNProtocolDTags.Key);
1568 // This is a DER-encoded SubjectPublicKeyInfo.
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08001569
Wentao Shang82854bd2012-12-27 14:14:41 -08001570 //TODO FIX THIS, This should create a Key Object instead of keeping bytes
1571
1572 this.publicKey = encodedKey;//CryptoUtil.getPublicKey(encodedKey);
1573 this.type = KeyLocatorType.KEY;
1574
1575
1576 if(LOG>4) console.log('PUBLIC KEY FOUND: '+ this.publicKey);
1577 //this.publicKey = encodedKey;
1578
1579
1580 } catch (e) {
1581 throw new Error("Cannot parse key: ", e);
1582 }
1583
1584 if (null == this.publicKey) {
1585 throw new Error("Cannot parse key: ");
Wentao Shang0e291c82012-12-02 23:36:29 -08001586 }
Wentao Shang82854bd2012-12-27 14:14:41 -08001587
1588 } else if ( decoder.peekStartElement(CCNProtocolDTags.Certificate)) {
1589 try {
1590 encodedCert = decoder.readBinaryElement(CCNProtocolDTags.Certificate);
1591
1592 /*
1593 * Certificates not yet working
1594 */
1595
1596 //CertificateFactory factory = CertificateFactory.getInstance("X.509");
1597 //this.certificate = (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(encodedCert));
1598
1599
1600 this.certificate = encodedCert;
1601 this.type = KeyLocatorType.CERTIFICATE;
1602
1603 if(LOG>4) console.log('CERTIFICATE FOUND: '+ this.certificate);
1604
1605 } catch ( e) {
1606 throw new Error("Cannot decode certificate: " + e);
1607 }
1608 if (null == this.certificate) {
1609 throw new Error("Cannot parse certificate! ");
1610 }
1611 } else {
1612 this.type = KeyLocatorType.KEYNAME;
1613
1614 this.keyName = new KeyName();
1615 this.keyName.from_ccnb(decoder);
Wentao Shang0e291c82012-12-02 23:36:29 -08001616 }
Wentao Shang82854bd2012-12-27 14:14:41 -08001617 decoder.readEndElement();
1618};
Wentao Shang0e291c82012-12-02 23:36:29 -08001619
1620
Wentao Shang82854bd2012-12-27 14:14:41 -08001621KeyLocator.prototype.to_ccnb = function( encoder) {
1622
1623 if(LOG>4) console.log('type is is ' + this.type);
1624 //TODO Check if Name is missing
1625 if (!this.validate()) {
1626 throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
1627 }
Wentao Shang0e291c82012-12-02 23:36:29 -08001628
Wentao Shang82854bd2012-12-27 14:14:41 -08001629
1630 //TODO FIX THIS TOO
1631 encoder.writeStartElement(this.getElementLabel());
1632
1633 if (this.type == KeyLocatorType.KEY) {
1634 if(LOG>5)console.log('About to encode a public key' +this.publicKey);
1635 encoder.writeElement(CCNProtocolDTags.Key, this.publicKey);
Wentao Shang0e291c82012-12-02 23:36:29 -08001636
Wentao Shang82854bd2012-12-27 14:14:41 -08001637 } else if (this.type == KeyLocatorType.CERTIFICATE) {
Wentao Shang0e291c82012-12-02 23:36:29 -08001638
Wentao Shang82854bd2012-12-27 14:14:41 -08001639 try {
1640 encoder.writeElement(CCNProtocolDTags.Certificate, this.certificate);
1641 } catch ( e) {
1642 throw new Error("CertificateEncodingException attempting to write key locator: " + e);
Wentao Shang0e291c82012-12-02 23:36:29 -08001643 }
Wentao Shang0e291c82012-12-02 23:36:29 -08001644
Wentao Shang82854bd2012-12-27 14:14:41 -08001645 } else if (this.type == KeyLocatorType.KEYNAME) {
1646
1647 this.keyName.to_ccnb(encoder);
1648 }
1649 encoder.writeEndElement();
1650
Wentao Shang0e291c82012-12-02 23:36:29 -08001651};
1652
1653KeyLocator.prototype.getElementLabel = function() {
1654 return CCNProtocolDTags.KeyLocator;
1655};
1656
1657KeyLocator.prototype.validate = function() {
1658 return ( (null != this.keyName) || (null != this.publicKey) || (null != this.certificate) );
1659};
1660
1661/**
1662 * KeyName is only used by KeyLocator.
1663 */
1664var KeyName = function KeyName() {
Wentao Shang98b595c2012-12-30 10:14:26 -08001665 this.contentName = this.contentName; //contentName
1666 this.publisherID = this.publisherID; //publisherID
Wentao Shang0e291c82012-12-02 23:36:29 -08001667
1668};
1669
1670KeyName.prototype.from_ccnb=function( decoder){
1671
1672
1673 decoder.readStartElement(this.getElementLabel());
1674
1675 this.contentName = new Name();
1676 this.contentName.from_ccnb(decoder);
1677
1678 if(LOG>4) console.log('KEY NAME FOUND: ');
1679
1680 if ( PublisherID.peek(decoder) ) {
1681 this.publisherID = new PublisherID();
1682 this.publisherID.from_ccnb(decoder);
1683 }
1684
1685 decoder.readEndElement();
1686};
1687
1688KeyName.prototype.to_ccnb = function( encoder) {
1689 if (!this.validate()) {
1690 throw new Error("Cannot encode : field values missing.");
1691 }
1692
1693 encoder.writeStartElement(this.getElementLabel());
1694
1695 this.contentName.to_ccnb(encoder);
1696 if (null != this.publisherID)
1697 this.publisherID.to_ccnb(encoder);
1698
1699 encoder.writeEndElement();
1700};
1701
1702KeyName.prototype.getElementLabel = function() { return CCNProtocolDTags.KeyName; };
1703
1704KeyName.prototype.validate = function() {
1705 // DKS -- do we do recursive validation?
1706 // null signedInfo ok
1707 return (null != this.contentName);
1708};
Wentao Shang82854bd2012-12-27 14:14:41 -08001709
Wentao Shangbd63e462012-12-03 16:19:33 -08001710/**
Wentao Shang0e291c82012-12-02 23:36:29 -08001711 * @author: Meki Cheraoui
1712 * See COPYING for copyright and distribution information.
1713 * This class represents Publisher and PublisherType Objects
1714 */
1715
1716
1717var PublisherType = function PublisherType(_tag){
1718 this.KEY =(CCNProtocolDTags.PublisherPublicKeyDigest);
1719 this.CERTIFICATE= (CCNProtocolDTags.PublisherCertificateDigest);
1720 this.ISSUER_KEY= (CCNProtocolDTags.PublisherIssuerKeyDigest);
1721 this.ISSUER_CERTIFICATE =(CCNProtocolDTags.PublisherIssuerCertificateDigest);
1722
1723 this.Tag = _tag;
1724};
1725
1726var isTypeTagVal = function(tagVal) {
1727 if ((tagVal == CCNProtocolDTags.PublisherPublicKeyDigest) ||
1728 (tagVal == CCNProtocolDTags.PublisherCertificateDigest) ||
1729 (tagVal == CCNProtocolDTags.PublisherIssuerKeyDigest) ||
1730 (tagVal == CCNProtocolDTags.PublisherIssuerCertificateDigest)) {
1731 return true;
1732 }
1733 return false;
1734};
1735
1736
1737
1738
1739var PublisherID = function PublisherID() {
1740
1741 this.PUBLISHER_ID_DIGEST_ALGORITHM = "SHA-256";
1742 this.PUBLISHER_ID_LEN = 256/8;
1743
1744 //TODO, implement publisherID creation and key creation
1745
1746 //TODO implement generatePublicKeyDigest
1747 this.publisherID =null;//= generatePublicKeyDigest(key);//ByteArray
1748
1749 //TODO implement generate key
1750 //CryptoUtil.generateKeyID(PUBLISHER_ID_DIGEST_ALGORITHM, key);
1751 this.publisherType = null;//isIssuer ? PublisherType.ISSUER_KEY : PublisherType.KEY;//publisher Type
1752
1753};
1754
1755
1756PublisherID.prototype.from_ccnb = function(decoder) {
1757
1758 // We have a choice here of one of 4 binary element types.
1759 var nextTag = decoder.peekStartElementAsLong();
1760
1761 if (null == nextTag) {
1762 throw new Error("Cannot parse publisher ID.");
1763 }
1764
1765 this.publisherType = new PublisherType(nextTag);
1766
1767 if (!isTypeTagVal(nextTag)) {
1768 throw new Error("Invalid publisher ID, got unexpected type: " + nextTag);
1769 }
1770 this.publisherID = decoder.readBinaryElement(nextTag);
1771 if (null == this.publisherID) {
1772 throw new ContentDecodingException(new Error("Cannot parse publisher ID of type : " + nextTag + "."));
1773 }
1774};
1775
1776PublisherID.prototype.to_ccnb = function(encoder) {
1777 if (!this.validate()) {
1778 throw new Error("Cannot encode " + this.getClass().getName() + ": field values missing.");
1779 }
1780
1781 encoder.writeElement(this.getElementLabel(), this.publisherID);
1782};
1783
1784PublisherID.peek = function(/* XMLDecoder */ decoder) {
1785
1786 //Long
1787 nextTag = decoder.peekStartElementAsLong();
1788
1789 if (null == nextTag) {
1790 // on end element
1791 return false;
1792 }
1793 return (isTypeTagVal(nextTag));
1794 };
1795
1796PublisherID.prototype.getElementLabel = function() {
1797 return this.publisherType.Tag;
1798};
1799
1800PublisherID.prototype.validate = function(){
1801 return ((null != id() && (null != type())));
1802};
1803
1804
1805
Wentao Shangbd63e462012-12-03 16:19:33 -08001806/**
Wentao Shang0e291c82012-12-02 23:36:29 -08001807 * @author: Meki Cheraoui
1808 * See COPYING for copyright and distribution information.
1809 * This class represents PublisherPublicKeyDigest Objects
1810 */
1811var PublisherPublicKeyDigest = function PublisherPublicKeyDigest(_pkd){
1812
1813 //this.PUBLISHER_ID_LEN = 256/8;
1814 this.PUBLISHER_ID_LEN = 512/8;
1815
1816
1817 this.publisherPublicKeyDigest = _pkd;
1818 //if( typeof _pkd == "object") this.publisherPublicKeyDigest = _pkd; // Byte Array
1819 //else if( typeof _pkd == "PublicKey") ;//TODO...
1820
1821};
1822
1823PublisherPublicKeyDigest.prototype.from_ccnb = function( decoder) {
1824
1825 this.publisherPublicKeyDigest = decoder.readBinaryElement(this.getElementLabel());
1826
1827 if(LOG>4)console.log('Publisher public key digest is ' + this.publisherPublicKeyDigest);
1828
1829 if (null == this.publisherPublicKeyDigest) {
1830 throw new Error("Cannot parse publisher key digest.");
1831 }
1832
1833 //TODO check if the length of the PublisherPublicKeyDigest is correct ( Security reason)
1834
1835 if (this.publisherPublicKeyDigest.length != this.PUBLISHER_ID_LEN) {
1836 if (LOG > 0)
1837 console.log('LENGTH OF PUBLISHER ID IS WRONG! Expected ' + this.PUBLISHER_ID_LEN + ", got " + this.publisherPublicKeyDigest.length);
1838
1839 //this.publisherPublicKeyDigest = new PublisherPublicKeyDigest(this.PublisherPublicKeyDigest).PublisherKeyDigest;
1840 }
1841 };
1842
1843PublisherPublicKeyDigest.prototype.to_ccnb= function( encoder) {
1844 //TODO Check that the ByteArray for the key is present
1845 if (!this.validate()) {
1846 throw new Error("Cannot encode : field values missing.");
1847 }
1848 if(LOG>3) console.log('PUBLISHER KEY DIGEST IS'+this.publisherPublicKeyDigest);
1849 encoder.writeElement(this.getElementLabel(), this.publisherPublicKeyDigest);
1850};
1851
1852PublisherPublicKeyDigest.prototype.getElementLabel = function() { return CCNProtocolDTags.PublisherPublicKeyDigest; };
1853
1854PublisherPublicKeyDigest.prototype.validate =function() {
1855 return (null != this.publisherPublicKeyDigest);
1856};
Wentao Shangbd63e462012-12-03 16:19:33 -08001857/**
Wentao Shang0e291c82012-12-02 23:36:29 -08001858 * @author: Meki Cheraoui
1859 * See COPYING for copyright and distribution information.
1860 * This class represents Face Instances
1861 */
1862
1863var NetworkProtocol = { TCP:6, UDP:17};
1864
1865var FaceInstance = function FaceInstance(
1866 _action,
1867 _publisherPublicKeyDigest,
1868 _faceID,
1869 _ipProto,
1870 _host,
1871 _port,
1872 _multicastInterface,
1873 _multicastTTL,
1874 _freshnessSeconds){
1875
1876
1877 this.action = _action;
1878 this.publisherPublicKeyDigest = _publisherPublicKeyDigest;
1879 this.faceID = _faceID;
1880 this.ipProto = _ipProto;
1881 this.host = _host;
1882 this.Port = _port;
1883 this.multicastInterface =_multicastInterface;
1884 this.multicastTTL =_multicastTTL;
1885 this.freshnessSeconds = _freshnessSeconds;
1886
1887 //action ::= ("newface" | "destroyface" | "queryface")
1888 //publisherPublicKeyDigest ::= SHA-256 digest
1889 //faceID ::= nonNegativeInteger
1890 //ipProto ::= nonNegativeInteger [IANA protocol number, 6=TCP, 17=UDP]
1891 //Host ::= textual representation of numeric IPv4 or IPv6 address
1892 //Port ::= nonNegativeInteger [1..65535]
1893 //MulticastInterface ::= textual representation of numeric IPv4 or IPv6 address
1894 //MulticastTTL ::= nonNegativeInteger [1..255]
1895 //freshnessSeconds ::= nonNegativeInteger
1896
1897};
1898
1899/**
1900 * Used by NetworkObject to decode the object from a network stream.
1901 */
1902FaceInstance.prototype.from_ccnb = function(//XMLDecoder
1903 decoder) {
1904
1905 decoder.readStartElement(this.getElementLabel());
1906
1907 if (decoder.peekStartElement(CCNProtocolDTags.Action)) {
1908
1909 this.action = decoder.readUTF8Element(CCNProtocolDTags.Action);
1910
1911 }
1912 if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
1913
1914 this.publisherPublicKeyDigest = new PublisherPublicKeyDigest();
1915 this.publisherPublicKeyDigest.from_ccnb(decoder);
1916
1917 }
1918 if (decoder.peekStartElement(CCNProtocolDTags.FaceID)) {
1919
1920 this.faceID = decoder.readIntegerElement(CCNProtocolDTags.FaceID);
1921
1922 }
1923 if (decoder.peekStartElement(CCNProtocolDTags.IPProto)) {
1924
1925 //int
1926 var pI = decoder.readIntegerElement(CCNProtocolDTags.IPProto);
1927
1928 this.ipProto = null;
1929
1930 if (NetworkProtocol.TCP == pI) {
1931
1932 this.ipProto = NetworkProtocol.TCP;
1933
1934 } else if (NetworkProtocol.UDP == pI) {
1935
1936 this.ipProto = NetworkProtocol.UDP;
1937
1938 } else {
1939
1940 throw new Error("FaceInstance.decoder. Invalid " +
1941 CCNProtocolDTags.tagToString(CCNProtocolDTags.IPProto) + " field: " + pI);
1942
1943 }
1944 }
1945
1946 if (decoder.peekStartElement(CCNProtocolDTags.Host)) {
1947
1948 this.host = decoder.readUTF8Element(CCNProtocolDTags.Host);
1949
1950 }
1951
1952 if (decoder.peekStartElement(CCNProtocolDTags.Port)) {
1953 this.Port = decoder.readIntegerElement(CCNProtocolDTags.Port);
1954 }
1955
1956 if (decoder.peekStartElement(CCNProtocolDTags.MulticastInterface)) {
1957 this.multicastInterface = decoder.readUTF8Element(CCNProtocolDTags.MulticastInterface);
1958 }
1959
1960 if (decoder.peekStartElement(CCNProtocolDTags.MulticastTTL)) {
1961 this.multicastTTL = decoder.readIntegerElement(CCNProtocolDTags.MulticastTTL);
1962 }
1963
1964 if (decoder.peekStartElement(CCNProtocolDTags.FreshnessSeconds)) {
1965 this.freshnessSeconds = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
1966 }
1967 decoder.readEndElement();
1968}
1969
1970/**
1971 * Used by NetworkObject to encode the object to a network stream.
1972 */
1973FaceInstance.prototype.to_ccnb = function(//XMLEncoder
1974 encoder){
1975
1976 //if (!this.validate()) {
1977 //throw new Error("Cannot encode : field values missing.");
1978 //throw new Error("")
1979 //}
1980 encoder.writeStartElement(this.getElementLabel());
1981
1982 if (null != this.action && this.action.length != 0)
1983 encoder.writeElement(CCNProtocolDTags.Action, this.action);
1984
1985 if (null != this.publisherPublicKeyDigest) {
1986 this.publisherPublicKeyDigest.to_ccnb(encoder);
1987 }
1988 if (null != this.faceID) {
1989 encoder.writeElement(CCNProtocolDTags.FaceID, this.faceID);
1990 }
1991 if (null != this.ipProto) {
1992 //encoder.writeElement(CCNProtocolDTags.IPProto, this.IpProto.value());
1993 encoder.writeElement(CCNProtocolDTags.IPProto, this.ipProto);
1994 }
1995 if (null != this.host && this.host.length != 0) {
1996 encoder.writeElement(CCNProtocolDTags.Host, this.host);
1997 }
1998 if (null != this.Port) {
1999 encoder.writeElement(CCNProtocolDTags.Port, this.Port);
2000 }
2001 if (null != this.multicastInterface && this.multicastInterface.length != 0) {
2002 encoder.writeElement(CCNProtocolDTags.MulticastInterface, this.multicastInterface);
2003 }
2004 if (null != this.multicastTTL) {
2005 encoder.writeElement(CCNProtocolDTags.MulticastTTL, this.multicastTTL);
2006 }
2007 if (null != this.freshnessSeconds) {
2008 encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.freshnessSeconds);
2009 }
2010 encoder.writeEndElement();
2011}
2012
2013
2014FaceInstance.prototype.getElementLabel= function(){return CCNProtocolDTags.FaceInstance;};
2015
Wentao Shangbd63e462012-12-03 16:19:33 -08002016/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002017 * @author: Meki Cheraoui
2018 * See COPYING for copyright and distribution information.
2019 * This class represents Forwarding Entries
2020 */
2021
2022var ForwardingEntry = function ForwardingEntry(
2023 //ActionType
2024 _action,
2025 //Name
2026 _prefixName,
2027 //PublisherPublicKeyDigest
2028 _ccndId,
2029 //Integer
2030 _faceID,
2031 //Integer
2032 _flags,
2033 //Integer
2034 _lifetime){
2035
2036
2037
2038 //String
2039 this.action = _action;
2040 //Name\
2041 this.prefixName = _prefixName;
2042 //PublisherPublicKeyDigest
2043 this.ccndID = _ccndId;
2044 //Integer
2045 this.faceID = _faceID;
2046 //Integer
2047 this.flags = _flags;
2048 //Integer
2049 this.lifetime = _lifetime; // in seconds
2050
2051};
2052
2053ForwardingEntry.prototype.from_ccnb =function(
2054 //XMLDecoder
2055 decoder)
2056 //throws ContentDecodingException
2057 {
2058 decoder.readStartElement(this.getElementLabel());
2059 if (decoder.peekStartElement(CCNProtocolDTags.Action)) {
2060 this.action = decoder.readUTF8Element(CCNProtocolDTags.Action);
2061 }
2062 if (decoder.peekStartElement(CCNProtocolDTags.Name)) {
2063 this.prefixName = new Name();
2064 this.prefixName.from_ccnb(decoder) ;
2065 }
2066 if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
2067 this.CcndId = new PublisherPublicKeyDigest();
2068 this.CcndId.from_ccnb(decoder);
2069 }
2070 if (decoder.peekStartElement(CCNProtocolDTags.FaceID)) {
2071 this.faceID = decoder.readIntegerElement(CCNProtocolDTags.FaceID);
2072 }
2073 if (decoder.peekStartElement(CCNProtocolDTags.ForwardingFlags)) {
2074 this.flags = decoder.readIntegerElement(CCNProtocolDTags.ForwardingFlags);
2075 }
2076 if (decoder.peekStartElement(CCNProtocolDTags.FreshnessSeconds)) {
2077 this.lifetime = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
2078 }
2079 decoder.readEndElement();
2080 };
2081
2082 /**
2083 * Used by NetworkObject to encode the object to a network stream.
2084 */
2085ForwardingEntry.prototype.to_ccnb =function(
2086 //XMLEncoder
2087encoder)
2088{
2089
2090
2091 //if (!validate()) {
2092 //throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
2093 //}
2094 encoder.writeStartElement(this.getElementLabel());
2095 if (null != this.action && this.action.length != 0)
2096 encoder.writeElement(CCNProtocolDTags.Action, this.action);
2097 if (null != this.prefixName) {
2098 this.prefixName.to_ccnb(encoder);
2099 }
2100 if (null != this.CcndId) {
2101 this.CcndId.to_ccnb(encoder);
2102 }
2103 if (null != this.faceID) {
2104 encoder.writeElement(CCNProtocolDTags.FaceID, this.faceID);
2105 }
2106 if (null != this.flags) {
2107 encoder.writeElement(CCNProtocolDTags.ForwardingFlags, this.flags);
2108 }
2109 if (null != this.lifetime) {
2110 encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.lifetime);
2111 }
2112 encoder.writeEndElement();
2113 };
2114
2115ForwardingEntry.prototype.getElementLabel = function() { return CCNProtocolDTags.ForwardingEntry; }
Wentao Shangbd63e462012-12-03 16:19:33 -08002116/**
Jeff Thompson96978b42012-12-29 21:59:54 -08002117 * @author: Jeff Thompson
2118 * See COPYING for copyright and distribution information.
2119 * Encapsulate an Uint8Array and support dynamic reallocation.
2120 */
2121
2122/*
2123 * Create a DynamicUint8Array where this.array is a Uint8Array of size length.
2124 * If length is not supplied, use a default initial length.
2125 * The methods will update this.length.
2126 * To access the array, use this.array or call subarray.
2127 */
2128var DynamicUint8Array = function DynamicUint8Array(length) {
2129 if (!length)
2130 length = 16;
2131
2132 this.array = new Uint8Array(length);
2133 this.length = length;
2134};
2135
2136/*
2137 * Ensure that this.array has the length, reallocate and copy if necessary.
2138 * Update this.length which may be greater than length.
2139 */
2140DynamicUint8Array.prototype.ensureLength = function(length) {
2141 if (this.array.length >= length)
2142 return;
2143
2144 // See if double is enough.
2145 var newLength = this.array.length * 2;
2146 if (length > newLength)
2147 // The needed length is much greater, so use it.
2148 newLength = length;
2149
2150 var newArray = new Uint8Array(newLength);
2151 newArray.set(this.array);
2152 this.array = newArray;
2153 this.length = newLength;
2154};
2155
2156/*
2157 * Call this.array.set(value, offset), reallocating if necessary.
2158 */
2159DynamicUint8Array.prototype.set = function(value, offset) {
2160 this.ensureLength(value.length + offset);
2161 this.array.set(value, offset);
2162};
2163
2164/*
2165 * Return this.array.subarray(begin, end);
2166 */
2167DynamicUint8Array.prototype.subarray = function(begin, end) {
2168 return this.array.subarray(begin, end);
2169}
2170/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002171 * This class is used to encode ccnb binary elements (blob, type/value pairs).
2172 *
2173 * @author: Meki Cheraoui
2174 * See COPYING for copyright and distribution information.
2175 */
2176
2177var XML_EXT = 0x00;
2178
2179var XML_TAG = 0x01;
2180
2181var XML_DTAG = 0x02;
2182
2183var XML_ATTR = 0x03;
2184
2185var XML_DATTR = 0x04;
2186
2187var XML_BLOB = 0x05;
2188
2189var XML_UDATA = 0x06;
2190
2191var XML_CLOSE = 0x0;
2192
2193var XML_SUBTYPE_PROCESSING_INSTRUCTIONS = 16;
2194
2195
2196var XML_TT_BITS = 3;
2197var XML_TT_MASK = ((1 << XML_TT_BITS) - 1);
2198var XML_TT_VAL_BITS = XML_TT_BITS + 1;
2199var XML_TT_VAL_MASK = ((1 << (XML_TT_VAL_BITS)) - 1);
2200var XML_REG_VAL_BITS = 7;
2201var XML_REG_VAL_MASK = ((1 << XML_REG_VAL_BITS) - 1);
2202var XML_TT_NO_MORE = (1 << XML_REG_VAL_BITS); // 0x80
2203var BYTE_MASK = 0xFF;
2204var LONG_BYTES = 8;
2205var LONG_BITS = 64;
2206
2207var bits_11 = 0x0000007FF;
2208var bits_18 = 0x00003FFFF;
2209var bits_32 = 0x0FFFFFFFF;
2210
2211
2212var BinaryXMLEncoder = function BinaryXMLEncoder(){
Jeff Thompson96978b42012-12-29 21:59:54 -08002213 this.ostream = new DynamicUint8Array(100);
Wentao Shang0e291c82012-12-02 23:36:29 -08002214 this.offset =0;
2215 this.CODEC_NAME = "Binary";
2216};
2217
2218/*
2219 * Encode utf8Content as utf8.
2220 */
2221BinaryXMLEncoder.prototype.writeUString = function(/*String*/ utf8Content) {
2222 this.encodeUString(utf8Content, XML_UDATA);
2223};
2224
2225
2226BinaryXMLEncoder.prototype.writeBlob = function(
2227 /*Uint8Array*/ binaryContent
2228 ) {
2229
2230 if(LOG >3) console.log(binaryContent);
2231
2232 this.encodeBlob(binaryContent, binaryContent.length);
2233};
2234
2235
2236BinaryXMLEncoder.prototype.writeStartElement = function(
2237 /*String*/ tag,
2238 /*TreeMap<String,String>*/ attributes
2239 ) {
2240
2241 /*Long*/ var dictionaryVal = tag; //stringToTag(tag);
2242
2243 if (null == dictionaryVal) {
2244 this.encodeUString(tag, XML_TAG);
2245 } else {
2246 this.encodeTypeAndVal(XML_DTAG, dictionaryVal);
2247 }
2248
2249 if (null != attributes) {
2250 this.writeAttributes(attributes);
2251 }
2252};
2253
2254
2255BinaryXMLEncoder.prototype.writeEndElement = function() {
Jeff Thompson96978b42012-12-29 21:59:54 -08002256 this.ostream.ensureLength(this.offset + 1);
2257 this.ostream.array[this.offset] = XML_CLOSE;
Wentao Shang0e291c82012-12-02 23:36:29 -08002258 this.offset += 1;
2259}
2260
2261
2262BinaryXMLEncoder.prototype.writeAttributes = function(/*TreeMap<String,String>*/ attributes) {
2263 if (null == attributes) {
2264 return;
2265 }
2266
2267 // the keySet of a TreeMap is sorted.
2268
2269 for(var i=0; i<attributes.length;i++){
2270 var strAttr = attributes[i].k;
2271 var strValue = attributes[i].v;
2272
2273 var dictionaryAttr = stringToTag(strAttr);
2274 if (null == dictionaryAttr) {
2275 // not in dictionary, encode as attr
2276 // compressed format wants length of tag represented as length-1
2277 // to save that extra bit, as tag cannot be 0 length.
2278 // encodeUString knows to do that.
2279 this.encodeUString(strAttr, XML_ATTR);
2280 } else {
2281 this.encodeTypeAndVal(XML_DATTR, dictionaryAttr);
2282 }
2283 // Write value
2284 this.encodeUString(strValue);
2285
2286 }
2287}
2288
2289
2290//returns a string
2291stringToTag = function(/*long*/ tagVal) {
2292 if ((tagVal >= 0) && (tagVal < CCNProtocolDTagsStrings.length)) {
2293 return CCNProtocolDTagsStrings[tagVal];
2294 } else if (tagVal == CCNProtocolDTags.CCNProtocolDataUnit) {
2295 return CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT;
2296 }
2297 return null;
2298};
2299
2300//returns a Long
2301tagToString = function(/*String*/ tagName) {
2302 // the slow way, but right now we don't care.... want a static lookup for the forward direction
2303 for (var i=0; i < CCNProtocolDTagsStrings.length; ++i) {
2304 if ((null != CCNProtocolDTagsStrings[i]) && (CCNProtocolDTagsStrings[i] == tagName)) {
2305 return i;
2306 }
2307 }
2308 if (CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT == tagName) {
2309 return CCNProtocolDTags.CCNProtocolDataUnit;
2310 }
2311 return null;
2312};
2313
2314/*
2315 * If Content is a string, then encode as utf8 and write UDATA.
2316 */
2317BinaryXMLEncoder.prototype.writeElement = function(
2318 //long
2319 tag,
2320 //byte[]
2321 Content,
2322 //TreeMap<String, String>
2323 attributes
2324 ) {
2325 this.writeStartElement(tag, attributes);
2326 // Will omit if 0-length
2327
2328 if(typeof Content === 'number') {
2329 if(LOG>4) console.log('GOING TO WRITE THE NUMBER .charCodeAt(0) ' + Content.toString().charCodeAt(0) );
2330 if(LOG>4) console.log('GOING TO WRITE THE NUMBER ' + Content.toString() );
2331 if(LOG>4) console.log('type of number is ' + typeof Content.toString() );
2332
2333 this.writeUString(Content.toString());
2334 //whatever
2335 }
2336 else if(typeof Content === 'string'){
2337 if(LOG>4) console.log('GOING TO WRITE THE STRING ' + Content );
2338 if(LOG>4) console.log('type of STRING is ' + typeof Content );
2339
2340 this.writeUString(Content);
2341 }
2342 else{
2343 if(LOG>4) console.log('GOING TO WRITE A BLOB ' + Content );
2344
2345 this.writeBlob(Content);
2346 }
2347
2348 this.writeEndElement();
2349}
2350
2351
2352
2353var TypeAndVal = function TypeAndVal(_type,_val) {
2354 this.type = _type;
2355 this.val = _val;
2356
2357};
2358
2359
2360BinaryXMLEncoder.prototype.encodeTypeAndVal = function(
2361 //int
2362 type,
2363 //long
2364 val
2365 ) {
2366
2367 if(LOG>4) console.log('Encoding type '+ type+ ' and value '+ val);
2368
2369 if(LOG>4) console.log('OFFSET IS ' + this.offset);
2370
2371 if ((type > XML_UDATA) || (type < 0) || (val < 0)) {
2372 throw new Error("Tag and value must be positive, and tag valid.");
2373 }
2374
2375 // Encode backwards. Calculate how many bytes we need:
2376 var numEncodingBytes = this.numEncodingBytes(val);
Jeff Thompson96978b42012-12-29 21:59:54 -08002377 this.ostream.ensureLength(this.offset + numEncodingBytes);
Wentao Shang0e291c82012-12-02 23:36:29 -08002378
2379 // Bottom 4 bits of val go in last byte with tag.
Jeff Thompson96978b42012-12-29 21:59:54 -08002380 this.ostream.array[this.offset + numEncodingBytes - 1] =
Wentao Shang0e291c82012-12-02 23:36:29 -08002381 //(byte)
2382 (BYTE_MASK &
2383 (((XML_TT_MASK & type) |
2384 ((XML_TT_VAL_MASK & val) << XML_TT_BITS))) |
2385 XML_TT_NO_MORE); // set top bit for last byte
Jeff Thompson96978b42012-12-29 21:59:54 -08002386 val = val >>> XML_TT_VAL_BITS;
Wentao Shang0e291c82012-12-02 23:36:29 -08002387
2388 // Rest of val goes into preceding bytes, 7 bits per byte, top bit
2389 // is "more" flag.
2390 var i = this.offset + numEncodingBytes - 2;
2391 while ((0 != val) && (i >= this.offset)) {
Jeff Thompson96978b42012-12-29 21:59:54 -08002392 this.ostream.array[i] = //(byte)
Wentao Shang0e291c82012-12-02 23:36:29 -08002393 (BYTE_MASK & (val & XML_REG_VAL_MASK)); // leave top bit unset
2394 val = val >>> XML_REG_VAL_BITS;
2395 --i;
2396 }
2397 if (val != 0) {
2398 throw new Error( "This should not happen: miscalculated encoding");
2399 //Log.warning(Log.FAC_ENCODING, "This should not happen: miscalculated encoding length, have " + val + " left.");
2400 }
2401 this.offset+= numEncodingBytes;
2402
2403 return numEncodingBytes;
2404};
2405
2406/*
2407 * Encode ustring as utf8.
2408 */
2409BinaryXMLEncoder.prototype.encodeUString = function(
2410 //String
2411 ustring,
2412 //byte
2413 type) {
2414
2415 if (null == ustring)
2416 return;
2417 if (type == XML_TAG || type == XML_ATTR && ustring.length == 0)
2418 return;
2419
2420 if(LOG>3) console.log("The string to write is ");
2421 if(LOG>3) console.log(ustring);
2422
2423 var strBytes = DataUtils.stringToUtf8Array(ustring);
2424
2425 this.encodeTypeAndVal(type,
2426 (((type == XML_TAG) || (type == XML_ATTR)) ?
2427 (strBytes.length-1) :
2428 strBytes.length));
2429
2430 if(LOG>3) console.log("THE string to write is ");
2431
2432 if(LOG>3) console.log(strBytes);
2433
Jeff Thompson96978b42012-12-29 21:59:54 -08002434 this.writeString(strBytes);
Wentao Shang0e291c82012-12-02 23:36:29 -08002435 this.offset+= strBytes.length;
2436};
2437
2438
2439
2440BinaryXMLEncoder.prototype.encodeBlob = function(
2441 //Uint8Array
2442 blob,
2443 //int
2444 length) {
2445
2446
2447 if (null == blob)
2448 return;
2449
2450 if(LOG>4) console.log('LENGTH OF XML_BLOB IS '+length);
2451
2452 /*blobCopy = new Array(blob.Length);
2453
2454 for (i = 0; i < blob.length; i++) //in InStr.ToCharArray())
2455 {
2456 blobCopy[i] = blob[i];
2457 }*/
2458
2459 this.encodeTypeAndVal(XML_BLOB, length);
2460
Jeff Thompson96978b42012-12-29 21:59:54 -08002461 this.writeBlobArray(blob);
Wentao Shang0e291c82012-12-02 23:36:29 -08002462 this.offset += length;
2463};
2464
2465var ENCODING_LIMIT_1_BYTE = ((1 << (XML_TT_VAL_BITS)) - 1);
2466var ENCODING_LIMIT_2_BYTES = ((1 << (XML_TT_VAL_BITS + XML_REG_VAL_BITS)) - 1);
2467var ENCODING_LIMIT_3_BYTES = ((1 << (XML_TT_VAL_BITS + 2 * XML_REG_VAL_BITS)) - 1);
2468
2469BinaryXMLEncoder.prototype.numEncodingBytes = function(
2470 //long
2471 x) {
2472 if (x <= ENCODING_LIMIT_1_BYTE) return (1);
2473 if (x <= ENCODING_LIMIT_2_BYTES) return (2);
2474 if (x <= ENCODING_LIMIT_3_BYTES) return (3);
2475
2476 var numbytes = 1;
2477
2478 // Last byte gives you XML_TT_VAL_BITS
2479 // Remainder each give you XML_REG_VAL_BITS
2480 x = x >>> XML_TT_VAL_BITS;
2481 while (x != 0) {
2482 numbytes++;
2483 x = x >>> XML_REG_VAL_BITS;
2484 }
2485 return (numbytes);
2486};
2487
2488BinaryXMLEncoder.prototype.writeDateTime = function(
2489 //String
2490 tag,
2491 //CCNTime
2492 dateTime) {
2493
2494 if(LOG>4)console.log('ENCODING DATE with LONG VALUE');
2495 if(LOG>4)console.log(dateTime.msec);
2496
2497 //var binarydate = DataUtils.unsignedLongToByteArray( Math.round((dateTime.msec/1000) * 4096) );
2498
2499
2500 //parse to hex
2501 var binarydate = Math.round((dateTime.msec/1000) * 4096).toString(16) ;
2502
2503 //HACK
2504 var binarydate = DataUtils.toNumbers( '0'.concat(binarydate,'0')) ;
2505
2506
2507 if(LOG>4)console.log('ENCODING DATE with BINARY VALUE');
2508 if(LOG>4)console.log(binarydate);
2509 if(LOG>4)console.log('ENCODING DATE with BINARY VALUE(HEX)');
2510 if(LOG>4)console.log(DataUtils.toHex(binarydate));
2511
2512 this.writeElement(tag, binarydate);
2513};
2514
Jeff Thompson96978b42012-12-29 21:59:54 -08002515// This does not update this.offset.
2516BinaryXMLEncoder.prototype.writeString = function(input) {
Wentao Shang0e291c82012-12-02 23:36:29 -08002517
2518 if(typeof input === 'string'){
2519 //console.log('went here');
2520 if(LOG>4) console.log('GOING TO WRITE A STRING');
2521 if(LOG>4) console.log(input);
2522
Jeff Thompson96978b42012-12-29 21:59:54 -08002523 this.ostream.ensureLength(this.offset + input.length);
2524 for (var i = 0; i < input.length; i++) {
Wentao Shang0e291c82012-12-02 23:36:29 -08002525 if(LOG>4) console.log('input.charCodeAt(i)=' + input.charCodeAt(i));
Jeff Thompson96978b42012-12-29 21:59:54 -08002526 this.ostream.array[this.offset + i] = (input.charCodeAt(i));
Wentao Shang0e291c82012-12-02 23:36:29 -08002527 }
2528 }
2529 else{
2530 if(LOG>4) console.log('GOING TO WRITE A STRING IN BINARY FORM');
2531 if(LOG>4) console.log(input);
2532
2533 this.writeBlobArray(input);
2534 }
2535 /*
2536 else if(typeof input === 'object'){
2537
2538 }
2539 */
2540};
2541
2542
2543BinaryXMLEncoder.prototype.writeBlobArray = function(
2544 //Uint8Array
Jeff Thompson96978b42012-12-29 21:59:54 -08002545 blob) {
Wentao Shang0e291c82012-12-02 23:36:29 -08002546
2547 if(LOG>4) console.log('GOING TO WRITE A BLOB');
2548
Wentao Shang0e291c82012-12-02 23:36:29 -08002549 this.ostream.set(blob, this.offset);
2550};
2551
2552
2553BinaryXMLEncoder.prototype.getReducedOstream = function() {
2554 return this.ostream.subarray(0, this.offset);
2555};
2556
Wentao Shangbd63e462012-12-03 16:19:33 -08002557/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002558 * This class is used to decode ccnb binary elements (blob, type/value pairs).
2559 *
2560 * @author: Meki Cheraoui
2561 * See COPYING for copyright and distribution information.
2562 */
2563
2564var XML_EXT = 0x00;
2565
2566var XML_TAG = 0x01;
2567
2568var XML_DTAG = 0x02;
2569
2570var XML_ATTR = 0x03;
2571
2572var XML_DATTR = 0x04;
2573
2574var XML_BLOB = 0x05;
2575
2576var XML_UDATA = 0x06;
2577
2578var XML_CLOSE = 0x0;
2579
2580var XML_SUBTYPE_PROCESSING_INSTRUCTIONS = 16;
2581
2582
2583var XML_TT_BITS = 3;
2584var XML_TT_MASK = ((1 << XML_TT_BITS) - 1);
2585var XML_TT_VAL_BITS = XML_TT_BITS + 1;
2586var XML_TT_VAL_MASK = ((1 << (XML_TT_VAL_BITS)) - 1);
2587var XML_REG_VAL_BITS = 7;
2588var XML_REG_VAL_MASK = ((1 << XML_REG_VAL_BITS) - 1);
2589var XML_TT_NO_MORE = (1 << XML_REG_VAL_BITS); // 0x80
2590var BYTE_MASK = 0xFF;
2591var LONG_BYTES = 8;
2592var LONG_BITS = 64;
2593
2594var bits_11 = 0x0000007FF;
2595var bits_18 = 0x00003FFFF;
2596var bits_32 = 0x0FFFFFFFF;
2597
2598
2599
2600//returns a string
2601tagToString = function(/*long*/ tagVal) {
2602 if ((tagVal >= 0) && (tagVal < CCNProtocolDTagsStrings.length)) {
2603 return CCNProtocolDTagsStrings[tagVal];
2604 } else if (tagVal == CCNProtocolDTags.CCNProtocolDataUnit) {
2605 return CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT;
2606 }
2607 return null;
2608};
2609
2610//returns a Long
2611stringToTag = function(/*String*/ tagName) {
2612 // the slow way, but right now we don't care.... want a static lookup for the forward direction
2613 for (var i=0; i < CCNProtocolDTagsStrings.length; ++i) {
2614 if ((null != CCNProtocolDTagsStrings[i]) && (CCNProtocolDTagsStrings[i] == tagName)) {
2615 return i;
2616 }
2617 }
2618 if (CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT == tagName) {
2619 return CCNProtocolDTags.CCNProtocolDataUnit;
2620 }
2621 return null;
2622};
2623
2624//console.log(stringToTag(64));
2625var BinaryXMLDecoder = function BinaryXMLDecoder(istream){
2626 var MARK_LEN=512;
2627 var DEBUG_MAX_LEN = 32768;
2628
2629 this.istream = istream;
2630 this.offset = 0;
2631};
2632
2633BinaryXMLDecoder.prototype.readAttributes = function(
2634 //TreeMap<String,String>
2635 attributes){
2636
2637 if (null == attributes) {
2638 return;
2639 }
2640
2641 try {
2642
2643 //this.TypeAndVal
2644 var nextTV = this.peekTypeAndVal();
2645
2646 while ((null != nextTV) && ((XML_ATTR == nextTV.type()) ||
2647 (XML_DATTR == nextTV.type()))) {
2648
2649 //this.TypeAndVal
2650 var thisTV = this.decodeTypeAndVal();
2651
2652 var attributeName = null;
2653 if (XML_ATTR == thisTV.type()) {
2654
2655 attributeName = this.decodeUString(thisTV.val()+1);
2656
2657 } else if (XML_DATTR == thisTV.type()) {
2658 // DKS TODO are attributes same or different dictionary?
2659 attributeName = tagToString(thisTV.val());
2660 if (null == attributeName) {
2661 throw new ContentDecodingException(new Error("Unknown DATTR value" + thisTV.val()));
2662 }
2663 }
2664
2665 var attributeValue = this.decodeUString();
2666
2667 attributes.put(attributeName, attributeValue);
2668
2669 nextTV = this.peekTypeAndVal();
2670 }
2671
2672 } catch ( e) {
2673
2674 throw new ContentDecodingException(new Error("readStartElement", e));
2675 }
2676};
2677
2678
2679BinaryXMLDecoder.prototype.initializeDecoding = function() {
2680 //if (!this.istream.markSupported()) {
2681 //throw new IllegalArgumentException(this.getClass().getName() + ": input stream must support marking!");
2682 //}
2683}
2684
2685BinaryXMLDecoder.prototype.readStartDocument = function(){
2686 // Currently no start document in binary encoding.
2687 }
2688
2689BinaryXMLDecoder.prototype.readEndDocument = function() {
2690 // Currently no end document in binary encoding.
2691 };
2692
2693BinaryXMLDecoder.prototype.readStartElement = function(
2694 //String
2695 startTag,
2696 //TreeMap<String, String>
2697 attributes) {
2698
2699
2700 //NOT SURE
2701 //if(typeof startTag == 'number')
2702 //startTag = tagToString(startTag);
2703
2704 //TypeAndVal
2705 tv = this.decodeTypeAndVal();
2706
2707 if (null == tv) {
2708 throw new ContentDecodingException(new Error("Expected start element: " + startTag + " got something not a tag."));
2709 }
2710
2711 //String
2712 var decodedTag = null;
2713 //console.log(tv);
2714 //console.log(typeof tv);
2715
2716 //console.log(XML_TAG);
2717 if (tv.type() == XML_TAG) {
2718 //console.log('got here');
2719 //Log.info(Log.FAC_ENCODING, "Unexpected: got tag in readStartElement; looking for tag " + startTag + " got length: " + (int)tv.val()+1);
2720 // Tag value represents length-1 as tags can never be empty.
2721 var valval ;
2722 if(typeof tv.val() == 'string'){
2723 valval = (parseInt(tv.val())) + 1;
2724 }
2725 else
2726 valval = (tv.val())+ 1;
2727
2728 //console.log('valval is ' +valval);
2729
2730 decodedTag = this.decodeUString(valval);
2731
2732 } else if (tv.type() == XML_DTAG) {
2733 //console.log('gothere');
2734 //console.log(tv.val());
2735 //decodedTag = tagToString(tv.val());
2736 //console.log()
2737 decodedTag = tv.val();
2738 }
2739
2740 //console.log(decodedTag);
2741 //console.log('startTag is '+startTag);
2742
2743
2744 if ((null == decodedTag) || decodedTag != startTag ) {
2745 console.log('expecting '+ startTag + ' but got '+ decodedTag);
2746 throw new ContentDecodingException(new Error("Expected start element: " + startTag + " got: " + decodedTag + "(" + tv.val() + ")"));
2747 }
2748
2749 // DKS: does not read attributes out of stream if caller doesn't
2750 // ask for them. Should possibly peek and skip over them regardless.
2751 // TODO: fix this
2752 if (null != attributes) {
2753 readAttributes(attributes);
2754 }
2755 }
2756
2757
2758BinaryXMLDecoder.prototype.readAttributes = function(
2759 //TreeMap<String,String>
2760 attributes) {
2761
2762 if (null == attributes) {
2763 return;
2764 }
2765
2766 try {
2767 // Now need to get attributes.
2768 //TypeAndVal
2769 var nextTV = this.peekTypeAndVal();
2770
2771 while ((null != nextTV) && ((XML_ATTR == nextTV.type()) ||
2772 (XML_DATTR == nextTV.type()))) {
2773
2774 // Decode this attribute. First, really read the type and value.
2775 //this.TypeAndVal
2776 var thisTV = this.decodeTypeAndVal();
2777
2778 //String
2779 var attributeName = null;
2780 if (XML_ATTR == thisTV.type()) {
2781 // Tag value represents length-1 as attribute names cannot be empty.
2782 var valval ;
2783 if(typeof tv.val() == 'string'){
2784 valval = (parseInt(tv.val())) + 1;
2785 }
2786 else
2787 valval = (tv.val())+ 1;
2788
2789 attributeName = this.decodeUString(valval);
2790
2791 } else if (XML_DATTR == thisTV.type()) {
2792 // DKS TODO are attributes same or different dictionary?
2793 attributeName = tagToString(thisTV.val());
2794 if (null == attributeName) {
2795 throw new ContentDecodingException(new Error("Unknown DATTR value" + thisTV.val()));
2796 }
2797 }
2798 // Attribute values are always UDATA
2799 //String
2800 var attributeValue = this.decodeUString();
2801
2802 //
2803 attributes.push([attributeName, attributeValue]);
2804
2805 nextTV = this.peekTypeAndVal();
2806 }
2807 } catch ( e) {
2808 throw new ContentDecodingException(new Error("readStartElement", e));
2809 }
2810};
2811
2812//returns a string
2813BinaryXMLDecoder.prototype.peekStartElementAsString = function() {
2814 //this.istream.mark(MARK_LEN);
2815
2816 //String
2817 var decodedTag = null;
2818 var previousOffset = this.offset;
2819 try {
2820 // Have to distinguish genuine errors from wrong tags. Could either use
2821 // a special exception subtype, or redo the work here.
2822 //this.TypeAndVal
2823 var tv = this.decodeTypeAndVal();
2824
2825 if (null != tv) {
2826
2827 if (tv.type() == XML_TAG) {
2828 /*if (tv.val()+1 > DEBUG_MAX_LEN) {
2829 throw new ContentDecodingException(new Error("Decoding error: length " + tv.val()+1 + " longer than expected maximum length!")(;
2830 }*/
2831
2832 // Tag value represents length-1 as tags can never be empty.
2833 var valval ;
2834 if(typeof tv.val() == 'string'){
2835 valval = (parseInt(tv.val())) + 1;
2836 }
2837 else
2838 valval = (tv.val())+ 1;
2839
2840 decodedTag = this.decodeUString(valval);
2841
2842 //Log.info(Log.FAC_ENCODING, "Unexpected: got text tag in peekStartElement; length: " + valval + " decoded tag = " + decodedTag);
2843
2844 } else if (tv.type() == XML_DTAG) {
2845 decodedTag = tagToString(tv.val());
2846 }
2847
2848 } // else, not a type and val, probably an end element. rewind and return false.
2849
2850 } catch ( e) {
2851
2852 } finally {
2853 try {
2854 this.offset = previousOffset;
2855 } catch ( e) {
2856 Log.logStackTrace(Log.FAC_ENCODING, Level.WARNING, e);
2857 throw new ContentDecodingException(new Error("Cannot reset stream! " + e.getMessage(), e));
2858 }
2859 }
2860 return decodedTag;
2861};
2862
2863BinaryXMLDecoder.prototype.peekStartElement = function(
2864 //String
2865 startTag) {
2866 //String
2867 if(typeof startTag == 'string'){
2868 var decodedTag = this.peekStartElementAsString();
2869
2870 if ((null != decodedTag) && decodedTag == startTag) {
2871 return true;
2872 }
2873 return false;
2874 }
2875 else if(typeof startTag == 'number'){
2876 var decodedTag = this.peekStartElementAsLong();
2877 if ((null != decodedTag) && decodedTag == startTag) {
2878 return true;
2879 }
2880 return false;
2881 }
2882 else{
2883 throw new ContentDecodingException(new Error("SHOULD BE STRING OR NUMBER"));
2884 }
2885}
2886//returns Long
2887BinaryXMLDecoder.prototype.peekStartElementAsLong = function() {
2888 //this.istream.mark(MARK_LEN);
2889
2890 //Long
2891 var decodedTag = null;
2892
2893 var previousOffset = this.offset;
2894
2895 try {
2896 // Have to distinguish genuine errors from wrong tags. Could either use
2897 // a special exception subtype, or redo the work here.
2898 //this.TypeAndVal
2899 var tv = this.decodeTypeAndVal();
2900
2901 if (null != tv) {
2902
2903 if (tv.type() == XML_TAG) {
2904 if (tv.val()+1 > DEBUG_MAX_LEN) {
2905 throw new ContentDecodingException(new Error("Decoding error: length " + tv.val()+1 + " longer than expected maximum length!"));
2906 }
2907
2908 var valval ;
2909 if(typeof tv.val() == 'string'){
2910 valval = (parseInt(tv.val())) + 1;
2911 }
2912 else
2913 valval = (tv.val())+ 1;
2914
2915 // Tag value represents length-1 as tags can never be empty.
2916 //String
2917 var strTag = this.decodeUString(valval);
2918
2919 decodedTag = stringToTag(strTag);
2920
2921 //Log.info(Log.FAC_ENCODING, "Unexpected: got text tag in peekStartElement; length: " + valval + " decoded tag = " + decodedTag);
2922
2923 } else if (tv.type() == XML_DTAG) {
2924 decodedTag = tv.val();
2925 }
2926
2927 } // else, not a type and val, probably an end element. rewind and return false.
2928
2929 } catch ( e) {
2930
2931 } finally {
2932 try {
2933 //this.istream.reset();
2934 this.offset = previousOffset;
2935 } catch ( e) {
2936 Log.logStackTrace(Log.FAC_ENCODING, Level.WARNING, e);
2937 throw new Error("Cannot reset stream! " + e.getMessage(), e);
2938 }
2939 }
2940 return decodedTag;
2941 };
2942
2943
2944// returns a byte[]
2945BinaryXMLDecoder.prototype.readBinaryElement = function(
2946 //long
2947 startTag,
2948 //TreeMap<String, String>
2949 attributes){
2950 //byte []
2951 var blob = null;
2952
2953 this.readStartElement(startTag, attributes);
2954 blob = this.readBlob();
2955
2956 return blob;
2957};
2958
2959
2960BinaryXMLDecoder.prototype.readEndElement = function(){
2961 if(LOG>4)console.log('this.offset is '+this.offset);
2962
2963 var next = this.istream[this.offset];
2964
2965 this.offset++;
2966 //read();
2967
2968 if(LOG>4)console.log('XML_CLOSE IS '+XML_CLOSE);
2969 if(LOG>4)console.log('next is '+next);
2970
2971 if (next != XML_CLOSE) {
2972 console.log("Expected end element, got: " + next);
2973 throw new ContentDecodingException(new Error("Expected end element, got: " + next));
2974 }
2975 };
2976
2977
2978//String
2979BinaryXMLDecoder.prototype.readUString = function(){
2980 //String
2981 var ustring = this.decodeUString();
2982 this.readEndElement();
2983 return ustring;
2984
2985 };
2986
2987
Wentao Shang882e34e2013-01-05 02:49:51 -08002988//returns a uint8array
Wentao Shang0e291c82012-12-02 23:36:29 -08002989BinaryXMLDecoder.prototype.readBlob = function() {
Wentao Shang882e34e2013-01-05 02:49:51 -08002990 //uint8array
Wentao Shang0e291c82012-12-02 23:36:29 -08002991
2992 var blob = this.decodeBlob();
2993 this.readEndElement();
2994 return blob;
2995
2996 };
2997
2998
2999//CCNTime
3000BinaryXMLDecoder.prototype.readDateTime = function(
3001 //long
3002 startTag) {
3003 //byte []
3004
3005 var byteTimestamp = this.readBinaryElement(startTag);
3006
3007 //var lontimestamp = DataUtils.byteArrayToUnsignedLong(byteTimestamp);
3008
3009 byteTimestamp = DataUtils.toHex(byteTimestamp);
3010
3011
3012 byteTimestamp = parseInt(byteTimestamp, 16);
3013
3014 var lontimestamp = (byteTimestamp/ 4096) * 1000;
3015
3016 //if(lontimestamp<0) lontimestamp = - lontimestamp;
3017
3018 if(LOG>3) console.log('DECODED DATE WITH VALUE');
3019 if(LOG>3) console.log(lontimestamp);
3020
3021
3022 //CCNTime
3023 var timestamp = new CCNTime(lontimestamp);
3024 //timestamp.setDateBinary(byteTimestamp);
3025
3026 if (null == timestamp) {
3027 throw new ContentDecodingException(new Error("Cannot parse timestamp: " + DataUtils.printHexBytes(byteTimestamp)));
3028 }
3029 return timestamp;
3030};
3031
3032BinaryXMLDecoder.prototype.decodeTypeAndVal = function() {
3033
3034 /*int*/var type = -1;
3035 /*long*/var val = 0;
3036 /*boolean*/var more = true;
3037
3038 do {
3039
3040 var next = this.istream[this.offset ];
3041
3042
3043 if (next < 0) {
3044 return null;
3045 }
3046
3047 if ((0 == next) && (0 == val)) {
3048 return null;
3049 }
3050
3051 more = (0 == (next & XML_TT_NO_MORE));
3052
3053 if (more) {
3054 val = val << XML_REG_VAL_BITS;
3055 val |= (next & XML_REG_VAL_MASK);
3056 } else {
3057
3058 type = next & XML_TT_MASK;
3059 val = val << XML_TT_VAL_BITS;
3060 val |= ((next >>> XML_TT_BITS) & XML_TT_VAL_MASK);
3061 }
3062
3063 this.offset++;
3064
3065 } while (more);
3066
3067 if(LOG>3)console.log('TYPE is '+ type + ' VAL is '+ val);
3068
3069 return new TypeAndVal(type, val);
3070};
3071
3072
3073
3074//TypeAndVal
3075BinaryXMLDecoder.peekTypeAndVal = function() {
3076 //TypeAndVal
3077 var tv = null;
3078
3079 //this.istream.mark(LONG_BYTES*2);
3080
3081 var previousOffset = this.offset;
3082
3083 try {
3084 tv = this.decodeTypeAndVal();
3085 } finally {
3086 //this.istream.reset();
3087 this.offset = previousOffset;
3088 }
3089
3090 return tv;
3091};
3092
3093
3094//Uint8Array
3095BinaryXMLDecoder.prototype.decodeBlob = function(
3096 //int
3097 blobLength) {
3098
3099 if(null == blobLength){
3100 //TypeAndVal
3101 var tv = this.decodeTypeAndVal();
3102
3103 var valval ;
3104
3105 if(typeof tv.val() == 'string'){
3106 valval = (parseInt(tv.val()));
3107 }
3108 else
3109 valval = (tv.val());
3110
3111 //console.log('valval here is ' + valval);
3112 return this.decodeBlob(valval);
3113 }
3114
3115 //
3116 //Uint8Array
3117 var bytes = this.istream.subarray(this.offset, this.offset+ blobLength);
3118 this.offset += blobLength;
3119
3120 return bytes;
3121};
3122
3123var count =0;
3124
3125//String
3126BinaryXMLDecoder.prototype.decodeUString = function(
3127 //int
3128 byteLength) {
3129
3130 /*
3131 console.log('COUNT IS '+count);
3132 console.log('INPUT BYTELENGTH IS '+byteLength);
3133 count++;
3134 if(null == byteLength|| undefined == byteLength){
3135 console.log("!!!!");
3136 tv = this.decodeTypeAndVal();
3137 var valval ;
3138 if(typeof tv.val() == 'string'){
3139 valval = (parseInt(tv.val()));
3140 }
3141 else
3142 valval = (tv.val());
3143
3144 if(LOG>4) console.log('valval is ' + valval);
3145 byteLength= this.decodeUString(valval);
3146
3147 //if(LOG>4) console.log('byte Length found in type val is '+ byteLength.charCodeAt(0));
3148 byteLength = parseInt(byteLength);
3149
3150
3151 //byteLength = byteLength.charCodeAt(0);
3152 //if(LOG>4) console.log('byte Length found in type val is '+ byteLength);
3153 }
3154 if(LOG>4)console.log('byteLength is '+byteLength);
3155 if(LOG>4)console.log('type of byteLength is '+typeof byteLength);
3156
3157 stringBytes = this.decodeBlob(byteLength);
3158
3159 //console.log('String bytes are '+ stringBytes);
3160 //console.log('stringBytes);
3161
3162 if(LOG>4)console.log('byteLength is '+byteLength);
3163 if(LOG>4)console.log('this.offset is '+this.offset);
3164
3165 tempBuffer = this.istream.slice(this.offset, this.offset+byteLength);
3166 if(LOG>4)console.log('TEMPBUFFER IS' + tempBuffer);
3167 if(LOG>4)console.log( tempBuffer);
3168
3169 if(LOG>4)console.log('ADDING to offset value' + byteLength);
3170 this.offset+= byteLength;
3171 //if(LOG>3)console.log('read the String' + tempBuffer.toString('ascii'));
3172 //return tempBuffer.toString('ascii');//
3173
3174
3175 //if(LOG>3)console.log( 'STRING READ IS '+ DataUtils.getUTF8StringFromBytes(stringBytes) ) ;
3176 //if(LOG>3)console.log( 'STRING READ IS '+ DataUtils.getUTF8StringFromBytes(tempBuffer) ) ;
3177 //if(LOG>3)console.log(DataUtils.getUTF8StringFromBytes(tempBuffer) ) ;
3178 //return DataUtils.getUTF8StringFromBytes(tempBuffer);
3179
3180 if(LOG>3)console.log( 'STRING READ IS '+ DataUtils.toString(stringBytes) ) ;
3181 if(LOG>3)console.log( 'TYPE OF STRING READ IS '+ typeof DataUtils.toString(stringBytes) ) ;
3182
3183 return DataUtils.toString(stringBytes);*/
3184
3185 if(null == byteLength ){
3186 var tempStreamPosition = this.offset;
3187
3188 //TypeAndVal
3189 var tv = this.decodeTypeAndVal();
3190
3191 if(LOG>3)console.log('TV is '+tv);
3192 if(LOG>3)console.log(tv);
3193
3194 if(LOG>3)console.log('Type of TV is '+typeof tv);
3195
3196 if ((null == tv) || (XML_UDATA != tv.type())) { // if we just have closers left, will get back null
3197 //if (Log.isLoggable(Log.FAC_ENCODING, Level.FINEST))
3198 //Log.finest(Log.FAC_ENCODING, "Expected UDATA, got " + ((null == tv) ? " not a tag " : tv.type()) + ", assuming elided 0-length blob.");
3199
3200 this.offset = tempStreamPosition;
3201
3202 return "";
3203 }
3204
3205 return this.decodeUString(tv.val());
3206 }
3207 else{
Wentao Shang882e34e2013-01-05 02:49:51 -08003208 //uint8array
Wentao Shang0e291c82012-12-02 23:36:29 -08003209 var stringBytes = this.decodeBlob(byteLength);
3210
3211 //return DataUtils.getUTF8StringFromBytes(stringBytes);
3212 return DataUtils.toString(stringBytes);
3213
3214 }
3215};
3216
3217
3218
3219
3220//OBject containg a pair of type and value
3221var TypeAndVal = function TypeAndVal(_type,_val) {
3222 this.t = _type;
3223 this.v = _val;
3224};
3225
3226TypeAndVal.prototype.type = function(){
3227 return this.t;
3228};
3229
3230TypeAndVal.prototype.val = function(){
3231 return this.v;
3232};
3233
3234
3235
3236
3237BinaryXMLDecoder.prototype.readIntegerElement =function(
3238 //String
3239 startTag) {
3240
3241 //String
3242 if(LOG>4) console.log('READING INTEGER '+ startTag);
3243 if(LOG>4) console.log('TYPE OF '+ typeof startTag);
3244
3245 var strVal = this.readUTF8Element(startTag);
3246
3247 return parseInt(strVal);
3248};
3249
3250
3251BinaryXMLDecoder.prototype.readUTF8Element =function(
3252 //String
3253 startTag,
3254 //TreeMap<String, String>
3255 attributes) {
3256 //throws Error where name == "ContentDecodingException"
3257
3258 this.readStartElement(startTag, attributes); // can't use getElementText, can't get attributes
3259 //String
3260 var strElementText = this.readUString();
3261 return strElementText;
3262};
3263
3264
3265/*
3266 * Set the offset into the input, used for the next read.
3267 */
3268BinaryXMLDecoder.prototype.seek = function(
3269 //int
3270 offset) {
3271 this.offset = offset;
3272}
3273
3274/*
3275 * Call with: throw new ContentDecodingException(new Error("message")).
3276 */
3277function ContentDecodingException(error) {
3278 this.message = error.message;
3279 // Copy lineNumber, etc. from where new Error was called.
3280 for (var prop in error)
3281 this[prop] = error[prop];
3282}
3283ContentDecodingException.prototype = new Error();
3284ContentDecodingException.prototype.name = "ContentDecodingException";
3285
Wentao Shangbd63e462012-12-03 16:19:33 -08003286/**
Wentao Shang0e291c82012-12-02 23:36:29 -08003287 * This class uses BinaryXMLDecoder to follow the structure of a ccnb binary element to
3288 * determine its end.
3289 *
3290 * @author: Jeff Thompson
3291 * See COPYING for copyright and distribution information.
3292 */
3293
3294var BinaryXMLStructureDecoder = function BinaryXMLDecoder() {
3295 this.gotElementEnd = false;
3296 this.offset = 0;
3297 this.level = 0;
3298 this.state = BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE;
3299 this.headerLength = 0;
3300 this.useHeaderBuffer = false;
Jeff Thompson96978b42012-12-29 21:59:54 -08003301 this.headerBuffer = new DynamicUint8Array(5);
Wentao Shang0e291c82012-12-02 23:36:29 -08003302 this.nBytesToRead = 0;
3303};
3304
3305BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE = 0;
3306BinaryXMLStructureDecoder.READ_BYTES = 1;
3307
3308/*
3309 * Continue scanning input starting from this.offset. If found the end of the element
3310 * which started at offset 0 then return true, else false.
3311 * If this returns false, you should read more into input and call again.
3312 * You have to pass in input each time because the array could be reallocated.
3313 * This throws an exception for badly formed ccnb.
3314 */
3315BinaryXMLStructureDecoder.prototype.findElementEnd = function(
3316 // Uint8Array
3317 input)
3318{
3319 if (this.gotElementEnd)
3320 // Someone is calling when we already got the end.
3321 return true;
3322
3323 var decoder = new BinaryXMLDecoder(input);
3324
3325 while (true) {
3326 if (this.offset >= input.length)
3327 // All the cases assume we have some input.
3328 return false;
Wentao Shang2b740e62012-12-07 00:02:53 -08003329
Wentao Shang0e291c82012-12-02 23:36:29 -08003330 switch (this.state) {
3331 case BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE:
3332 // First check for XML_CLOSE.
3333 if (this.headerLength == 0 && input[this.offset] == XML_CLOSE) {
3334 ++this.offset;
3335 // Close the level.
3336 --this.level;
3337 if (this.level == 0)
3338 // Finished.
3339 return true;
3340 if (this.level < 0)
3341 throw new Error("BinaryXMLStructureDecoder: Unexepected close tag at offset " +
3342 (this.offset - 1));
3343
3344 // Get ready for the next header.
3345 this.startHeader();
3346 break;
3347 }
3348
3349 var startingHeaderLength = this.headerLength;
3350 while (true) {
3351 if (this.offset >= input.length) {
3352 // We can't get all of the header bytes from this input. Save in headerBuffer.
3353 this.useHeaderBuffer = true;
3354 var nNewBytes = this.headerLength - startingHeaderLength;
Jeff Thompson96978b42012-12-29 21:59:54 -08003355 this.headerBuffer.set
Wentao Shang0e291c82012-12-02 23:36:29 -08003356 (input.subarray(this.offset - nNewBytes, nNewBytes), startingHeaderLength);
3357
3358 return false;
3359 }
3360 var headerByte = input[this.offset++];
3361 ++this.headerLength;
3362 if (headerByte & XML_TT_NO_MORE)
3363 // Break and read the header.
3364 break;
3365 }
3366
3367 var typeAndVal;
3368 if (this.useHeaderBuffer) {
3369 // Copy the remaining bytes into headerBuffer.
3370 nNewBytes = this.headerLength - startingHeaderLength;
Jeff Thompson96978b42012-12-29 21:59:54 -08003371 this.headerBuffer.set
Wentao Shang0e291c82012-12-02 23:36:29 -08003372 (input.subarray(this.offset - nNewBytes, nNewBytes), startingHeaderLength);
3373
Jeff Thompson96978b42012-12-29 21:59:54 -08003374 typeAndVal = new BinaryXMLDecoder(this.headerBuffer.array).decodeTypeAndVal();
Wentao Shang0e291c82012-12-02 23:36:29 -08003375 }
3376 else {
3377 // We didn't have to use the headerBuffer.
3378 decoder.seek(this.offset - this.headerLength);
3379 typeAndVal = decoder.decodeTypeAndVal();
3380 }
3381
3382 if (typeAndVal == null)
3383 throw new Error("BinaryXMLStructureDecoder: Can't read header starting at offset " +
3384 (this.offset - this.headerLength));
3385
3386 // Set the next state based on the type.
3387 var type = typeAndVal.t;
3388 if (type == XML_DATTR)
3389 // We already consumed the item. READ_HEADER_OR_CLOSE again.
3390 // ccnb has rules about what must follow an attribute, but we are just scanning.
3391 this.startHeader();
3392 else if (type == XML_DTAG || type == XML_EXT) {
3393 // Start a new level and READ_HEADER_OR_CLOSE again.
3394 ++this.level;
3395 this.startHeader();
3396 }
3397 else if (type == XML_TAG || type == XML_ATTR) {
3398 if (type == XML_TAG)
3399 // Start a new level and read the tag.
3400 ++this.level;
3401 // Minimum tag or attribute length is 1.
3402 this.nBytesToRead = typeAndVal.v + 1;
3403 this.state = BinaryXMLStructureDecoder.READ_BYTES;
3404 // ccnb has rules about what must follow an attribute, but we are just scanning.
3405 }
3406 else if (type == XML_BLOB || type == XML_UDATA) {
3407 this.nBytesToRead = typeAndVal.v;
3408 this.state = BinaryXMLStructureDecoder.READ_BYTES;
3409 }
3410 else
3411 throw new Error("BinaryXMLStructureDecoder: Unrecognized header type " + type);
3412 break;
3413
3414 case BinaryXMLStructureDecoder.READ_BYTES:
3415 var nRemainingBytes = input.length - this.offset;
3416 if (nRemainingBytes < this.nBytesToRead) {
3417 // Need more.
3418 this.offset += nRemainingBytes;
3419 this.nBytesToRead -= nRemainingBytes;
3420 return false;
3421 }
3422 // Got the bytes. Read a new header or close.
3423 this.offset += this.nBytesToRead;
3424 this.startHeader();
3425 break;
3426
3427 default:
3428 // We don't expect this to happen.
3429 throw new Error("BinaryXMLStructureDecoder: Unrecognized state " + this.state);
3430 }
3431 }
3432};
3433
3434/*
3435 * Set the state to READ_HEADER_OR_CLOSE and set up to start reading the header
3436 */
3437BinaryXMLStructureDecoder.prototype.startHeader = function() {
3438 this.headerLength = 0;
3439 this.useHeaderBuffer = false;
3440 this.state = BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE;
3441}
3442
3443/*
3444 * Set the offset into the input, used for the next read.
3445 */
3446BinaryXMLStructureDecoder.prototype.seek = function(
3447 //int
3448 offset) {
3449 this.offset = offset;
3450}
Jeff Thompson96978b42012-12-29 21:59:54 -08003451/**
Wentao Shang0e291c82012-12-02 23:36:29 -08003452 * This class contains utilities to help parse the data
3453 * author: Meki Cheraoui, Jeff Thompson
3454 * See COPYING for copyright and distribution information.
3455 */
3456
3457var DataUtils = function DataUtils(){
3458
3459
3460};
3461
3462
3463/*
3464 * NOTE THIS IS CURRENTLY NOT BEHING USED
3465 *
3466 */
3467
3468DataUtils.keyStr = "ABCDEFGHIJKLMNOP" +
3469 "QRSTUVWXYZabcdef" +
3470 "ghijklmnopqrstuv" +
3471 "wxyz0123456789+/" +
3472 "=";
3473
3474
3475/**
3476 * Raw String to Base 64
3477 */
3478DataUtils.stringtoBase64=function stringtoBase64(input) {
3479 input = escape(input);
3480 var output = "";
3481 var chr1, chr2, chr3 = "";
3482 var enc1, enc2, enc3, enc4 = "";
3483 var i = 0;
3484
3485 do {
3486 chr1 = input.charCodeAt(i++);
3487 chr2 = input.charCodeAt(i++);
3488 chr3 = input.charCodeAt(i++);
3489
3490 enc1 = chr1 >> 2;
3491 enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
3492 enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
3493 enc4 = chr3 & 63;
3494
3495 if (isNaN(chr2)) {
3496 enc3 = enc4 = 64;
3497 } else if (isNaN(chr3)) {
3498 enc4 = 64;
3499 }
3500
3501 output = output +
3502 DataUtils.keyStr.charAt(enc1) +
3503 DataUtils.keyStr.charAt(enc2) +
3504 DataUtils.keyStr.charAt(enc3) +
3505 DataUtils.keyStr.charAt(enc4);
3506 chr1 = chr2 = chr3 = "";
3507 enc1 = enc2 = enc3 = enc4 = "";
3508 } while (i < input.length);
3509
3510 return output;
3511 }
3512
3513/**
3514 * Base 64 to Raw String
3515 */
3516DataUtils.base64toString = function base64toString(input) {
3517 var output = "";
3518 var chr1, chr2, chr3 = "";
3519 var enc1, enc2, enc3, enc4 = "";
3520 var i = 0;
3521
3522 // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
3523 var base64test = /[^A-Za-z0-9\+\/\=]/g;
3524 /* Test for invalid characters. */
3525 if (base64test.exec(input)) {
3526 alert("There were invalid base64 characters in the input text.\n" +
3527 "Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\n" +
3528 "Expect errors in decoding.");
3529 }
3530
3531 input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
3532
3533 do {
3534 enc1 = DataUtils.keyStr.indexOf(input.charAt(i++));
3535 enc2 = DataUtils.keyStr.indexOf(input.charAt(i++));
3536 enc3 = DataUtils.keyStr.indexOf(input.charAt(i++));
3537 enc4 = DataUtils.keyStr.indexOf(input.charAt(i++));
3538
3539 chr1 = (enc1 << 2) | (enc2 >> 4);
3540 chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
3541 chr3 = ((enc3 & 3) << 6) | enc4;
3542
3543 output = output + String.fromCharCode(chr1);
3544
3545 if (enc3 != 64) {
3546 output = output + String.fromCharCode(chr2);
3547 }
3548 if (enc4 != 64) {
3549 output = output + String.fromCharCode(chr3);
3550 }
3551
3552 chr1 = chr2 = chr3 = "";
3553 enc1 = enc2 = enc3 = enc4 = "";
3554
3555 } while (i < input.length);
3556
3557 return unescape(output);
3558 };
3559
3560//byte []
3561
3562/**
3563 * NOT WORKING!!!!!
3564 *
3565 * Unsiged Long Number to Byte Array
3566 */
3567
3568 /*
3569DataUtils.unsignedLongToByteArray= function( value) {
3570
3571 if(LOG>4)console.log('INPUT IS '+value);
3572
3573 if( 0 == value )
3574 return [0];
3575
3576 if( 0 <= value && value <= 0x00FF ) {
3577 //byte []
3578 var bb = new Array(1);
3579 bb[0] = (value & 0x00FF);
3580 return bb;
3581 }
3582
3583 if(LOG>4) console.log('type of value is '+typeof value);
3584 if(LOG>4) console.log('value is '+value);
3585 //byte []
3586 var out = null;
3587 //int
3588 var offset = -1;
3589 for(var i = 7; i >=0; --i) {
3590 //byte
3591 console.log(i);
3592 console.log('value is '+value);
3593 console.log('(value >> (i * 8)) '+ (value >> (i * 8)) );
3594 console.log(' ((value >> (i * 8)) & 0xFF) '+ ((value >> (i * 8)) & 0xFF) );
3595
3596 var b = ((value >> (i * 8)) & 0xFF) ;
3597
3598 if(LOG>4) console.log('b is '+b);
3599
3600 if( out == null && b != 0 ) {
3601 //out = new byte[i+1];
3602 out = new Array(i+1);
3603 offset = i;
3604 }
3605
3606 if( out != null )
3607 out[ offset - i ] = b;
3608 }
3609 if(LOG>4)console.log('OUTPUT IS ');
3610 if(LOG>4)console.log(out);
3611 return out;
3612}
3613*/
3614
3615/**
3616 * NOT WORKING!!!!!
3617 *
3618 * Unsiged Long Number to Byte Array
3619 *//*
3620DataUtils.byteArrayToUnsignedLong = function(//final byte []
3621 src) {
3622 if(LOG>4) console.log('INPUT IS ');
3623 if(LOG>4) console.log(src);
3624
3625 var value = 0;
3626 for(var i = 0; i < src.length; i++) {
3627 value = value << 8;
3628 // Java will assume the byte is signed, so extend it and trim it.
3629
3630
3631 var b = ((src[i]) & 0xFF );
3632 value |= b;
3633 }
3634
3635 if(LOG>4) console.log('OUTPUT IS ');
3636
3637 if(LOG>4) console.log(value);
3638
3639 return value;
3640 }*/
3641
3642
3643/**
3644 * Hex String to Byte Array
3645 */
3646 //THIS IS NOT WORKING
3647/*
3648DataUtils.HexStringtoByteArray = function(str) {
3649 var byteArray = [];
3650 for (var i = 0; i < str.length; i++)
3651 if (str.charCodeAt(i) <= 0x7F)
3652 byteArray.push(str.charCodeAt(i));
3653 else {
3654 var h = encodeURIComponent(str.charAt(i)).substr(1).split('%');
3655 for (var j = 0; j < h.length; j++)
3656 byteArray.push(parseInt(h[j], 16));
3657 }
3658 return byteArray;
3659};
3660*/
3661
3662/**
3663 * Uint8Array to Hex String
3664 */
3665//http://ejohn.org/blog/numbers-hex-and-colors/
3666DataUtils.toHex = function(args){
3667 if (LOG>4) console.log('ABOUT TO CONVERT '+ args);
3668 //console.log(args);
3669 var ret = "";
3670 for ( var i = 0; i < args.length; i++ )
3671 ret += (args[i] < 16 ? "0" : "") + args[i].toString(16);
3672 if (LOG>4) console.log('Converted to: ' + ret);
3673 return ret; //.toUpperCase();
3674}
3675
3676/**
3677 * Raw string to hex string.
3678 */
3679DataUtils.stringToHex = function(args){
3680 var ret = "";
3681 for (var i = 0; i < args.length; ++i) {
3682 var value = args.charCodeAt(i);
3683 ret += (value < 16 ? "0" : "") + value.toString(16);
3684 }
3685 return ret;
3686}
3687
3688/**
3689 * Uint8Array to raw string.
3690 */
3691DataUtils.toString = function(args){
3692 //console.log(arguments);
3693 var ret = "";
3694 for ( var i = 0; i < args.length; i++ )
3695 ret += String.fromCharCode(args[i]);
3696 return ret;
3697}
3698
3699/**
3700 * Hex String to Uint8Array.
3701 */
3702DataUtils.toNumbers = function(str) {
3703 if (typeof str == 'string') {
3704 var ret = new Uint8Array(Math.floor(str.length / 2));
3705 var i = 0;
3706 str.replace(/(..)/g, function(str) {
3707 ret[i++] = parseInt(str, 16);
3708 });
3709 return ret;
3710 }
3711}
3712
3713/**
3714 * Hex String to raw string.
3715 */
3716DataUtils.hexToRawString = function(str) {
3717 if(typeof str =='string') {
3718 var ret = "";
3719 str.replace(/(..)/g, function(s) {
3720 ret += String.fromCharCode(parseInt(s, 16));
3721 });
3722 return ret;
3723 }
3724}
3725
3726/**
3727 * Raw String to Uint8Array.
3728 */
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08003729DataUtils.toNumbersFromString = function(str) {
Wentao Shang0e291c82012-12-02 23:36:29 -08003730 var bytes = new Uint8Array(str.length);
3731 for(var i=0;i<str.length;i++)
3732 bytes[i] = str.charCodeAt(i);
3733 return bytes;
3734}
3735
3736/*
3737 * Encode str as utf8 and return as Uint8Array.
3738 * TODO: Use TextEncoder when available.
3739 */
3740DataUtils.stringToUtf8Array = function(str) {
3741 return DataUtils.toNumbersFromString(str2rstr_utf8(str));
3742}
3743
3744/*
3745 * arrays is an array of Uint8Array. Return a new Uint8Array which is the concatenation of all.
3746 */
3747DataUtils.concatArrays = function(arrays) {
3748 var totalLength = 0;
3749 for (var i = 0; i < arrays.length; ++i)
3750 totalLength += arrays[i].length;
3751
3752 var result = new Uint8Array(totalLength);
3753 var offset = 0;
3754 for (var i = 0; i < arrays.length; ++i) {
3755 result.set(arrays[i], offset);
3756 offset += arrays[i].length;
3757 }
3758 return result;
3759
3760}
3761
3762// TODO: Take Uint8Array and use TextDecoder when available.
3763DataUtils.decodeUtf8 = function (utftext) {
3764 var string = "";
3765 var i = 0;
3766 var c = 0;
3767 var c1 = 0;
3768 var c2 = 0;
3769
3770 while ( i < utftext.length ) {
3771
3772 c = utftext.charCodeAt(i);
3773
3774 if (c < 128) {
3775 string += String.fromCharCode(c);
3776 i++;
3777 }
3778 else if((c > 191) && (c < 224)) {
3779 c2 = utftext.charCodeAt(i+1);
3780 string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
3781 i += 2;
3782 }
3783 else {
3784 c2 = utftext.charCodeAt(i+1);
3785 var c3 = utftext.charCodeAt(i+2);
3786 string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
3787 i += 3;
3788 }
3789
3790 }
3791
3792 return string;
3793 };
3794
3795//NOT WORKING
3796/*
3797DataUtils.getUTF8StringFromBytes = function(bytes) {
3798
3799 bytes = toString(bytes);
3800
3801 var ix = 0;
3802
3803 if( bytes.slice(0,3) == "\xEF\xBB\xBF") {
3804 ix = 3;
3805 }
3806
3807 var string = "";
3808 for( ; ix < bytes.length; ix++ ) {
3809 var byte1 = bytes[ix].charCodeAt(0);
3810 if( byte1 < 0x80 ) {
3811 string += String.fromCharCode(byte1);
3812 } else if( byte1 >= 0xC2 && byte1 < 0xE0 ) {
3813 var byte2 = bytes[++ix].charCodeAt(0);
3814 string += String.fromCharCode(((byte1&0x1F)<<6) + (byte2&0x3F));
3815 } else if( byte1 >= 0xE0 && byte1 < 0xF0 ) {
3816 var byte2 = bytes[++ix].charCodeAt(0);
3817 var byte3 = bytes[++ix].charCodeAt(0);
3818 string += String.fromCharCode(((byte1&0xFF)<<12) + ((byte2&0x3F)<<6) + (byte3&0x3F));
3819 } else if( byte1 >= 0xF0 && byte1 < 0xF5) {
3820 var byte2 = bytes[++ix].charCodeAt(0);
3821 var byte3 = bytes[++ix].charCodeAt(0);
3822 var byte4 = bytes[++ix].charCodeAt(0);
3823 var codepoint = ((byte1&0x07)<<18) + ((byte2&0x3F)<<12)+ ((byte3&0x3F)<<6) + (byte4&0x3F);
3824 codepoint -= 0x10000;
3825 string += String.fromCharCode(
3826 (codepoint>>10) + 0xD800,
3827 (codepoint&0x3FF) + 0xDC00
3828 );
3829 }
3830 }
3831
3832 return string;
3833}*/
3834
3835/**
3836 * Return true if a1 and a2 are the same length with equal elements.
3837 */
3838DataUtils.arraysEqual = function(a1, a2){
3839 if (a1.length != a2.length)
3840 return false;
3841
3842 for (var i = 0; i < a1.length; ++i) {
3843 if (a1[i] != a2[i])
3844 return false;
3845 }
3846
3847 return true;
3848};
3849
3850/*
3851 * Convert the big endian Uint8Array to an unsigned int.
3852 * Don't check for overflow.
3853 */
3854DataUtils.bigEndianToUnsignedInt = function(bytes) {
3855 var result = 0;
3856 for (var i = 0; i < bytes.length; ++i) {
3857 result <<= 8;
3858 result += bytes[i];
3859 }
3860 return result;
3861};
3862
3863/*
3864 * Convert the int value to a new big endian Uint8Array and return.
3865 * If value is 0 or negative, return Uint8Array(0).
3866 */
3867DataUtils.nonNegativeIntToBigEndian = function(value) {
3868 value = Math.round(value);
3869 if (value <= 0)
3870 return new Uint8Array(0);
3871
3872 // Assume value is not over 64 bits.
3873 var size = 8;
3874 var result = new Uint8Array(size);
3875 var i = 0;
3876 while (value != 0) {
3877 ++i;
3878 result[size - i] = value & 0xff;
3879 value >>= 8;
3880 }
3881 return result.subarray(size - i, size);
3882};
Jeff Thompson3dfddaa2012-12-16 17:55:47 -08003883
3884/*
3885 * Modify array to randomly shuffle the elements.
3886 */
3887DataUtils.shuffle = function(array) {
3888 for (var i = array.length - 1; i >= 1; --i) {
3889 // j is from 0 to i.
3890 var j = Math.floor(Math.random() * (i + 1));
3891 var temp = array[i];
3892 array[i] = array[j];
3893 array[j] = temp;
3894 }
3895}
Wentao Shangbd63e462012-12-03 16:19:33 -08003896/**
Wentao Shang0e291c82012-12-02 23:36:29 -08003897 * This file contains utilities to help encode and decode NDN objects.
3898 * author: Meki Cheraoui
3899 * See COPYING for copyright and distribution information.
3900 */
3901
3902function encodeToHexInterest(interest){
3903 return DataUtils.toHex(encodeToBinaryInterest(interest));
3904}
3905
3906
3907function encodeToBinaryInterest(interest) {
3908 var enc = new BinaryXMLEncoder();
3909 interest.to_ccnb(enc);
3910
3911 return enc.getReducedOstream();
3912}
3913
3914
3915function encodeToHexContentObject(co){
3916 return DataUtils.toHex(encodeToBinaryContentObject(co));
3917}
3918
3919function encodeToBinaryContentObject(co){
3920 var enc = new BinaryXMLEncoder();
3921 co.to_ccnb(enc);
3922
3923 return enc.getReducedOstream();
3924}
3925
3926function encodeForwardingEntry(co){
3927 var enc = new BinaryXMLEncoder();
3928
3929 co.to_ccnb(enc);
3930
3931 var bytes = enc.getReducedOstream();
3932
3933 return bytes;
3934
3935
3936}
3937
3938
3939
3940function decodeHexFaceInstance(result){
3941
3942 var numbers = DataUtils.toNumbers(result);
3943
3944
3945 decoder = new BinaryXMLDecoder(numbers);
3946
3947 if(LOG>3)console.log('DECODING HEX FACE INSTANCE \n'+numbers);
3948
3949 var faceInstance = new FaceInstance();
3950
3951 faceInstance.from_ccnb(decoder);
3952
3953 return faceInstance;
3954
3955}
3956
3957
3958
3959function decodeHexInterest(result){
3960 var numbers = DataUtils.toNumbers(result);
3961
3962 decoder = new BinaryXMLDecoder(numbers);
3963
3964 if(LOG>3)console.log('DECODING HEX INTERST \n'+numbers);
3965
3966 var interest = new Interest();
3967
3968 interest.from_ccnb(decoder);
3969
3970 return interest;
3971
3972}
3973
3974
3975
3976function decodeHexContentObject(result){
3977 var numbers = DataUtils.toNumbers(result);
3978
3979 decoder = new BinaryXMLDecoder(numbers);
3980
3981 if(LOG>3)console.log('DECODED HEX CONTENT OBJECT \n'+numbers);
3982
3983 co = new ContentObject();
3984
3985 co.from_ccnb(decoder);
3986
3987 return co;
3988
3989}
3990
3991
3992
3993function decodeHexForwardingEntry(result){
3994 var numbers = DataUtils.toNumbers(result);
3995
3996 decoder = new BinaryXMLDecoder(numbers);
3997
3998 if(LOG>3)console.log('DECODED HEX FORWARDING ENTRY \n'+numbers);
3999
4000 forwardingEntry = new ForwardingEntry();
4001
4002 forwardingEntry.from_ccnb(decoder);
4003
4004 return forwardingEntry;
4005
4006}
4007
Jeff Thompson68fccd62012-12-29 17:38:23 -08004008/*
4009 * Decode the Uint8Array which holds SubjectPublicKeyInfo and return an RSAKey.
4010 */
4011function decodeSubjectPublicKeyInfo(array) {
4012 var hex = DataUtils.toHex(array).toLowerCase();
4013 var a = _x509_getPublicKeyHexArrayFromCertHex(hex, _x509_getSubjectPublicKeyPosFromCertHex(hex, 0));
4014 var rsaKey = new RSAKey();
4015 rsaKey.setPublic(a[0], a[1]);
4016 return rsaKey;
4017}
4018
Wentao Shang0e291c82012-12-02 23:36:29 -08004019/* Return a user friendly HTML string with the contents of co.
4020 This also outputs to console.log.
4021 */
4022function contentObjectToHtml(/* ContentObject */ co) {
4023 var output ="";
4024
4025 if(co==-1)
4026 output+= "NO CONTENT FOUND"
4027 else if (co==-2)
4028 output+= "CONTENT NAME IS EMPTY"
4029 else{
4030 if(co.name!=null && co.name.components!=null){
4031 output+= "NAME: " + co.name.to_uri();
4032
4033 output+= "<br />";
4034 output+= "<br />";
4035 }
4036
4037 if(co.content !=null){
4038 output += "CONTENT(ASCII): "+ DataUtils.toString(co.content);
4039
4040 output+= "<br />";
4041 output+= "<br />";
4042 }
4043 if(co.content !=null){
4044 output += "CONTENT(hex): "+ DataUtils.toHex(co.content);
4045
4046 output+= "<br />";
4047 output+= "<br />";
4048 }
4049 if(co.signature !=null && co.signature.signature!=null){
4050 output += "SIGNATURE(hex): "+ DataUtils.toHex(co.signature.signature);
4051
4052 output+= "<br />";
4053 output+= "<br />";
4054 }
4055 if(co.signedInfo !=null && co.signedInfo.publisher!=null && co.signedInfo.publisher.publisherPublicKeyDigest!=null){
4056 output += "Publisher Public Key Digest(hex): "+ DataUtils.toHex(co.signedInfo.publisher.publisherPublicKeyDigest);
4057
4058 output+= "<br />";
4059 output+= "<br />";
4060 }
4061 if(co.signedInfo !=null && co.signedInfo.timestamp!=null){
4062 var d = new Date();
4063 d.setTime( co.signedInfo.timestamp.msec );
4064
4065 var bytes = [217, 185, 12, 225, 217, 185, 12, 225];
4066
4067 output += "TimeStamp: "+d;
4068 output+= "<br />";
4069 output += "TimeStamp(number): "+ co.signedInfo.timestamp.msec;
4070
4071 output+= "<br />";
4072 }
4073 if(co.signedInfo !=null && co.signedInfo.finalBlockID!=null){
4074 output += "FinalBlockID: "+ DataUtils.toHex(co.signedInfo.finalBlockID);
4075 output+= "<br />";
4076 }
4077 if(co.signedInfo!=null && co.signedInfo.locator!=null && co.signedInfo.locator.certificate!=null){
Jeff Thompson68fccd62012-12-29 17:38:23 -08004078 var certificateHex = DataUtils.toHex(co.signedInfo.locator.certificate).toLowerCase();
Wentao Shang0e291c82012-12-02 23:36:29 -08004079 var signature = DataUtils.toHex(co.signature.signature).toLowerCase();
4080 var input = DataUtils.toString(co.rawSignatureData);
4081
Jeff Thompson68fccd62012-12-29 17:38:23 -08004082 output += "Hex Certificate: "+ certificateHex ;
Wentao Shang0e291c82012-12-02 23:36:29 -08004083
4084 output+= "<br />";
4085 output+= "<br />";
4086
Wentao Shang0e291c82012-12-02 23:36:29 -08004087 var x509 = new X509();
Jeff Thompson68fccd62012-12-29 17:38:23 -08004088 x509.readCertHex(certificateHex);
Jeff Thompson253cab42012-12-29 17:48:40 -08004089 output += "Public key (hex) modulus: " + x509.subjectPublicKeyRSA.n.toString(16) + "<br/>";
4090 output += "exponent: " + x509.subjectPublicKeyRSA.e.toString(16) + "<br/>";
4091 output += "<br/>";
Wentao Shang0e291c82012-12-02 23:36:29 -08004092
Wentao Shangfddf90d2013-01-05 17:18:49 -08004093 var result = x509.subjectPublicKeyRSA.verifyByteArray(co.rawSignatureData, null, signature);
Wentao Shang0e291c82012-12-02 23:36:29 -08004094 if(LOG>2) console.log('result is '+result);
4095
4096 var n = x509.subjectPublicKeyRSA.n;
4097 var e = x509.subjectPublicKeyRSA.e;
4098
4099 if(LOG>2) console.log('PUBLIC KEY n after is ');
4100 if(LOG>2) console.log(n);
4101
4102 if(LOG>2) console.log('EXPONENT e after is ');
4103 if(LOG>2) console.log(e);
4104
Wentao Shang0e291c82012-12-02 23:36:29 -08004105 if(result)
Jeff Thompson68fccd62012-12-29 17:38:23 -08004106 output += 'SIGNATURE VALID';
Wentao Shang0e291c82012-12-02 23:36:29 -08004107 else
Jeff Thompson68fccd62012-12-29 17:38:23 -08004108 output += 'SIGNATURE INVALID';
Wentao Shang0e291c82012-12-02 23:36:29 -08004109
4110 //output += "VALID: "+ toHex(co.signedInfo.locator.publicKey);
4111
4112 output+= "<br />";
4113 output+= "<br />";
4114
4115 //if(LOG>4) console.log('str'[1]);
4116 }
4117 if(co.signedInfo!=null && co.signedInfo.locator!=null && co.signedInfo.locator.publicKey!=null){
Wentao Shang0e291c82012-12-02 23:36:29 -08004118 var publickeyHex = DataUtils.toHex(co.signedInfo.locator.publicKey).toLowerCase();
4119 var publickeyString = DataUtils.toString(co.signedInfo.locator.publicKey);
4120 var signature = DataUtils.toHex(co.signature.signature).toLowerCase();
4121 var input = DataUtils.toString(co.rawSignatureData);
4122
Wentao Shangfddf90d2013-01-05 17:18:49 -08004123 var wit = null;
4124 var witHex = "";
4125 if (co.signature.Witness != null) {
4126 wit = new Witness();
4127 wit.decode(co.signature.Witness);
4128 witHex = DataUtils.toHex(co.signature.Witness);
4129 }
4130
Jeff Thompson68fccd62012-12-29 17:38:23 -08004131 output += "Public key: " + publickeyHex;
Wentao Shang0e291c82012-12-02 23:36:29 -08004132
4133 output+= "<br />";
4134 output+= "<br />";
4135
4136 if(LOG>2) console.log(" ContentName + SignedInfo + Content = "+input);
Wentao Shang0e291c82012-12-02 23:36:29 -08004137 if(LOG>2) console.log(" PublicKeyHex = "+publickeyHex );
4138 if(LOG>2) console.log(" PublicKeyString = "+publickeyString );
4139
4140 if(LOG>2) console.log(" Signature "+signature );
Wentao Shangfddf90d2013-01-05 17:18:49 -08004141 if(LOG>2) console.log(" Witness "+witHex );
Wentao Shang0e291c82012-12-02 23:36:29 -08004142
4143 if(LOG>2) console.log(" Signature NOW IS" );
4144
4145 if(LOG>2) console.log(co.signature.signature);
Jeff Thompson68fccd62012-12-29 17:38:23 -08004146
4147 var rsakey = decodeSubjectPublicKeyInfo(co.signedInfo.locator.publicKey);
Wentao Shang0e291c82012-12-02 23:36:29 -08004148
Jeff Thompson68fccd62012-12-29 17:38:23 -08004149 output += "Public key (hex) modulus: " + rsakey.n.toString(16) + "<br/>";
4150 output += "exponent: " + rsakey.e.toString(16) + "<br/>";
4151 output += "<br/>";
4152
Wentao Shangfddf90d2013-01-05 17:18:49 -08004153 var result = rsakey.verifyByteArray(co.rawSignatureData, wit, signature);
Wentao Shang0e291c82012-12-02 23:36:29 -08004154 // var result = rsakey.verifyString(input, signature);
4155
Wentao Shang2b740e62012-12-07 00:02:53 -08004156 if(LOG>2) console.log('PUBLIC KEY n after is ');
4157 if(LOG>2) console.log(rsakey.n);
Wentao Shang0e291c82012-12-02 23:36:29 -08004158
Wentao Shang2b740e62012-12-07 00:02:53 -08004159 if(LOG>2) console.log('EXPONENT e after is ');
4160 if(LOG>2) console.log(rsakey.e);
Wentao Shang0e291c82012-12-02 23:36:29 -08004161
4162 if(result)
Wentao Shangfddf90d2013-01-05 17:18:49 -08004163 output += 'SIGNATURE VALID';
Wentao Shang0e291c82012-12-02 23:36:29 -08004164 else
Wentao Shangfddf90d2013-01-05 17:18:49 -08004165 output += 'SIGNATURE INVALID';
Wentao Shang0e291c82012-12-02 23:36:29 -08004166
4167 //output += "VALID: "+ toHex(co.signedInfo.locator.publicKey);
4168
4169 output+= "<br />";
4170 output+= "<br />";
4171
4172 //if(LOG>4) console.log('str'[1]);
4173 }
4174 }
4175
4176 return output;
4177}
Jeff Thompson1a338f82012-12-29 17:07:04 -08004178
4179
Wentao Shangbd63e462012-12-03 16:19:33 -08004180/**
Wentao Shang0e291c82012-12-02 23:36:29 -08004181 * @author: Meki Cheraoui
4182 * See COPYING for copyright and distribution information.
4183 */
4184
4185var KeyManager = function KeyManager(){
4186
4187
4188//Certificate
4189
4190this.certificate = 'MIIBmzCCAQQCCQC32FyQa61S7jANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwd'+
4191
4192'heGVsY2R2MB4XDTEyMDQyODIzNDQzN1oXDTEyMDUyODIzNDQzN1owEjEQMA4GA1'+
4193
4194'UEAxMHYXhlbGNkdjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4X0wp9goq'+
4195
4196'xuECxdULcr2IHr9Ih4Iaypg0Wy39URIup8/CLzQmdsh3RYqd55hqonu5VTTpH3i'+
4197
4198'MLx6xZDVJAZ8OJi7pvXcQ2C4Re2kjL2c8SanI0RfDhlS1zJadfr1VhRPmpivcYa'+
4199
4200'wJ4aFuOLAi+qHFxtN7lhcGCgpW1OV60oXd58CAwEAATANBgkqhkiG9w0BAQUFAA'+
4201
4202'OBgQDLOrA1fXzSrpftUB5Ro6DigX1Bjkf7F5Bkd69hSVp+jYeJFBBlsILQAfSxU'+
4203
4204'ZPQtD+2Yc3iCmSYNyxqu9PcufDRJlnvB7PG29+L3y9lR37tetzUV9eTscJ7rdp8'+
4205
4206'Wt6AzpW32IJ/54yKNfP7S6ZIoIG+LP6EIxq6s8K1MXRt8uBJKw==';
4207
4208
4209//this.publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhfTCn2CirG4QLF1QtyvYgev0iHghrKmDRbLf1REi6nz8IvNCZ2yHdFip3nmGqie7lVNOkfeIwvHrFkNUkBnw4mLum9dxDYLhF7aSMvZzxJqcjRF8OGVLXMlp1+vVWFE+amK9xhrAnhoW44sCL6ocXG03uWFwYKClbU5XrShd3nwIDAQAB';
4210this.publicKey ='30819F300D06092A864886F70D010101050003818D0030818902818100E17D30A7D828AB1B840B17542DCAF6207AFD221E086B2A60D16CB7F54448BA9F3F08BCD099DB21DD162A779E61AA89EEE554D3A47DE230BC7AC590D524067C3898BBA6F5DC4360B845EDA48CBD9CF126A723445F0E1952D7325A75FAF556144F9A98AF7186B0278685B8E2C08BEA87171B4DEE585C1828295B5395EB4A17779F0203010001';
4211//Private Key
4212
4213this.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';
4214
4215
4216/*
4217 this.certificate =
4218 'MIIBvTCCASYCCQD55fNzc0WF7TANBgkqhkiG9w0BAQUFADAjMQswCQYDVQQGEwJK'+
4219 'UDEUMBIGA1UEChMLMDAtVEVTVC1SU0EwHhcNMTAwNTI4MDIwODUxWhcNMjAwNTI1'+
4220 'MDIwODUxWjAjMQswCQYDVQQGEwJKUDEUMBIGA1UEChMLMDAtVEVTVC1SU0EwgZ8w'+
4221 'DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANGEYXtfgDRlWUSDn3haY4NVVQiKI9Cz'+
4222 'Thoua9+DxJuiseyzmBBe7Roh1RPqdvmtOHmEPbJ+kXZYhbozzPRbFGHCJyBfCLzQ'+
4223 'fVos9/qUQ88u83b0SFA2MGmQWQAlRtLy66EkR4rDRwTj2DzR4EEXgEKpIvo8VBs/'+
4224 '3+sHLF3ESgAhAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAEZ6mXFFq3AzfaqWHmCy1'+
4225 'ARjlauYAa8ZmUFnLm0emg9dkVBJ63aEqARhtok6bDQDzSJxiLpCEF6G4b/Nv/M/M'+
4226 'LyhP+OoOTmETMegAVQMq71choVJyOFE5BtQa6M/lCHEOya5QUfoRF2HF9EjRF44K'+
4227 '3OK+u3ivTSj3zwjtpudY5Xo=';
4228
4229 this.privateKey =
4230 'MIICWwIBAAKBgQDRhGF7X4A0ZVlEg594WmODVVUIiiPQs04aLmvfg8SborHss5gQ'+
4231 'Xu0aIdUT6nb5rTh5hD2yfpF2WIW6M8z0WxRhwicgXwi80H1aLPf6lEPPLvN29EhQ'+
4232 'NjBpkFkAJUbS8uuhJEeKw0cE49g80eBBF4BCqSL6PFQbP9/rByxdxEoAIQIDAQAB'+
4233 'AoGAA9/q3Zk6ib2GFRpKDLO/O2KMnAfR+b4XJ6zMGeoZ7Lbpi3MW0Nawk9ckVaX0'+
4234 'ZVGqxbSIX5Cvp/yjHHpww+QbUFrw/gCjLiiYjM9E8C3uAF5AKJ0r4GBPl4u8K4bp'+
4235 'bXeSxSB60/wPQFiQAJVcA5xhZVzqNuF3EjuKdHsw+dk+dPECQQDubX/lVGFgD/xY'+
4236 'uchz56Yc7VHX+58BUkNSewSzwJRbcueqknXRWwj97SXqpnYfKqZq78dnEF10SWsr'+
4237 '/NMKi+7XAkEA4PVqDv/OZAbWr4syXZNv/Mpl4r5suzYMMUD9U8B2JIRnrhmGZPzL'+
4238 'x23N9J4hEJ+Xh8tSKVc80jOkrvGlSv+BxwJAaTOtjA3YTV+gU7Hdza53sCnSw/8F'+
4239 'YLrgc6NOJtYhX9xqdevbyn1lkU0zPr8mPYg/F84m6MXixm2iuSz8HZoyzwJARi2p'+
4240 'aYZ5/5B2lwroqnKdZBJMGKFpUDn7Mb5hiSgocxnvMkv6NjT66Xsi3iYakJII9q8C'+
4241 'Ma1qZvT/cigmdbAh7wJAQNXyoizuGEltiSaBXx4H29EdXNYWDJ9SS5f070BRbAIl'+
4242 'dqRh3rcNvpY6BKJqFapda1DjdcncZECMizT/GMrc1w==';
4243
4244 */
4245};
4246
4247
4248KeyManager.prototype.verify = function verify(message,signature){
4249
4250 var input = message;
4251
4252 var _PEM_X509CERT_STRING_ = this.certificate;
4253
4254 var x509 = new X509();
4255
4256 x509.readCertPEM(_PEM_X509CERT_STRING_);
4257
4258 var result = x509.subjectPublicKeyRSA.verifyString(input, signature);
4259
4260 return result;
4261};
4262
4263KeyManager.prototype.sign= function sign(message){
4264
4265 var input = message;
4266
4267 var _PEM_PRIVATE_KEY_STRING_ = this.privateKey;
4268
4269 var rsa = new RSAKey();
4270
4271 rsa.readPrivateKeyFromPEMString(_PEM_PRIVATE_KEY_STRING_);
4272
4273 var hSig = rsa.signString(input, "sha256");
4274
4275 return hSig;
4276
4277};
4278
4279
4280
4281var globalKeyManager = new KeyManager();
4282//var KeyPair = { "public" : "PUBLIC KEY" , "private" : "PRIVATE KEY" };
4283
4284
Wentao Shang882e34e2013-01-05 02:49:51 -08004285/**
4286 * @author: Wentao Shang
4287 * See COPYING for copyright and distribution information.
4288 */
4289
4290var MerklePath = function MerkelPath() {
4291 this.index = null; // int
4292 this.digestList = []; // array of hex string
4293};
4294
4295var Witness = function Witness() {
4296 this.oid = null; // string
4297 this.path = new MerklePath(); // MerklePath
4298};
4299
Wentao Shange0d7f052013-01-05 16:37:02 -08004300function parseOID(bytes, start, end) {
4301 var s, n = 0, bits = 0;
4302 for (var i = start; i < end; ++i) {
4303 var v = bytes[i];
4304 n = (n << 7) | (v & 0x7F);
4305 bits += 7;
4306 if (!(v & 0x80)) { // finished
4307 if (s == undefined)
4308 s = parseInt(n / 40) + "." + (n % 40);
4309 else
4310 s += "." + ((bits >= 31) ? "bigint" : n);
4311 n = bits = 0;
4312 }
4313 s += String.fromCharCode();
4314 }
4315 return s;
4316}
4317
4318function parseInteger(bytes, start, end) {
4319 var n = 0;
4320 for (var i = start; i < end; ++i)
4321 n = (n << 8) | bytes[i];
4322 return n;
4323}
4324
Wentao Shang882e34e2013-01-05 02:49:51 -08004325Witness.prototype.decode = function(/* Uint8Array */ witness) {
Wentao Shange0d7f052013-01-05 16:37:02 -08004326 /* The asn1.js decoder has some bug and
4327 * cannot decode certain kind of witness.
4328 * So we use an alternative (and dirty) hack
4329 * to read witness from byte streams
4330 * ------Wentao
4331 */
4332 /*
Wentao Shang882e34e2013-01-05 02:49:51 -08004333 var wit = DataUtils.toHex(witness).toLowerCase();
Wentao Shange0d7f052013-01-05 16:37:02 -08004334 try {
4335 var der = Hex.decode(wit);
4336 var asn1 = ASN1.decode(der);
4337 }
4338 catch (e) {
4339 console.log(e);
4340 console.log(wit);
4341 }
Wentao Shang882e34e2013-01-05 02:49:51 -08004342 //console.log(asn1.toPrettyString());
4343
4344 this.oid = asn1.sub[0].sub[0].content(); // OID
Wentao Shange0d7f052013-01-05 16:37:02 -08004345 //console.log(this.oid);
Wentao Shang882e34e2013-01-05 02:49:51 -08004346 this.path.index = asn1.sub[1].sub[0].sub[0].content(); // index
Wentao Shange0d7f052013-01-05 16:37:02 -08004347 //console.log(this.path.index);
Wentao Shang882e34e2013-01-05 02:49:51 -08004348 for (i = 0; i < asn1.sub[1].sub[0].sub[1].sub.length; i++) {
4349 pos = asn1.sub[1].sub[0].sub[1].sub[i].stream.pos;
4350 str = wit.substring(2 * pos + 4, 2 * pos + 68);
4351 this.path.digestList.push(str); // digest hex string
Wentao Shange0d7f052013-01-05 16:37:02 -08004352 //console.log(str);
4353 }
4354 */
4355
4356 // FIXME: Need to be fixed to support arbitrary ASN1 encoding,
4357 // But do we really nned that???? -------Wentao
4358
4359 // The structure of Witness is fixed as follows:
4360 // SEQUENCE (2 elem)
4361 // SEQUENCE (1 elem)
4362 // OBJECT IDENTIFIER 1.2.840.113550.11.1.2.2
4363 // OCTET STRING (1 elem)
4364 // SEQUENCE (2 elem)
4365 // INTEGER index
4366 // SEQUENCE (n elem)
4367 // OCTET STRING(32 byte) 345FB4B5E9A1D2FF450ECA87EB87601683027A1A...
4368 // OCTET STRING(32 byte) DBCEE5B7A6C2B851B029324197DDBD9A655723DC...
4369 // OCTET STRING(32 byte) 4C79B2D256E4CD657A27F01DCB51AC3C56A24E71...
4370 // OCTET STRING(32 byte) 7F7FB169604A87EAC94378F0BDB4FC5D5899AB88...
4371 // ......
4372 // Hence we can follow this structure to extract witness fields at fixed level
4373 // Tag numbers for ASN1:
4374 // SEQUENCE 0x10
4375 // OCT STRING 0x04
4376 // INTEGER 0x02
4377 // OBJECT IDENTIFIER 0x06
4378 var i = 0;
4379 var step = 0; // count of sequence tag
4380 while (i < witness.length) {
4381 var len = 0;
4382
4383 if (witness[i] == 0x30) {
4384 // Sequence (constructed)
4385 // There is no primitive sequence in Witness
4386 if ((witness[i + 1] & 0x80) != 0) {
4387 len = witness[i+1] & 0x7F;
4388 }
4389 step++;
4390 } else if (witness[i] == 0x06) {
4391 // Decode OID
4392 len = witness[i+1]; // XXX: OID will not be longer than 127 bytes
4393 this.oid = parseOID(witness, i + 2, i + 2 + len);
4394 //console.log(this.oid);
4395 } else if (witness[i] == 0x02) {
4396 // Decode node index
4397 len = witness[i+1]; // XXX: index will not be longer than 127 bytes
4398 this.path.index = parseInteger(witness, i + 2, i + 2 + len);
4399 //console.log(this.path.index);
4400 } else if (witness[i] == 0x04) {
4401 if ((witness[i + 1] & 0x80) != 0) {
4402 len = witness[i+1] & 0x7F;
Wentao Shange0d7f052013-01-05 16:37:02 -08004403 }
4404 if (step == 4) {
4405 // Start to decode digest hex string
Wentao Shangedd4dea2013-01-19 16:55:11 -08004406 len = witness[i+1]; // XXX: digest hex should always be 32 bytes
Wentao Shange0d7f052013-01-05 16:37:02 -08004407 str = DataUtils.toHex(witness.subarray(i + 2, i + 2 + len));
4408 this.path.digestList.push(str); // digest hex string
4409 //console.log(str);
4410 }
4411 }
4412 i = i + 2 + len;
Wentao Shang882e34e2013-01-05 02:49:51 -08004413 }
4414};
Wentao Shang0e291c82012-12-02 23:36:29 -08004415/*
4416 * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined
4417 * in FIPS 180-2
4418 * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
4419 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
4420 * Distributed under the BSD License
4421 * See http://pajhome.org.uk/crypt/md5 for details.
4422 * Also http://anmar.eu.org/projects/jssha2/
4423 */
4424
4425/*
4426 * Configurable variables. You may need to tweak these to be compatible with
4427 * the server-side, but the defaults work in most cases.
4428 */
4429var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
4430var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
4431
4432/*
4433 * These are the functions you'll usually want to call
4434 * They take string arguments and return either hex or base-64 encoded strings
4435 */
4436
4437//@author axelcdv
4438/**
4439 * Computes the Sha-256 hash of the given byte array
4440 * @param {byte[]}
4441 * @return the hex string corresponding to the Sha-256 hash of the byte array
4442 */
4443function hex_sha256_from_bytes(byteArray){
4444 return rstr2hex(binb2rstr(binb_sha256( byteArray2binb(byteArray), byteArray.length * 8)));
4445}
4446
4447function hex_sha256(s) { return rstr2hex(rstr_sha256(str2rstr_utf8(s))); }
4448function b64_sha256(s) { return rstr2b64(rstr_sha256(str2rstr_utf8(s))); }
4449function any_sha256(s, e) { return rstr2any(rstr_sha256(str2rstr_utf8(s)), e); }
4450function hex_hmac_sha256(k, d)
4451 { return rstr2hex(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d))); }
4452function b64_hmac_sha256(k, d)
4453 { return rstr2b64(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d))); }
4454function any_hmac_sha256(k, d, e)
4455 { return rstr2any(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
4456
4457
4458/*
4459 function hex_sha256(s) { return rstr2hex(rstr_sha256(s)); }
4460function b64_sha256(s) { return rstr2b64(rstr_sha256(s)); }
4461function any_sha256(s, e) { return rstr2any(rstr_sha256(s), e); }
4462function hex_hmac_sha256(k, d)
4463 { return rstr2hex(rstr_hmac_sha256(str2rstr_utf8(k), d)); }
4464function b64_hmac_sha256(k, d)
4465 { return rstr2b64(rstr_hmac_sha256(str2rstr_utf8(k), d)); }
4466function any_hmac_sha256(k, d, e)
4467 { return rstr2any(rstr_hmac_sha256(str2rstr_utf8(k), d), e); }
4468*/
4469
4470/*
4471 * Perform a simple self-test to see if the VM is working
4472 */
4473function sha256_vm_test()
4474{
4475 return hex_sha256("abc").toLowerCase() ==
4476 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad";
4477}
4478
4479/**
4480 * Calculate the sha256 of a raw string
4481 * @param s: the raw string
4482 */
4483function rstr_sha256(s)
4484{
4485 return binb2rstr(binb_sha256(rstr2binb(s), s.length * 8));
4486}
4487
4488/**
4489 * Calculate the HMAC-sha256 of a key and some data (raw strings)
4490 */
4491function rstr_hmac_sha256(key, data)
4492{
4493 var bkey = rstr2binb(key);
4494 if(bkey.length > 16) bkey = binb_sha256(bkey, key.length * 8);
4495
4496 var ipad = Array(16), opad = Array(16);
4497 for(var i = 0; i < 16; i++)
4498 {
4499 ipad[i] = bkey[i] ^ 0x36363636;
4500 opad[i] = bkey[i] ^ 0x5C5C5C5C;
4501 }
4502
4503 var hash = binb_sha256(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
4504 return binb2rstr(binb_sha256(opad.concat(hash), 512 + 256));
4505}
4506
4507/**
4508 * Convert a raw string to a hex string
4509 */
4510function rstr2hex(input)
4511{
4512 try { hexcase } catch(e) { hexcase=0; }
4513 var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
4514 var output = "";
4515 var x;
4516 for(var i = 0; i < input.length; i++)
4517 {
4518 x = input.charCodeAt(i);
4519 output += hex_tab.charAt((x >>> 4) & 0x0F)
4520 + hex_tab.charAt( x & 0x0F);
4521 }
4522 return output;
4523}
4524
4525/*
4526 * Convert a raw string to a base-64 string
4527 */
4528function rstr2b64(input)
4529{
4530 try { b64pad } catch(e) { b64pad=''; }
4531 var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4532 var output = "";
4533 var len = input.length;
4534 for(var i = 0; i < len; i += 3)
4535 {
4536 var triplet = (input.charCodeAt(i) << 16)
4537 | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
4538 | (i + 2 < len ? input.charCodeAt(i+2) : 0);
4539 for(var j = 0; j < 4; j++)
4540 {
4541 if(i * 8 + j * 6 > input.length * 8) output += b64pad;
4542 else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
4543 }
4544 }
4545 return output;
4546}
4547
4548/*
4549 * Convert a raw string to an arbitrary string encoding
4550 */
4551function rstr2any(input, encoding)
4552{
4553 var divisor = encoding.length;
4554 var remainders = Array();
4555 var i, q, x, quotient;
4556
4557 /* Convert to an array of 16-bit big-endian values, forming the dividend */
4558 var dividend = Array(Math.ceil(input.length / 2));
4559 for(i = 0; i < dividend.length; i++)
4560 {
4561 dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
4562 }
4563
4564 /*
4565 * Repeatedly perform a long division. The binary array forms the dividend,
4566 * the length of the encoding is the divisor. Once computed, the quotient
4567 * forms the dividend for the next step. We stop when the dividend is zero.
4568 * All remainders are stored for later use.
4569 */
4570 while(dividend.length > 0)
4571 {
4572 quotient = Array();
4573 x = 0;
4574 for(i = 0; i < dividend.length; i++)
4575 {
4576 x = (x << 16) + dividend[i];
4577 q = Math.floor(x / divisor);
4578 x -= q * divisor;
4579 if(quotient.length > 0 || q > 0)
4580 quotient[quotient.length] = q;
4581 }
4582 remainders[remainders.length] = x;
4583 dividend = quotient;
4584 }
4585
4586 /* Convert the remainders to the output string */
4587 var output = "";
4588 for(i = remainders.length - 1; i >= 0; i--)
4589 output += encoding.charAt(remainders[i]);
4590
4591 /* Append leading zero equivalents */
4592 var full_length = Math.ceil(input.length * 8 /
4593 (Math.log(encoding.length) / Math.log(2)))
4594 for(i = output.length; i < full_length; i++)
4595 output = encoding[0] + output;
4596
4597 return output;
4598}
4599
4600/*
4601 * Encode a string as utf-8.
4602 * For efficiency, this assumes the input is valid utf-16.
4603 */
4604function str2rstr_utf8(input)
4605{
4606 var output = "";
4607 var i = -1;
4608 var x, y;
4609
4610 while(++i < input.length)
4611 {
4612 /* Decode utf-16 surrogate pairs */
4613 x = input.charCodeAt(i);
4614 y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
4615 if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
4616 {
4617 x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
4618 i++;
4619 }
4620
4621 /* Encode output as utf-8 */
4622 if(x <= 0x7F)
4623 output += String.fromCharCode(x);
4624 else if(x <= 0x7FF)
4625 output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
4626 0x80 | ( x & 0x3F));
4627 else if(x <= 0xFFFF)
4628 output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
4629 0x80 | ((x >>> 6 ) & 0x3F),
4630 0x80 | ( x & 0x3F));
4631 else if(x <= 0x1FFFFF)
4632 output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
4633 0x80 | ((x >>> 12) & 0x3F),
4634 0x80 | ((x >>> 6 ) & 0x3F),
4635 0x80 | ( x & 0x3F));
4636 }
4637 return output;
4638}
4639
4640/*
4641 * Encode a string as utf-16
4642 */
4643function str2rstr_utf16le(input)
4644{
4645 var output = "";
4646 for(var i = 0; i < input.length; i++)
4647 output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
4648 (input.charCodeAt(i) >>> 8) & 0xFF);
4649 return output;
4650}
4651
4652function str2rstr_utf16be(input)
4653{
4654 var output = "";
4655 for(var i = 0; i < input.length; i++)
4656 output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
4657 input.charCodeAt(i) & 0xFF);
4658 return output;
4659}
4660
4661/**
4662 * Convert a raw string to an array of big-endian words
4663 * Characters >255 have their high-byte silently ignored.
4664 */
4665function rstr2binb(input)
4666{
4667 //console.log('Raw string comming is '+input);
4668 var output = Array(input.length >> 2);
Wentao Shangc0311e52012-12-03 10:38:23 -08004669 /* JavaScript automatically zeroizes a new array.
Wentao Shang0e291c82012-12-02 23:36:29 -08004670 for(var i = 0; i < output.length; i++)
4671 output[i] = 0;
Wentao Shangc0311e52012-12-03 10:38:23 -08004672 */
Wentao Shang0e291c82012-12-02 23:36:29 -08004673 for(var i = 0; i < input.length * 8; i += 8)
4674 output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
4675 return output;
4676}
4677
4678/**
4679 * @author axelcdv
4680 * Convert a byte array to an array of big-endian words
4681 * @param {byte[]} input
4682 * @return the array of big-endian words
4683 */
4684function byteArray2binb(input){
4685 //console.log("Byte array coming is " + input);
4686 var output = Array(input.length >> 2);
Wentao Shangc0311e52012-12-03 10:38:23 -08004687 /* JavaScript automatically zeroizes a new array.
Wentao Shang0e291c82012-12-02 23:36:29 -08004688 for(var i = 0; i < output.length; i++)
4689 output[i] = 0;
Wentao Shangc0311e52012-12-03 10:38:23 -08004690 */
Wentao Shang0e291c82012-12-02 23:36:29 -08004691 for(var i = 0; i < input.length * 8; i += 8)
4692 output[i>>5] |= (input[i / 8] & 0xFF) << (24 - i % 32);
4693 return output;
4694}
4695
4696/*
4697 * Convert an array of big-endian words to a string
4698 */
4699function binb2rstr(input)
4700{
4701 var output = "";
4702 for(var i = 0; i < input.length * 32; i += 8)
4703 output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
4704 return output;
4705}
4706
4707/*
4708 * Main sha256 function, with its support functions
4709 */
4710function sha256_S (X, n) {return ( X >>> n ) | (X << (32 - n));}
4711function sha256_R (X, n) {return ( X >>> n );}
4712function sha256_Ch(x, y, z) {return ((x & y) ^ ((~x) & z));}
4713function sha256_Maj(x, y, z) {return ((x & y) ^ (x & z) ^ (y & z));}
4714function sha256_Sigma0256(x) {return (sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22));}
4715function sha256_Sigma1256(x) {return (sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25));}
4716function sha256_Gamma0256(x) {return (sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3));}
4717function sha256_Gamma1256(x) {return (sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10));}
4718function sha256_Sigma0512(x) {return (sha256_S(x, 28) ^ sha256_S(x, 34) ^ sha256_S(x, 39));}
4719function sha256_Sigma1512(x) {return (sha256_S(x, 14) ^ sha256_S(x, 18) ^ sha256_S(x, 41));}
4720function sha256_Gamma0512(x) {return (sha256_S(x, 1) ^ sha256_S(x, 8) ^ sha256_R(x, 7));}
4721function sha256_Gamma1512(x) {return (sha256_S(x, 19) ^ sha256_S(x, 61) ^ sha256_R(x, 6));}
4722
4723var sha256_K = new Array
4724(
4725 1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993,
4726 -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987,
4727 1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522,
4728 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986,
4729 -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585,
4730 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291,
4731 1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885,
4732 -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344,
4733 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218,
4734 1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872,
4735 -1866530822, -1538233109, -1090935817, -965641998
4736);
4737
4738function binb_sha256(m, l)
4739{
4740 var HASH = new Array(1779033703, -1150833019, 1013904242, -1521486534,
4741 1359893119, -1694144372, 528734635, 1541459225);
4742 var W = new Array(64);
Wentao Shang0e291c82012-12-02 23:36:29 -08004743
4744 /* append padding */
4745 m[l >> 5] |= 0x80 << (24 - l % 32);
4746 m[((l + 64 >> 9) << 4) + 15] = l;
Wentao Shangc0311e52012-12-03 10:38:23 -08004747
4748 for(var offset = 0; offset < m.length; offset += 16)
4749 processBlock_sha256(m, offset, HASH, W);
Wentao Shang0e291c82012-12-02 23:36:29 -08004750
Wentao Shangc0311e52012-12-03 10:38:23 -08004751 return HASH;
4752}
4753
4754/*
4755 * Process a block of 16 4-byte words in m starting at offset and update HASH.
4756 * offset must be a multiple of 16 and less than m.length. W is a scratchpad Array(64).
4757 */
4758function processBlock_sha256(m, offset, HASH, W) {
4759 var a, b, c, d, e, f, g, h;
4760 var j, T1, T2;
4761
Wentao Shang0e291c82012-12-02 23:36:29 -08004762 a = HASH[0];
4763 b = HASH[1];
4764 c = HASH[2];
4765 d = HASH[3];
4766 e = HASH[4];
4767 f = HASH[5];
4768 g = HASH[6];
4769 h = HASH[7];
4770
4771 for(j = 0; j < 64; j++)
4772 {
Wentao Shangc0311e52012-12-03 10:38:23 -08004773 if (j < 16) W[j] = m[j + offset];
Wentao Shang0e291c82012-12-02 23:36:29 -08004774 else W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]),
4775 sha256_Gamma0256(W[j - 15])), W[j - 16]);
4776
4777 T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)),
4778 sha256_K[j]), W[j]);
4779 T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
4780 h = g;
4781 g = f;
4782 f = e;
4783 e = safe_add(d, T1);
4784 d = c;
4785 c = b;
4786 b = a;
4787 a = safe_add(T1, T2);
4788 }
4789
4790 HASH[0] = safe_add(a, HASH[0]);
4791 HASH[1] = safe_add(b, HASH[1]);
4792 HASH[2] = safe_add(c, HASH[2]);
4793 HASH[3] = safe_add(d, HASH[3]);
4794 HASH[4] = safe_add(e, HASH[4]);
4795 HASH[5] = safe_add(f, HASH[5]);
4796 HASH[6] = safe_add(g, HASH[6]);
4797 HASH[7] = safe_add(h, HASH[7]);
Wentao Shang0e291c82012-12-02 23:36:29 -08004798}
4799
4800function safe_add (x, y)
4801{
4802 var lsw = (x & 0xFFFF) + (y & 0xFFFF);
4803 var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
4804 return (msw << 16) | (lsw & 0xFFFF);
4805}
Wentao Shangc0311e52012-12-03 10:38:23 -08004806
4807/*
4808 * Create a Sha256, call update(data) multiple times, then call finalize().
4809 */
4810var Sha256 = function Sha256() {
4811 this.W = new Array(64);
4812 this.hash = new Array(1779033703, -1150833019, 1013904242, -1521486534,
4813 1359893119, -1694144372, 528734635, 1541459225);
4814 this.nTotalBytes = 0;
4815 this.buffer = new Uint8Array(16 * 4);
4816 this.nBufferBytes = 0;
4817}
4818
4819/*
4820 * Update the hash with data, which is Uint8Array.
4821 */
4822Sha256.prototype.update = function(data) {
4823 this.nTotalBytes += data.length;
4824
4825 if (this.nBufferBytes > 0) {
4826 // Fill up the buffer and process it first.
4827 var bytesNeeded = this.buffer.length - this.nBufferBytes;
4828 if (data.length < bytesNeeded) {
4829 this.buffer.set(data, this.nBufferBytes);
4830 this.nBufferBytes += data.length;
4831 return;
4832 }
4833 else {
4834 this.buffer.set(data.subarray(0, bytesNeeded), this.nBufferBytes);
4835 processBlock_sha256(byteArray2binb(this.buffer), 0, this.hash, this.W);
4836 this.nBufferBytes = 0;
4837 // Consume the bytes from data.
4838 data = data.subarray(bytesNeeded, data.length);
4839 if (data.length == 0)
4840 return;
4841 }
4842 }
4843
4844 // 2^6 is 16 * 4.
4845 var nBlocks = data.length >> 6;
4846 if (nBlocks > 0) {
4847 var nBytes = nBlocks * 16 * 4;
4848 var m = byteArray2binb(data.subarray(0, nBytes));
4849 for(var offset = 0; offset < m.length; offset += 16)
4850 processBlock_sha256(m, offset, this.hash, this.W);
4851
4852 data = data.subarray(nBytes, data.length);
4853 }
4854
4855 if (data.length > 0) {
4856 // Save the remainder in the buffer.
4857 this.buffer.set(data);
4858 this.nBufferBytes = data.length;
4859 }
4860}
4861
4862/*
4863 * Finalize the hash and return the result as Uint8Array.
4864 * Only call this once. Return values on subsequent calls are undefined.
4865 */
4866Sha256.prototype.finalize = function() {
4867 var m = byteArray2binb(this.buffer.subarray(0, this.nBufferBytes));
4868 /* append padding */
4869 var l = this.nBufferBytes * 8;
4870 m[l >> 5] |= 0x80 << (24 - l % 32);
4871 m[((l + 64 >> 9) << 4) + 15] = this.nTotalBytes * 8;
4872
4873 for(var offset = 0; offset < m.length; offset += 16)
4874 processBlock_sha256(m, offset, this.hash, this.W);
4875
4876 return Sha256.binb2Uint8Array(this.hash);
4877}
4878
4879/*
4880 * Convert an array of big-endian words to Uint8Array.
4881 */
4882Sha256.binb2Uint8Array = function(input)
4883{
4884 var output = new Uint8Array(input.length * 4);
4885 var iOutput = 0;
4886 for (var i = 0; i < input.length * 32; i += 8)
4887 output[iOutput++] = (input[i>>5] >>> (24 - i % 32)) & 0xFF;
4888 return output;
4889}
Wentao Shang0e291c82012-12-02 23:36:29 -08004890var b64map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4891var b64pad="=";
4892
4893function hex2b64(h) {
4894 var i;
4895 var c;
4896 var ret = "";
4897 for(i = 0; i+3 <= h.length; i+=3) {
4898 c = parseInt(h.substring(i,i+3),16);
4899 ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63);
4900 }
4901 if(i+1 == h.length) {
4902 c = parseInt(h.substring(i,i+1),16);
4903 ret += b64map.charAt(c << 2);
4904 }
4905 else if(i+2 == h.length) {
4906 c = parseInt(h.substring(i,i+2),16);
4907 ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4);
4908 }
4909 while((ret.length & 3) > 0) ret += b64pad;
4910 return ret;
4911}
4912
4913// convert a base64 string to hex
4914function b64tohex(s) {
4915 var ret = ""
4916 var i;
4917 var k = 0; // b64 state, 0-3
4918 var slop;
4919 for(i = 0; i < s.length; ++i) {
4920 if(s.charAt(i) == b64pad) break;
4921 v = b64map.indexOf(s.charAt(i));
4922 if(v < 0) continue;
4923 if(k == 0) {
4924 ret += int2char(v >> 2);
4925 slop = v & 3;
4926 k = 1;
4927 }
4928 else if(k == 1) {
4929 ret += int2char((slop << 2) | (v >> 4));
4930 slop = v & 0xf;
4931 k = 2;
4932 }
4933 else if(k == 2) {
4934 ret += int2char(slop);
4935 ret += int2char(v >> 2);
4936 slop = v & 3;
4937 k = 3;
4938 }
4939 else {
4940 ret += int2char((slop << 2) | (v >> 4));
4941 ret += int2char(v & 0xf);
4942 k = 0;
4943 }
4944 }
4945 if(k == 1)
4946 ret += int2char(slop << 2);
4947 return ret;
4948}
4949
4950// convert a base64 string to a byte/number array
4951function b64toBA(s) {
4952 //piggyback on b64tohex for now, optimize later
4953 var h = b64tohex(s);
4954 var i;
4955 var a = new Array();
4956 for(i = 0; 2*i < h.length; ++i) {
4957 a[i] = parseInt(h.substring(2*i,2*i+2),16);
4958 }
4959 return a;
4960}
4961// Depends on jsbn.js and rng.js
4962
4963// Version 1.1: support utf-8 encoding in pkcs1pad2
4964
4965// convert a (hex) string to a bignum object
4966function parseBigInt(str,r) {
4967 return new BigInteger(str,r);
4968}
4969
4970function linebrk(s,n) {
4971 var ret = "";
4972 var i = 0;
4973 while(i + n < s.length) {
4974 ret += s.substring(i,i+n) + "\n";
4975 i += n;
4976 }
4977 return ret + s.substring(i,s.length);
4978}
4979
4980function byte2Hex(b) {
4981 if(b < 0x10)
4982 return "0" + b.toString(16);
4983 else
4984 return b.toString(16);
4985}
4986
4987/**
4988 * PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint
4989 * @param s: the string to encode
4990 * @param n: the size in byte
4991 */
4992function pkcs1pad2(s,n) {
4993 if(n < s.length + 11) { // TODO: fix for utf-8
4994 alert("Message too long for RSA");
4995 return null;
4996 }
4997 var ba = new Array();
4998 var i = s.length - 1;
4999 while(i >= 0 && n > 0) {
5000 var c = s.charCodeAt(i--);
5001 if(c < 128) { // encode using utf-8
5002 ba[--n] = c;
5003 }
5004 else if((c > 127) && (c < 2048)) {
5005 ba[--n] = (c & 63) | 128;
5006 ba[--n] = (c >> 6) | 192;
5007 }
5008 else {
5009 ba[--n] = (c & 63) | 128;
5010 ba[--n] = ((c >> 6) & 63) | 128;
5011 ba[--n] = (c >> 12) | 224;
5012 }
5013 }
5014 ba[--n] = 0;
5015 var rng = new SecureRandom();
5016 var x = new Array();
5017 while(n > 2) { // random non-zero pad
5018 x[0] = 0;
5019 while(x[0] == 0) rng.nextBytes(x);
5020 ba[--n] = x[0];
5021 }
5022 ba[--n] = 2;
5023 ba[--n] = 0;
5024 return new BigInteger(ba);
5025}
5026
5027/**
5028 * "empty" RSA key constructor
5029 * @returns {RSAKey}
5030 */
5031function RSAKey() {
5032 this.n = null;
5033 this.e = 0;
5034 this.d = null;
5035 this.p = null;
5036 this.q = null;
5037 this.dmp1 = null;
5038 this.dmq1 = null;
5039 this.coeff = null;
5040}
5041
5042/**
5043 * Set the public key fields N and e from hex strings
5044 * @param N
5045 * @param E
5046 * @returns {RSASetPublic}
5047 */
5048function RSASetPublic(N,E) {
5049 if(N != null && E != null && N.length > 0 && E.length > 0) {
5050 this.n = parseBigInt(N,16);
5051 this.e = parseInt(E,16);
5052 }
5053 else
5054 alert("Invalid RSA public key");
5055}
5056
5057/**
5058 * Perform raw public operation on "x": return x^e (mod n)
5059 * @param x
5060 * @returns x^e (mod n)
5061 */
5062function RSADoPublic(x) {
5063 return x.modPowInt(this.e, this.n);
5064}
5065
5066/**
5067 * Return the PKCS#1 RSA encryption of "text" as an even-length hex string
5068 */
5069function RSAEncrypt(text) {
5070 var m = pkcs1pad2(text,(this.n.bitLength()+7)>>3);
5071 if(m == null) return null;
5072 var c = this.doPublic(m);
5073 if(c == null) return null;
5074 var h = c.toString(16);
5075 if((h.length & 1) == 0) return h; else return "0" + h;
5076}
5077
5078// Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string
5079//function RSAEncryptB64(text) {
5080// var h = this.encrypt(text);
5081// if(h) return hex2b64(h); else return null;
5082//}
5083
5084// protected
5085RSAKey.prototype.doPublic = RSADoPublic;
5086
5087// public
5088RSAKey.prototype.setPublic = RSASetPublic;
5089RSAKey.prototype.encrypt = RSAEncrypt;
5090//RSAKey.prototype.encrypt_b64 = RSAEncryptB64;
5091// Depends on rsa.js and jsbn2.js
5092
5093// Version 1.1: support utf-8 decoding in pkcs1unpad2
5094
5095// Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext
5096function pkcs1unpad2(d,n) {
5097 var b = d.toByteArray();
5098 var i = 0;
5099 while(i < b.length && b[i] == 0) ++i;
5100 if(b.length-i != n-1 || b[i] != 2)
5101 return null;
5102 ++i;
5103 while(b[i] != 0)
5104 if(++i >= b.length) return null;
5105 var ret = "";
5106 while(++i < b.length) {
5107 var c = b[i] & 255;
5108 if(c < 128) { // utf-8 decode
5109 ret += String.fromCharCode(c);
5110 }
5111 else if((c > 191) && (c < 224)) {
5112 ret += String.fromCharCode(((c & 31) << 6) | (b[i+1] & 63));
5113 ++i;
5114 }
5115 else {
5116 ret += String.fromCharCode(((c & 15) << 12) | ((b[i+1] & 63) << 6) | (b[i+2] & 63));
5117 i += 2;
5118 }
5119 }
5120 return ret;
5121}
5122
5123// Set the private key fields N, e, and d from hex strings
5124function RSASetPrivate(N,E,D) {
5125 if(N != null && E != null && N.length > 0 && E.length > 0) {
5126 this.n = parseBigInt(N,16);
5127 this.e = parseInt(E,16);
5128 this.d = parseBigInt(D,16);
5129 }
5130 else
5131 alert("Invalid RSA private key");
5132}
5133
5134// Set the private key fields N, e, d and CRT params from hex strings
5135function RSASetPrivateEx(N,E,D,P,Q,DP,DQ,C) {
5136 if(N != null && E != null && N.length > 0 && E.length > 0) {
5137 this.n = parseBigInt(N,16);
5138 this.e = parseInt(E,16);
5139 this.d = parseBigInt(D,16);
5140 this.p = parseBigInt(P,16);
5141 this.q = parseBigInt(Q,16);
5142 this.dmp1 = parseBigInt(DP,16);
5143 this.dmq1 = parseBigInt(DQ,16);
5144 this.coeff = parseBigInt(C,16);
5145 }
5146 else
5147 alert("Invalid RSA private key");
5148}
5149
5150/**
5151 * Generate a new random private key B bits long, using public expt E
5152 */
5153function RSAGenerate(B,E) {
5154 var rng = new SecureRandom();
5155 var qs = B>>1;
5156 this.e = parseInt(E,16);
5157 var ee = new BigInteger(E,16);
5158 for(;;) {
5159 for(;;) {
5160 this.p = new BigInteger(B-qs,1,rng);
5161 if(this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.p.isProbablePrime(10)) break;
5162 }
5163 for(;;) {
5164 this.q = new BigInteger(qs,1,rng);
5165 if(this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.q.isProbablePrime(10)) break;
5166 }
5167 if(this.p.compareTo(this.q) <= 0) {
5168 var t = this.p;
5169 this.p = this.q;
5170 this.q = t;
5171 }
5172 var p1 = this.p.subtract(BigInteger.ONE); // p1 = p - 1
5173 var q1 = this.q.subtract(BigInteger.ONE); // q1 = q - 1
5174 var phi = p1.multiply(q1);
5175 if(phi.gcd(ee).compareTo(BigInteger.ONE) == 0) {
5176 this.n = this.p.multiply(this.q); // this.n = p * q
5177 this.d = ee.modInverse(phi); // this.d =
5178 this.dmp1 = this.d.mod(p1); // this.dmp1 = d mod (p - 1)
5179 this.dmq1 = this.d.mod(q1); // this.dmq1 = d mod (q - 1)
5180 this.coeff = this.q.modInverse(this.p); // this.coeff = (q ^ -1) mod p
5181 break;
5182 }
5183 }
5184}
5185
5186/**
5187 * Perform raw private operation on "x": return x^d (mod n)
5188 * @return x^d (mod n)
5189 */
5190function RSADoPrivate(x) {
5191 if(this.p == null || this.q == null)
5192 return x.modPow(this.d, this.n);
5193
5194 // TODO: re-calculate any missing CRT params
5195 var xp = x.mod(this.p).modPow(this.dmp1, this.p); // xp=cp?
5196 var xq = x.mod(this.q).modPow(this.dmq1, this.q); // xq=cq?
5197
5198 while(xp.compareTo(xq) < 0)
5199 xp = xp.add(this.p);
5200 // NOTE:
5201 // xp.subtract(xq) => cp -cq
5202 // xp.subtract(xq).multiply(this.coeff).mod(this.p) => (cp - cq) * u mod p = h
5203 // xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq) => cq + (h * q) = M
5204 return xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq);
5205}
5206
5207// Return the PKCS#1 RSA decryption of "ctext".
5208// "ctext" is an even-length hex string and the output is a plain string.
5209function RSADecrypt(ctext) {
5210 var c = parseBigInt(ctext, 16);
5211 var m = this.doPrivate(c);
5212 if(m == null) return null;
5213 return pkcs1unpad2(m, (this.n.bitLength()+7)>>3);
5214}
5215
5216// Return the PKCS#1 RSA decryption of "ctext".
5217// "ctext" is a Base64-encoded string and the output is a plain string.
5218//function RSAB64Decrypt(ctext) {
5219// var h = b64tohex(ctext);
5220// if(h) return this.decrypt(h); else return null;
5221//}
5222
5223// protected
5224RSAKey.prototype.doPrivate = RSADoPrivate;
5225
5226// public
5227RSAKey.prototype.setPrivate = RSASetPrivate;
5228RSAKey.prototype.setPrivateEx = RSASetPrivateEx;
5229RSAKey.prototype.generate = RSAGenerate;
5230RSAKey.prototype.decrypt = RSADecrypt;
5231//RSAKey.prototype.b64_decrypt = RSAB64Decrypt;
5232/*! rsapem-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
5233 */
5234//
5235// rsa-pem.js - adding function for reading/writing PKCS#1 PEM private key
5236// to RSAKey class.
5237//
5238// version: 1.1 (2012-May-10)
5239//
5240// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
5241//
5242// This software is licensed under the terms of the MIT License.
5243// http://kjur.github.com/jsrsasign/license/
5244//
5245// The above copyright and license notice shall be
5246// included in all copies or substantial portions of the Software.
5247//
5248//
5249// Depends on:
5250//
5251//
5252//
5253// _RSApem_pemToBase64(sPEM)
5254//
5255// removing PEM header, PEM footer and space characters including
5256// new lines from PEM formatted RSA private key string.
5257//
5258
5259function _rsapem_pemToBase64(sPEMPrivateKey) {
5260 var s = sPEMPrivateKey;
5261 s = s.replace("-----BEGIN RSA PRIVATE KEY-----", "");
5262 s = s.replace("-----END RSA PRIVATE KEY-----", "");
5263 s = s.replace(/[ \n]+/g, "");
5264 return s;
5265}
5266
5267function _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey) {
5268 var a = new Array();
5269 var v1 = ASN1HEX.getStartPosOfV_AtObj(hPrivateKey, 0);
5270 var n1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, v1);
5271 var e1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, n1);
5272 var d1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, e1);
5273 var p1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, d1);
5274 var q1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, p1);
5275 var dp1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, q1);
5276 var dq1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dp1);
5277 var co1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dq1);
5278 a.push(v1, n1, e1, d1, p1, q1, dp1, dq1, co1);
5279 return a;
5280}
5281
5282function _rsapem_getHexValueArrayOfChildrenFromHex(hPrivateKey) {
5283 var posArray = _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey);
5284 var v = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[0]);
5285 var n = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[1]);
5286 var e = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[2]);
5287 var d = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[3]);
5288 var p = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[4]);
5289 var q = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[5]);
5290 var dp = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[6]);
5291 var dq = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[7]);
5292 var co = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[8]);
5293 var a = new Array();
5294 a.push(v, n, e, d, p, q, dp, dq, co);
5295 return a;
5296}
5297
5298/**
5299 * read PKCS#1 private key from a string
5300 * @name readPrivateKeyFromPEMString
5301 * @memberOf RSAKey#
5302 * @function
5303 * @param {String} keyPEM string of PKCS#1 private key.
5304 */
5305function _rsapem_readPrivateKeyFromPEMString(keyPEM) {
5306 var keyB64 = _rsapem_pemToBase64(keyPEM);
5307 var keyHex = b64tohex(keyB64) // depends base64.js
5308 var a = _rsapem_getHexValueArrayOfChildrenFromHex(keyHex);
5309 this.setPrivateEx(a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]);
5310}
5311
5312RSAKey.prototype.readPrivateKeyFromPEMString = _rsapem_readPrivateKeyFromPEMString;
5313/*! rsasign-1.2.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
5314 */
5315//
5316// rsa-sign.js - adding signing functions to RSAKey class.
5317//
5318//
5319// version: 1.2.1 (08 May 2012)
5320//
5321// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
5322//
5323// This software is licensed under the terms of the MIT License.
5324// http://kjur.github.com/jsrsasign/license/
5325//
5326// The above copyright and license notice shall be
5327// included in all copies or substantial portions of the Software.
5328
5329//
5330// Depends on:
5331// function sha1.hex(s) of sha1.js
5332// jsbn.js
5333// jsbn2.js
5334// rsa.js
5335// rsa2.js
5336//
5337
5338// keysize / pmstrlen
5339// 512 / 128
5340// 1024 / 256
5341// 2048 / 512
5342// 4096 / 1024
5343
5344/**
5345 * @property {Dictionary} _RSASIGN_DIHEAD
5346 * @description Array of head part of hexadecimal DigestInfo value for hash algorithms.
5347 * You can add any DigestInfo hash algorith for signing.
5348 * See PKCS#1 v2.1 spec (p38).
5349 */
5350var _RSASIGN_DIHEAD = [];
5351_RSASIGN_DIHEAD['sha1'] = "3021300906052b0e03021a05000414";
5352_RSASIGN_DIHEAD['sha256'] = "3031300d060960864801650304020105000420";
5353_RSASIGN_DIHEAD['sha384'] = "3041300d060960864801650304020205000430";
5354_RSASIGN_DIHEAD['sha512'] = "3051300d060960864801650304020305000440";
5355_RSASIGN_DIHEAD['md2'] = "3020300c06082a864886f70d020205000410";
5356_RSASIGN_DIHEAD['md5'] = "3020300c06082a864886f70d020505000410";
5357_RSASIGN_DIHEAD['ripemd160'] = "3021300906052b2403020105000414";
5358
5359/**
5360 * @property {Dictionary} _RSASIGN_HASHHEXFUNC
5361 * @description Array of functions which calculate hash and returns it as hexadecimal.
5362 * You can add any hash algorithm implementations.
5363 */
5364var _RSASIGN_HASHHEXFUNC = [];
5365_RSASIGN_HASHHEXFUNC['sha1'] = function(s){return hex_sha1(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
5366_RSASIGN_HASHHEXFUNC['sha256'] = function(s){return hex_sha256(s);} // http://pajhome.org.uk/crypt/md5/md5.html
5367_RSASIGN_HASHHEXFUNC['sha512'] = function(s){return hex_sha512(s);} // http://pajhome.org.uk/crypt/md5/md5.html
5368_RSASIGN_HASHHEXFUNC['md5'] = function(s){return hex_md5(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
5369_RSASIGN_HASHHEXFUNC['ripemd160'] = function(s){return hex_rmd160(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
5370
5371//@author axelcdv
5372var _RSASIGN_HASHBYTEFUNC = [];
5373_RSASIGN_HASHBYTEFUNC['sha256'] = function(byteArray){return hex_sha256_from_bytes(byteArray);};
5374
5375//_RSASIGN_HASHHEXFUNC['sha1'] = function(s){return sha1.hex(s);} // http://user1.matsumoto.ne.jp/~goma/js/hash.html
5376//_RSASIGN_HASHHEXFUNC['sha256'] = function(s){return sha256.hex;} // http://user1.matsumoto.ne.jp/~goma/js/hash.html
5377
5378var _RE_HEXDECONLY = new RegExp("");
5379_RE_HEXDECONLY.compile("[^0-9a-f]", "gi");
5380
5381// ========================================================================
5382// Signature Generation
5383// ========================================================================
5384
5385function _rsasign_getHexPaddedDigestInfoForString(s, keySize, hashAlg) {
5386 var pmStrLen = keySize / 4;
5387 var hashFunc = _RSASIGN_HASHHEXFUNC[hashAlg];
5388 var sHashHex = hashFunc(s);
5389
5390 var sHead = "0001";
5391 var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex;
5392 var sMid = "";
5393 var fLen = pmStrLen - sHead.length - sTail.length;
5394 for (var i = 0; i < fLen; i += 2) {
5395 sMid += "ff";
5396 }
5397 sPaddedMessageHex = sHead + sMid + sTail;
5398 return sPaddedMessageHex;
5399}
5400
5401
5402//@author: Meki Cheraoui
5403function _rsasign_getHexPaddedDigestInfoForStringHEX(s, keySize, hashAlg) {
5404 var pmStrLen = keySize / 4;
5405 var hashFunc = _RSASIGN_HASHHEXFUNC[hashAlg];
5406 var sHashHex = hashFunc(s);
5407
5408 var sHead = "0001";
5409 var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex;
5410 var sMid = "";
5411 var fLen = pmStrLen - sHead.length - sTail.length;
5412 for (var i = 0; i < fLen; i += 2) {
5413 sMid += "ff";
5414 }
5415 sPaddedMessageHex = sHead + sMid + sTail;
5416 return sPaddedMessageHex;
5417}
5418
5419/**
5420 * Apply padding, then computes the hash of the given byte array, according to the key size and with the hash algorithm
5421 * @param byteArray (byte[])
5422 * @param keySize (int)
5423 * @param hashAlg the hash algorithm to apply (string)
5424 * @return the hash of byteArray
5425 */
5426function _rsasign_getHexPaddedDigestInfoForByteArray(byteArray, keySize, hashAlg){
5427 var pmStrLen = keySize / 4;
5428 var hashFunc = _RSASIGN_HASHBYTEFUNC[hashAlg];
5429 var sHashHex = hashFunc(byteArray); //returns hex hash
5430
5431 var sHead = "0001";
5432 var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex;
5433 var sMid = "";
5434 var fLen = pmStrLen - sHead.length - sTail.length;
5435 for (var i = 0; i < fLen; i += 2) {
5436 sMid += "ff";
5437 }
5438 sPaddedMessageHex = sHead + sMid + sTail;
5439 return sPaddedMessageHex;
5440}
5441
5442function _zeroPaddingOfSignature(hex, bitLength) {
5443 var s = "";
5444 var nZero = bitLength / 4 - hex.length;
5445 for (var i = 0; i < nZero; i++) {
5446 s = s + "0";
5447 }
5448 return s + hex;
5449}
5450
5451/**
5452 * sign for a message string with RSA private key.<br/>
5453 * @name signString
5454 * @memberOf RSAKey#
5455 * @function
5456 * @param {String} s message string to be signed.
5457 * @param {String} hashAlg hash algorithm name for signing.<br/>
5458 * @return returns hexadecimal string of signature value.
5459 */
5460function _rsasign_signString(s, hashAlg) {
5461 //alert("this.n.bitLength() = " + this.n.bitLength());
5462 var hPM = _rsasign_getHexPaddedDigestInfoForString(s, this.n.bitLength(), hashAlg);
5463 var biPaddedMessage = parseBigInt(hPM, 16);
5464 var biSign = this.doPrivate(biPaddedMessage);
5465 var hexSign = biSign.toString(16);
5466 return _zeroPaddingOfSignature(hexSign, this.n.bitLength());
5467}
5468
5469//@author: ucla-cs
5470function _rsasign_signStringHEX(s, hashAlg) {
5471 //alert("this.n.bitLength() = " + this.n.bitLength());
5472 var hPM = _rsasign_getHexPaddedDigestInfoForString(s, this.n.bitLength(), hashAlg);
5473 var biPaddedMessage = parseBigInt(hPM, 16);
5474 var biSign = this.doPrivate(biPaddedMessage);
5475 var hexSign = biSign.toString(16);
5476 return _zeroPaddingOfSignature(hexSign, this.n.bitLength());
5477}
5478
5479
5480/**
5481 * Sign a message byteArray with an RSA private key
5482 * @name signByteArray
5483 * @memberOf RSAKey#
5484 * @function
5485 * @param {byte[]} byteArray
5486 * @param {Sring} hashAlg the hash algorithm to apply
5487 * @param {RSAKey} rsa key to sign with: hack because the context is lost here
5488 * @return hexadecimal string of signature value
5489 */
5490function _rsasign_signByteArray(byteArray, hashAlg, rsaKey) {
5491 var hPM = _rsasign_getHexPaddedDigestInfoForByteArray(byteArray, rsaKey.n.bitLength(), hashAlg); ///hack because the context is lost here
5492 var biPaddedMessage = parseBigInt(hPM, 16);
5493 var biSign = rsaKey.doPrivate(biPaddedMessage); //hack because the context is lost here
5494 var hexSign = biSign.toString(16);
5495 return _zeroPaddingOfSignature(hexSign, rsaKey.n.bitLength()); //hack because the context is lost here
5496}
5497
5498/**
5499 * Sign a byte array with the Sha-256 algorithm
5500 * @param {byte[]} byteArray
5501 * @return hexadecimal string of signature value
5502 */
5503function _rsasign_signByteArrayWithSHA256(byteArray){
5504 return _rsasign_signByteArray(byteArray, 'sha256', this); //Hack because the context is lost in the next function
5505}
5506
5507
5508function _rsasign_signStringWithSHA1(s) {
5509 return _rsasign_signString(s, 'sha1');
5510}
5511
5512function _rsasign_signStringWithSHA256(s) {
5513 return _rsasign_signString(s, 'sha256');
5514}
5515
5516// ========================================================================
5517// Signature Verification
5518// ========================================================================
5519
5520function _rsasign_getDecryptSignatureBI(biSig, hN, hE) {
5521 var rsa = new RSAKey();
5522 rsa.setPublic(hN, hE);
5523 var biDecryptedSig = rsa.doPublic(biSig);
5524 return biDecryptedSig;
5525}
5526
5527function _rsasign_getHexDigestInfoFromSig(biSig, hN, hE) {
5528 var biDecryptedSig = _rsasign_getDecryptSignatureBI(biSig, hN, hE);
5529 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
5530 return hDigestInfo;
5531}
5532
5533function _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo) {
5534 for (var algName in _RSASIGN_DIHEAD) {
5535 var head = _RSASIGN_DIHEAD[algName];
5536 var len = head.length;
5537 if (hDigestInfo.substring(0, len) == head) {
5538 var a = [algName, hDigestInfo.substring(len)];
5539 return a;
5540 }
5541 }
5542 return [];
5543}
5544
5545function _rsasign_verifySignatureWithArgs(sMsg, biSig, hN, hE) {
5546 var hDigestInfo = _rsasign_getHexDigestInfoFromSig(biSig, hN, hE);
5547 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
5548 if (digestInfoAry.length == 0) return false;
5549 var algName = digestInfoAry[0];
5550 var diHashValue = digestInfoAry[1];
5551 var ff = _RSASIGN_HASHHEXFUNC[algName];
5552 var msgHashValue = ff(sMsg);
5553 return (diHashValue == msgHashValue);
5554}
5555
5556function _rsasign_verifyHexSignatureForMessage(hSig, sMsg) {
5557 var biSig = parseBigInt(hSig, 16);
5558 var result = _rsasign_verifySignatureWithArgs(sMsg, biSig,
5559 this.n.toString(16),
5560 this.e.toString(16));
5561 return result;
5562}
5563
5564/**
5565 * verifies a sigature for a message string with RSA public key.<br/>
5566 * @name verifyString
5567 * @memberOf RSAKey#
5568 * @function
5569 * @param {String} sMsg message string to be verified.
5570 * @param {String} hSig hexadecimal string of siganture.<br/>
5571 * non-hexadecimal charactors including new lines will be ignored.
5572 * @return returns 1 if valid, otherwise 0
5573 */
5574function _rsasign_verifyString(sMsg, hSig) {
5575 hSig = hSig.replace(_RE_HEXDECONLY, '');
5576
5577 if(LOG>3)console.log('n is '+this.n);
5578 if(LOG>3)console.log('e is '+this.e);
5579
5580 if (hSig.length != this.n.bitLength() / 4) return 0;
5581 hSig = hSig.replace(/[ \n]+/g, "");
5582 var biSig = parseBigInt(hSig, 16);
5583 var biDecryptedSig = this.doPublic(biSig);
5584 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
5585 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
5586
5587 if (digestInfoAry.length == 0) return false;
5588 var algName = digestInfoAry[0];
5589 var diHashValue = digestInfoAry[1];
5590 var ff = _RSASIGN_HASHHEXFUNC[algName];
5591 var msgHashValue = ff(sMsg);
5592 return (diHashValue == msgHashValue);
5593}
5594
5595/**
5596 * verifies a sigature for a message byte array with RSA public key.<br/>
5597 * @name verifyByteArray
5598 * @memberOf RSAKey#
5599 * @function
5600 * @param {byte[]} byteArray message byte array to be verified.
5601 * @param {String} hSig hexadecimal string of signature.<br/>
5602 * non-hexadecimal charactors including new lines will be ignored.
5603 * @return returns 1 if valid, otherwise 0
5604 */
Wentao Shang882e34e2013-01-05 02:49:51 -08005605function _rsasign_verifyByteArray(byteArray, witness, hSig) {
Wentao Shang0e291c82012-12-02 23:36:29 -08005606 hSig = hSig.replace(_RE_HEXDECONLY, '');
5607
5608 if(LOG>3)console.log('n is '+this.n);
5609 if(LOG>3)console.log('e is '+this.e);
5610
5611 if (hSig.length != this.n.bitLength() / 4) return 0;
5612 hSig = hSig.replace(/[ \n]+/g, "");
5613 var biSig = parseBigInt(hSig, 16);
5614 var biDecryptedSig = this.doPublic(biSig);
5615 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
5616 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
5617
5618 if (digestInfoAry.length == 0) return false;
5619 var algName = digestInfoAry[0];
5620 var diHashValue = digestInfoAry[1];
Wentao Shang882e34e2013-01-05 02:49:51 -08005621 var msgHashValue = null;
5622
5623 if (witness == null) {
5624 var ff = _RSASIGN_HASHBYTEFUNC[algName];
5625 msgHashValue = ff(byteArray);
5626 } else {
5627 // Compute merkle hash
5628 h = hex_sha256_from_bytes(byteArray);
5629 index = witness.path.index;
5630 for (i = witness.path.digestList.length - 1; i >= 0; i--) {
5631 var str = "";
5632 if (index % 2 == 0) {
5633 str = h + witness.path.digestList[i];
5634 } else {
5635 str = witness.path.digestList[i] + h;
5636 }
5637 h = hex_sha256_from_bytes(DataUtils.toNumbers(str));
5638 index = Math.floor(index / 2);
5639 }
5640 msgHashValue = hex_sha256_from_bytes(DataUtils.toNumbers(h));
5641 }
5642 //console.log(diHashValue);
5643 //console.log(msgHashValue);
Wentao Shang0e291c82012-12-02 23:36:29 -08005644 return (diHashValue == msgHashValue);
5645}
5646
Wentao Shang882e34e2013-01-05 02:49:51 -08005647
Wentao Shang0e291c82012-12-02 23:36:29 -08005648RSAKey.prototype.signString = _rsasign_signString;
5649
5650RSAKey.prototype.signByteArray = _rsasign_signByteArray; //@author axelcdv
5651RSAKey.prototype.signByteArrayWithSHA256 = _rsasign_signByteArrayWithSHA256; //@author axelcdv
5652
5653RSAKey.prototype.signStringWithSHA1 = _rsasign_signStringWithSHA1;
5654RSAKey.prototype.signStringWithSHA256 = _rsasign_signStringWithSHA256;
5655RSAKey.prototype.sign = _rsasign_signString;
5656RSAKey.prototype.signWithSHA1 = _rsasign_signStringWithSHA1;
5657RSAKey.prototype.signWithSHA256 = _rsasign_signStringWithSHA256;
5658
5659
5660/*RSAKey.prototype.signStringHEX = _rsasign_signStringHEX;
5661RSAKey.prototype.signStringWithSHA1HEX = _rsasign_signStringWithSHA1HEX;
5662RSAKey.prototype.signStringWithSHA256HEX = _rsasign_signStringWithSHA256HEX;
5663RSAKey.prototype.signHEX = _rsasign_signStringHEX;
5664RSAKey.prototype.signWithSHA1HEX = _rsasign_signStringWithSHA1HEX;
5665RSAKey.prototype.signWithSHA256HEX = _rsasign_signStringWithSHA256HEX;
5666*/
5667
5668RSAKey.prototype.verifyByteArray = _rsasign_verifyByteArray;
5669RSAKey.prototype.verifyString = _rsasign_verifyString;
5670RSAKey.prototype.verifyHexSignatureForMessage = _rsasign_verifyHexSignatureForMessage;
5671RSAKey.prototype.verify = _rsasign_verifyString;
5672RSAKey.prototype.verifyHexSignatureForByteArrayMessage = _rsasign_verifyHexSignatureForMessage;
5673
5674/*
5675RSAKey.prototype.verifyStringHEX = _rsasign_verifyStringHEX;
5676RSAKey.prototype.verifyHexSignatureForMessageHEX = _rsasign_verifyHexSignatureForMessageHEX;
5677RSAKey.prototype.verifyHEX = _rsasign_verifyStringHEX;
5678RSAKey.prototype.verifyHexSignatureForByteArrayMessageHEX = _rsasign_verifyHexSignatureForMessageHEX;
5679*/
5680
5681
5682/**
5683 * @name RSAKey
5684 * @class
5685 * @description Tom Wu's RSA Key class and extension
5686 */
5687/*! asn1hex-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
5688 */
5689//
5690// asn1hex.js - Hexadecimal represented ASN.1 string library
5691//
5692// version: 1.1 (09-May-2012)
5693//
5694// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
5695//
5696// This software is licensed under the terms of the MIT License.
5697// http://kjur.github.com/jsrsasign/license/
5698//
5699// The above copyright and license notice shall be
5700// included in all copies or substantial portions of the Software.
5701//
5702// Depends on:
5703//
5704
5705// MEMO:
5706// f('3082025b02...', 2) ... 82025b ... 3bytes
5707// f('020100', 2) ... 01 ... 1byte
5708// f('0203001...', 2) ... 03 ... 1byte
5709// f('02818003...', 2) ... 8180 ... 2bytes
5710// f('3080....0000', 2) ... 80 ... -1
5711//
5712// Requirements:
5713// - ASN.1 type octet length MUST be 1.
5714// (i.e. ASN.1 primitives like SET, SEQUENCE, INTEGER, OCTETSTRING ...)
5715// -
5716/**
5717 * get byte length for ASN.1 L(length) bytes
5718 * @name getByteLengthOfL_AtObj
5719 * @memberOf ASN1HEX
5720 * @function
5721 * @param {String} s hexadecimal string of ASN.1 DER encoded data
5722 * @param {Number} pos string index
5723 * @return byte length for ASN.1 L(length) bytes
5724 */
5725function _asnhex_getByteLengthOfL_AtObj(s, pos) {
5726 if (s.substring(pos + 2, pos + 3) != '8') return 1;
5727 var i = parseInt(s.substring(pos + 3, pos + 4));
5728 if (i == 0) return -1; // length octet '80' indefinite length
5729 if (0 < i && i < 10) return i + 1; // including '8?' octet;
5730 return -2; // malformed format
5731}
5732
5733
5734/**
5735 * get hexadecimal string for ASN.1 L(length) bytes
5736 * @name getHexOfL_AtObj
5737 * @memberOf ASN1HEX
5738 * @function
5739 * @param {String} s hexadecimal string of ASN.1 DER encoded data
5740 * @param {Number} pos string index
5741 * @return {String} hexadecimal string for ASN.1 L(length) bytes
5742 */
5743function _asnhex_getHexOfL_AtObj(s, pos) {
5744 var len = _asnhex_getByteLengthOfL_AtObj(s, pos);
5745 if (len < 1) return '';
5746 return s.substring(pos + 2, pos + 2 + len * 2);
5747}
5748
5749//
5750// getting ASN.1 length value at the position 'idx' of
5751// hexa decimal string 's'.
5752//
5753// f('3082025b02...', 0) ... 82025b ... ???
5754// f('020100', 0) ... 01 ... 1
5755// f('0203001...', 0) ... 03 ... 3
5756// f('02818003...', 0) ... 8180 ... 128
5757/**
5758 * get integer value of ASN.1 length for ASN.1 data
5759 * @name getIntOfL_AtObj
5760 * @memberOf ASN1HEX
5761 * @function
5762 * @param {String} s hexadecimal string of ASN.1 DER encoded data
5763 * @param {Number} pos string index
5764 * @return ASN.1 L(length) integer value
5765 */
5766function _asnhex_getIntOfL_AtObj(s, pos) {
5767 var hLength = _asnhex_getHexOfL_AtObj(s, pos);
5768 if (hLength == '') return -1;
5769 var bi;
5770 if (parseInt(hLength.substring(0, 1)) < 8) {
5771 bi = parseBigInt(hLength, 16);
5772 } else {
5773 bi = parseBigInt(hLength.substring(2), 16);
5774 }
5775 return bi.intValue();
5776}
5777
5778/**
5779 * get ASN.1 value starting string position for ASN.1 object refered by index 'idx'.
5780 * @name getStartPosOfV_AtObj
5781 * @memberOf ASN1HEX
5782 * @function
5783 * @param {String} s hexadecimal string of ASN.1 DER encoded data
5784 * @param {Number} pos string index
5785 */
5786function _asnhex_getStartPosOfV_AtObj(s, pos) {
5787 var l_len = _asnhex_getByteLengthOfL_AtObj(s, pos);
5788 if (l_len < 0) return l_len;
5789 return pos + (l_len + 1) * 2;
5790}
5791
5792/**
5793 * get hexadecimal string of ASN.1 V(value)
5794 * @name getHexOfV_AtObj
5795 * @memberOf ASN1HEX
5796 * @function
5797 * @param {String} s hexadecimal string of ASN.1 DER encoded data
5798 * @param {Number} pos string index
5799 * @return {String} hexadecimal string of ASN.1 value.
5800 */
5801function _asnhex_getHexOfV_AtObj(s, pos) {
5802 var pos1 = _asnhex_getStartPosOfV_AtObj(s, pos);
5803 var len = _asnhex_getIntOfL_AtObj(s, pos);
5804 return s.substring(pos1, pos1 + len * 2);
5805}
5806
5807/**
5808 * get hexadecimal string of ASN.1 TLV at
5809 * @name getHexOfTLV_AtObj
5810 * @memberOf ASN1HEX
5811 * @function
5812 * @param {String} s hexadecimal string of ASN.1 DER encoded data
5813 * @param {Number} pos string index
5814 * @return {String} hexadecimal string of ASN.1 TLV.
5815 * @since 1.1
5816 */
5817function _asnhex_getHexOfTLV_AtObj(s, pos) {
5818 var hT = s.substr(pos, 2);
5819 var hL = _asnhex_getHexOfL_AtObj(s, pos);
5820 var hV = _asnhex_getHexOfV_AtObj(s, pos);
5821 return hT + hL + hV;
5822}
5823
5824/**
5825 * get next sibling starting index for ASN.1 object string
5826 * @name getPosOfNextSibling_AtObj
5827 * @memberOf ASN1HEX
5828 * @function
5829 * @param {String} s hexadecimal string of ASN.1 DER encoded data
5830 * @param {Number} pos string index
5831 * @return next sibling starting index for ASN.1 object string
5832 */
5833function _asnhex_getPosOfNextSibling_AtObj(s, pos) {
5834 var pos1 = _asnhex_getStartPosOfV_AtObj(s, pos);
5835 var len = _asnhex_getIntOfL_AtObj(s, pos);
5836 return pos1 + len * 2;
5837}
5838
5839/**
5840 * get array of indexes of child ASN.1 objects
5841 * @name getPosArrayOfChildren_AtObj
5842 * @memberOf ASN1HEX
5843 * @function
5844 * @param {String} s hexadecimal string of ASN.1 DER encoded data
5845 * @param {Number} start string index of ASN.1 object
5846 * @return {Array of Number} array of indexes for childen of ASN.1 objects
5847 */
5848function _asnhex_getPosArrayOfChildren_AtObj(h, pos) {
5849 var a = new Array();
5850 var p0 = _asnhex_getStartPosOfV_AtObj(h, pos);
5851 a.push(p0);
5852
5853 var len = _asnhex_getIntOfL_AtObj(h, pos);
5854 var p = p0;
5855 var k = 0;
5856 while (1) {
5857 var pNext = _asnhex_getPosOfNextSibling_AtObj(h, p);
5858 if (pNext == null || (pNext - p0 >= (len * 2))) break;
5859 if (k >= 200) break;
5860
5861 a.push(pNext);
5862 p = pNext;
5863
5864 k++;
5865 }
5866
5867 return a;
5868}
5869
5870/**
5871 * get string index of nth child object of ASN.1 object refered by h, idx
5872 * @name getNthChildIndex_AtObj
5873 * @memberOf ASN1HEX
5874 * @function
5875 * @param {String} h hexadecimal string of ASN.1 DER encoded data
5876 * @param {Number} idx start string index of ASN.1 object
5877 * @param {Number} nth for child
5878 * @return {Number} string index of nth child.
5879 * @since 1.1
5880 */
5881function _asnhex_getNthChildIndex_AtObj(h, idx, nth) {
5882 var a = _asnhex_getPosArrayOfChildren_AtObj(h, idx);
5883 return a[nth];
5884}
5885
5886// ========== decendant methods ==============================
5887
5888/**
5889 * get string index of nth child object of ASN.1 object refered by h, idx
5890 * @name getDecendantIndexByNthList
5891 * @memberOf ASN1HEX
5892 * @function
5893 * @param {String} h hexadecimal string of ASN.1 DER encoded data
5894 * @param {Number} currentIndex start string index of ASN.1 object
5895 * @param {Array of Number} nthList array list of nth
5896 * @return {Number} string index refered by nthList
5897 * @since 1.1
5898 */
5899function _asnhex_getDecendantIndexByNthList(h, currentIndex, nthList) {
5900 if (nthList.length == 0) {
5901 return currentIndex;
5902 }
5903 var firstNth = nthList.shift();
5904 var a = _asnhex_getPosArrayOfChildren_AtObj(h, currentIndex);
5905 return _asnhex_getDecendantIndexByNthList(h, a[firstNth], nthList);
5906}
5907
5908/**
5909 * get hexadecimal string of ASN.1 TLV refered by current index and nth index list.
5910 * @name getDecendantHexTLVByNthList
5911 * @memberOf ASN1HEX
5912 * @function
5913 * @param {String} h hexadecimal string of ASN.1 DER encoded data
5914 * @param {Number} currentIndex start string index of ASN.1 object
5915 * @param {Array of Number} nthList array list of nth
5916 * @return {Number} hexadecimal string of ASN.1 TLV refered by nthList
5917 * @since 1.1
5918 */
5919function _asnhex_getDecendantHexTLVByNthList(h, currentIndex, nthList) {
5920 var idx = _asnhex_getDecendantIndexByNthList(h, currentIndex, nthList);
5921 return _asnhex_getHexOfTLV_AtObj(h, idx);
5922}
5923
5924/**
5925 * get hexadecimal string of ASN.1 V refered by current index and nth index list.
5926 * @name getDecendantHexVByNthList
5927 * @memberOf ASN1HEX
5928 * @function
5929 * @param {String} h hexadecimal string of ASN.1 DER encoded data
5930 * @param {Number} currentIndex start string index of ASN.1 object
5931 * @param {Array of Number} nthList array list of nth
5932 * @return {Number} hexadecimal string of ASN.1 V refered by nthList
5933 * @since 1.1
5934 */
5935function _asnhex_getDecendantHexVByNthList(h, currentIndex, nthList) {
5936 var idx = _asnhex_getDecendantIndexByNthList(h, currentIndex, nthList);
5937 return _asnhex_getHexOfV_AtObj(h, idx);
5938}
5939
5940// ========== class definition ==============================
5941
5942/**
5943 * ASN.1 DER encoded hexadecimal string utility class
5944 * @class ASN.1 DER encoded hexadecimal string utility class
5945 * @author Kenji Urushima
5946 * @version 1.1 (09 May 2012)
5947 * @see <a href="http://kjur.github.com/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a>
5948 * @since 1.1
5949 */
5950function ASN1HEX() {
5951 return ASN1HEX;
5952}
5953
5954ASN1HEX.getByteLengthOfL_AtObj = _asnhex_getByteLengthOfL_AtObj;
5955ASN1HEX.getHexOfL_AtObj = _asnhex_getHexOfL_AtObj;
5956ASN1HEX.getIntOfL_AtObj = _asnhex_getIntOfL_AtObj;
5957ASN1HEX.getStartPosOfV_AtObj = _asnhex_getStartPosOfV_AtObj;
5958ASN1HEX.getHexOfV_AtObj = _asnhex_getHexOfV_AtObj;
5959ASN1HEX.getHexOfTLV_AtObj = _asnhex_getHexOfTLV_AtObj;
5960ASN1HEX.getPosOfNextSibling_AtObj = _asnhex_getPosOfNextSibling_AtObj;
5961ASN1HEX.getPosArrayOfChildren_AtObj = _asnhex_getPosArrayOfChildren_AtObj;
5962ASN1HEX.getNthChildIndex_AtObj = _asnhex_getNthChildIndex_AtObj;
5963ASN1HEX.getDecendantIndexByNthList = _asnhex_getDecendantIndexByNthList;
5964ASN1HEX.getDecendantHexVByNthList = _asnhex_getDecendantHexVByNthList;
5965ASN1HEX.getDecendantHexTLVByNthList = _asnhex_getDecendantHexTLVByNthList;
Jeff Thompson1a338f82012-12-29 17:07:04 -08005966/*! x509-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
5967 */
5968//
5969// x509.js - X509 class to read subject public key from certificate.
5970//
5971// version: 1.1 (10-May-2012)
5972//
5973// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
5974//
5975// This software is licensed under the terms of the MIT License.
5976// http://kjur.github.com/jsrsasign/license
5977//
5978// The above copyright and license notice shall be
5979// included in all copies or substantial portions of the Software.
5980//
5981
5982// Depends:
5983// base64.js
5984// rsa.js
5985// asn1hex.js
5986
5987function _x509_pemToBase64(sCertPEM) {
5988 var s = sCertPEM;
5989 s = s.replace("-----BEGIN CERTIFICATE-----", "");
5990 s = s.replace("-----END CERTIFICATE-----", "");
5991 s = s.replace(/[ \n]+/g, "");
5992 return s;
5993}
5994
5995function _x509_pemToHex(sCertPEM) {
5996 var b64Cert = _x509_pemToBase64(sCertPEM);
5997 var hCert = b64tohex(b64Cert);
5998 return hCert;
5999}
6000
6001function _x509_getHexTbsCertificateFromCert(hCert) {
6002 var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0);
6003 return pTbsCert;
6004}
6005
6006// NOTE: privateKeyUsagePeriod field of X509v2 not supported.
6007// NOTE: v1 and v3 supported
6008function _x509_getSubjectPublicKeyInfoPosFromCertHex(hCert) {
6009 var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0);
6010 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pTbsCert);
6011 if (a.length < 1) return -1;
6012 if (hCert.substring(a[0], a[0] + 10) == "a003020102") { // v3
6013 if (a.length < 6) return -1;
6014 return a[6];
6015 } else {
6016 if (a.length < 5) return -1;
6017 return a[5];
6018 }
6019}
6020
6021// NOTE: Without BITSTRING encapsulation.
6022// If pInfo is supplied, it is the position in hCert of the SubjectPublicKeyInfo.
6023function _x509_getSubjectPublicKeyPosFromCertHex(hCert, pInfo) {
6024 if (pInfo == null)
6025 pInfo = _x509_getSubjectPublicKeyInfoPosFromCertHex(hCert);
6026 if (pInfo == -1) return -1;
6027 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pInfo);
6028
6029 if (a.length != 2) return -1;
6030 var pBitString = a[1];
6031 if (hCert.substring(pBitString, pBitString + 2) != '03') return -1;
6032 var pBitStringV = ASN1HEX.getStartPosOfV_AtObj(hCert, pBitString);
6033
6034 if (hCert.substring(pBitStringV, pBitStringV + 2) != '00') return -1;
6035 return pBitStringV + 2;
6036}
6037
6038// If p is supplied, it is the public key position in hCert.
6039function _x509_getPublicKeyHexArrayFromCertHex(hCert, p) {
6040 if (p == null)
6041 p = _x509_getSubjectPublicKeyPosFromCertHex(hCert);
6042 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, p);
6043 //var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a[3]);
6044 if(LOG>4){
6045 console.log('a is now');
6046 console.log(a);
6047 }
6048
6049 //if (a.length != 2) return [];
6050 if (a.length < 2) return [];
6051
6052 var hN = ASN1HEX.getHexOfV_AtObj(hCert, a[0]);
6053 var hE = ASN1HEX.getHexOfV_AtObj(hCert, a[1]);
6054 if (hN != null && hE != null) {
6055 return [hN, hE];
6056 } else {
6057 return [];
6058 }
6059}
6060
6061function _x509_getPublicKeyHexArrayFromCertPEM(sCertPEM) {
6062 var hCert = _x509_pemToHex(sCertPEM);
6063 var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
6064 return a;
6065}
6066
6067// ===== get basic fields from hex =====================================
6068/**
6069 * get hexadecimal string of serialNumber field of certificate.<br/>
6070 * @name getSerialNumberHex
6071 * @memberOf X509#
6072 * @function
6073 */
6074function _x509_getSerialNumberHex() {
6075 return ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 1]);
6076}
6077
6078/**
6079 * get hexadecimal string of issuer field of certificate.<br/>
6080 * @name getIssuerHex
6081 * @memberOf X509#
6082 * @function
6083 */
6084function _x509_getIssuerHex() {
6085 return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]);
6086}
6087
6088/**
6089 * get string of issuer field of certificate.<br/>
6090 * @name getIssuerString
6091 * @memberOf X509#
6092 * @function
6093 */
6094function _x509_getIssuerString() {
6095 return _x509_hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]));
6096}
6097
6098/**
6099 * get hexadecimal string of subject field of certificate.<br/>
6100 * @name getSubjectHex
6101 * @memberOf X509#
6102 * @function
6103 */
6104function _x509_getSubjectHex() {
6105 return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]);
6106}
6107
6108/**
6109 * get string of subject field of certificate.<br/>
6110 * @name getSubjectString
6111 * @memberOf X509#
6112 * @function
6113 */
6114function _x509_getSubjectString() {
6115 return _x509_hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]));
6116}
6117
6118/**
6119 * get notBefore field string of certificate.<br/>
6120 * @name getNotBefore
6121 * @memberOf X509#
6122 * @function
6123 */
6124function _x509_getNotBefore() {
6125 var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 0]);
6126 s = s.replace(/(..)/g, "%$1");
6127 s = decodeURIComponent(s);
6128 return s;
6129}
6130
6131/**
6132 * get notAfter field string of certificate.<br/>
6133 * @name getNotAfter
6134 * @memberOf X509#
6135 * @function
6136 */
6137function _x509_getNotAfter() {
6138 var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 1]);
6139 s = s.replace(/(..)/g, "%$1");
6140 s = decodeURIComponent(s);
6141 return s;
6142}
6143
6144// ===== read certificate =====================================
6145
6146_x509_DN_ATTRHEX = {
6147 "0603550406": "C",
6148 "060355040a": "O",
6149 "060355040b": "OU",
6150 "0603550403": "CN",
6151 "0603550405": "SN",
6152 "0603550408": "ST",
6153 "0603550407": "L" };
6154
6155function _x509_hex2dn(hDN) {
6156 var s = "";
6157 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hDN, 0);
6158 for (var i = 0; i < a.length; i++) {
6159 var hRDN = ASN1HEX.getHexOfTLV_AtObj(hDN, a[i]);
6160 s = s + "/" + _x509_hex2rdn(hRDN);
6161 }
6162 return s;
6163}
6164
6165function _x509_hex2rdn(hRDN) {
6166 var hType = ASN1HEX.getDecendantHexTLVByNthList(hRDN, 0, [0, 0]);
6167 var hValue = ASN1HEX.getDecendantHexVByNthList(hRDN, 0, [0, 1]);
6168 var type = "";
6169 try { type = _x509_DN_ATTRHEX[hType]; } catch (ex) { type = hType; }
6170 hValue = hValue.replace(/(..)/g, "%$1");
6171 var value = decodeURIComponent(hValue);
6172 return type + "=" + value;
6173}
6174
6175// ===== read certificate =====================================
6176
6177
6178/**
6179 * read PEM formatted X.509 certificate from string.<br/>
6180 * @name readCertPEM
6181 * @memberOf X509#
6182 * @function
6183 * @param {String} sCertPEM string for PEM formatted X.509 certificate
6184 */
6185function _x509_readCertPEM(sCertPEM) {
6186 var hCert = _x509_pemToHex(sCertPEM);
6187 var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
6188 if(LOG>4){
6189 console.log('HEX VALUE IS ' + hCert);
6190 console.log('type of a' + typeof a);
6191 console.log('a VALUE IS ');
6192 console.log(a);
6193 console.log('a[0] VALUE IS ' + a[0]);
6194 console.log('a[1] VALUE IS ' + a[1]);
6195 }
6196 var rsa = new RSAKey();
6197 rsa.setPublic(a[0], a[1]);
6198 this.subjectPublicKeyRSA = rsa;
6199 this.subjectPublicKeyRSA_hN = a[0];
6200 this.subjectPublicKeyRSA_hE = a[1];
6201 this.hex = hCert;
6202}
6203
6204/**
6205 * read hex formatted X.509 certificate from string.
6206 * @name readCertHex
6207 * @memberOf X509#
6208 * @function
6209 * @param {String} hCert string for hex formatted X.509 certificate
6210 */
6211function _x509_readCertHex(hCert) {
6212 hCert = hCert.toLowerCase();
6213 var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
6214 var rsa = new RSAKey();
6215 rsa.setPublic(a[0], a[1]);
6216 this.subjectPublicKeyRSA = rsa;
6217 this.subjectPublicKeyRSA_hN = a[0];
6218 this.subjectPublicKeyRSA_hE = a[1];
6219 this.hex = hCert;
6220}
6221
6222function _x509_readCertPEMWithoutRSAInit(sCertPEM) {
6223 var hCert = _x509_pemToHex(sCertPEM);
6224 var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
6225 this.subjectPublicKeyRSA.setPublic(a[0], a[1]);
6226 this.subjectPublicKeyRSA_hN = a[0];
6227 this.subjectPublicKeyRSA_hE = a[1];
6228 this.hex = hCert;
6229}
6230
6231/**
6232 * X.509 certificate class.<br/>
6233 * @class X.509 certificate class
6234 * @property {RSAKey} subjectPublicKeyRSA Tom Wu's RSAKey object
6235 * @property {String} subjectPublicKeyRSA_hN hexadecimal string for modulus of RSA public key
6236 * @property {String} subjectPublicKeyRSA_hE hexadecimal string for public exponent of RSA public key
6237 * @property {String} hex hexacedimal string for X.509 certificate.
6238 * @author Kenji Urushima
6239 * @version 1.0.1 (08 May 2012)
6240 * @see <a href="http://kjur.github.com/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a>
6241 */
6242function X509() {
6243 this.subjectPublicKeyRSA = null;
6244 this.subjectPublicKeyRSA_hN = null;
6245 this.subjectPublicKeyRSA_hE = null;
6246 this.hex = null;
6247}
6248
6249X509.prototype.readCertPEM = _x509_readCertPEM;
6250X509.prototype.readCertHex = _x509_readCertHex;
6251X509.prototype.readCertPEMWithoutRSAInit = _x509_readCertPEMWithoutRSAInit;
6252X509.prototype.getSerialNumberHex = _x509_getSerialNumberHex;
6253X509.prototype.getIssuerHex = _x509_getIssuerHex;
6254X509.prototype.getSubjectHex = _x509_getSubjectHex;
6255X509.prototype.getIssuerString = _x509_getIssuerString;
6256X509.prototype.getSubjectString = _x509_getSubjectString;
6257X509.prototype.getNotBefore = _x509_getNotBefore;
6258X509.prototype.getNotAfter = _x509_getNotAfter;
6259
Wentao Shang0e291c82012-12-02 23:36:29 -08006260// Copyright (c) 2005 Tom Wu
6261// All Rights Reserved.
6262// See "LICENSE" for details.
6263
6264// Basic JavaScript BN library - subset useful for RSA encryption.
6265
6266// Bits per digit
6267var dbits;
6268
6269// JavaScript engine analysis
6270var canary = 0xdeadbeefcafe;
6271var j_lm = ((canary&0xffffff)==0xefcafe);
6272
6273// (public) Constructor
6274function BigInteger(a,b,c) {
6275 if(a != null)
6276 if("number" == typeof a) this.fromNumber(a,b,c);
6277 else if(b == null && "string" != typeof a) this.fromString(a,256);
6278 else this.fromString(a,b);
6279}
6280
6281// return new, unset BigInteger
6282function nbi() { return new BigInteger(null); }
6283
6284// am: Compute w_j += (x*this_i), propagate carries,
6285// c is initial carry, returns final carry.
6286// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
6287// We need to select the fastest one that works in this environment.
6288
6289// am1: use a single mult and divide to get the high bits,
6290// max digit bits should be 26 because
6291// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
6292function am1(i,x,w,j,c,n) {
6293 while(--n >= 0) {
6294 var v = x*this[i++]+w[j]+c;
6295 c = Math.floor(v/0x4000000);
6296 w[j++] = v&0x3ffffff;
6297 }
6298 return c;
6299}
6300// am2 avoids a big mult-and-extract completely.
6301// Max digit bits should be <= 30 because we do bitwise ops
6302// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
6303function am2(i,x,w,j,c,n) {
6304 var xl = x&0x7fff, xh = x>>15;
6305 while(--n >= 0) {
6306 var l = this[i]&0x7fff;
6307 var h = this[i++]>>15;
6308 var m = xh*l+h*xl;
6309 l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff);
6310 c = (l>>>30)+(m>>>15)+xh*h+(c>>>30);
6311 w[j++] = l&0x3fffffff;
6312 }
6313 return c;
6314}
6315// Alternately, set max digit bits to 28 since some
6316// browsers slow down when dealing with 32-bit numbers.
6317function am3(i,x,w,j,c,n) {
6318 var xl = x&0x3fff, xh = x>>14;
6319 while(--n >= 0) {
6320 var l = this[i]&0x3fff;
6321 var h = this[i++]>>14;
6322 var m = xh*l+h*xl;
6323 l = xl*l+((m&0x3fff)<<14)+w[j]+c;
6324 c = (l>>28)+(m>>14)+xh*h;
6325 w[j++] = l&0xfffffff;
6326 }
6327 return c;
6328}
6329if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
6330 BigInteger.prototype.am = am2;
6331 dbits = 30;
6332}
6333else if(j_lm && (navigator.appName != "Netscape")) {
6334 BigInteger.prototype.am = am1;
6335 dbits = 26;
6336}
6337else { // Mozilla/Netscape seems to prefer am3
6338 BigInteger.prototype.am = am3;
6339 dbits = 28;
6340}
6341
6342BigInteger.prototype.DB = dbits;
6343BigInteger.prototype.DM = ((1<<dbits)-1);
6344BigInteger.prototype.DV = (1<<dbits);
6345
6346var BI_FP = 52;
6347BigInteger.prototype.FV = Math.pow(2,BI_FP);
6348BigInteger.prototype.F1 = BI_FP-dbits;
6349BigInteger.prototype.F2 = 2*dbits-BI_FP;
6350
6351// Digit conversions
6352var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
6353var BI_RC = new Array();
6354var rr,vv;
6355rr = "0".charCodeAt(0);
6356for(vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
6357rr = "a".charCodeAt(0);
6358for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
6359rr = "A".charCodeAt(0);
6360for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
6361
6362function int2char(n) { return BI_RM.charAt(n); }
6363function intAt(s,i) {
6364 var c = BI_RC[s.charCodeAt(i)];
6365 return (c==null)?-1:c;
6366}
6367
6368// (protected) copy this to r
6369function bnpCopyTo(r) {
6370 for(var i = this.t-1; i >= 0; --i) r[i] = this[i];
6371 r.t = this.t;
6372 r.s = this.s;
6373}
6374
6375// (protected) set from integer value x, -DV <= x < DV
6376function bnpFromInt(x) {
6377 this.t = 1;
6378 this.s = (x<0)?-1:0;
6379 if(x > 0) this[0] = x;
6380 else if(x < -1) this[0] = x+DV;
6381 else this.t = 0;
6382}
6383
6384// return bigint initialized to value
6385function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
6386
6387// (protected) set from string and radix
6388function bnpFromString(s,b) {
6389 var k;
6390 if(b == 16) k = 4;
6391 else if(b == 8) k = 3;
6392 else if(b == 256) k = 8; // byte array
6393 else if(b == 2) k = 1;
6394 else if(b == 32) k = 5;
6395 else if(b == 4) k = 2;
6396 else { this.fromRadix(s,b); return; }
6397 this.t = 0;
6398 this.s = 0;
6399 var i = s.length, mi = false, sh = 0;
6400 while(--i >= 0) {
6401 var x = (k==8)?s[i]&0xff:intAt(s,i);
6402 if(x < 0) {
6403 if(s.charAt(i) == "-") mi = true;
6404 continue;
6405 }
6406 mi = false;
6407 if(sh == 0)
6408 this[this.t++] = x;
6409 else if(sh+k > this.DB) {
6410 this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<<sh;
6411 this[this.t++] = (x>>(this.DB-sh));
6412 }
6413 else
6414 this[this.t-1] |= x<<sh;
6415 sh += k;
6416 if(sh >= this.DB) sh -= this.DB;
6417 }
6418 if(k == 8 && (s[0]&0x80) != 0) {
6419 this.s = -1;
6420 if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh;
6421 }
6422 this.clamp();
6423 if(mi) BigInteger.ZERO.subTo(this,this);
6424}
6425
6426// (protected) clamp off excess high words
6427function bnpClamp() {
6428 var c = this.s&this.DM;
6429 while(this.t > 0 && this[this.t-1] == c) --this.t;
6430}
6431
6432// (public) return string representation in given radix
6433function bnToString(b) {
6434 if(this.s < 0) return "-"+this.negate().toString(b);
6435 var k;
6436 if(b == 16) k = 4;
6437 else if(b == 8) k = 3;
6438 else if(b == 2) k = 1;
6439 else if(b == 32) k = 5;
6440 else if(b == 4) k = 2;
6441 else return this.toRadix(b);
6442 var km = (1<<k)-1, d, m = false, r = "", i = this.t;
6443 var p = this.DB-(i*this.DB)%k;
6444 if(i-- > 0) {
6445 if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); }
6446 while(i >= 0) {
6447 if(p < k) {
6448 d = (this[i]&((1<<p)-1))<<(k-p);
6449 d |= this[--i]>>(p+=this.DB-k);
6450 }
6451 else {
6452 d = (this[i]>>(p-=k))&km;
6453 if(p <= 0) { p += this.DB; --i; }
6454 }
6455 if(d > 0) m = true;
6456 if(m) r += int2char(d);
6457 }
6458 }
6459 return m?r:"0";
6460}
6461
6462// (public) -this
6463function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }
6464
6465// (public) |this|
6466function bnAbs() { return (this.s<0)?this.negate():this; }
6467
6468// (public) return + if this > a, - if this < a, 0 if equal
6469function bnCompareTo(a) {
6470 var r = this.s-a.s;
6471 if(r != 0) return r;
6472 var i = this.t;
6473 r = i-a.t;
6474 if(r != 0) return r;
6475 while(--i >= 0) if((r=this[i]-a[i]) != 0) return r;
6476 return 0;
6477}
6478
6479// returns bit length of the integer x
6480function nbits(x) {
6481 var r = 1, t;
6482 if((t=x>>>16) != 0) { x = t; r += 16; }
6483 if((t=x>>8) != 0) { x = t; r += 8; }
6484 if((t=x>>4) != 0) { x = t; r += 4; }
6485 if((t=x>>2) != 0) { x = t; r += 2; }
6486 if((t=x>>1) != 0) { x = t; r += 1; }
6487 return r;
6488}
6489
6490// (public) return the number of bits in "this"
6491function bnBitLength() {
6492 if(this.t <= 0) return 0;
6493 return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM));
6494}
6495
6496// (protected) r = this << n*DB
6497function bnpDLShiftTo(n,r) {
6498 var i;
6499 for(i = this.t-1; i >= 0; --i) r[i+n] = this[i];
6500 for(i = n-1; i >= 0; --i) r[i] = 0;
6501 r.t = this.t+n;
6502 r.s = this.s;
6503}
6504
6505// (protected) r = this >> n*DB
6506function bnpDRShiftTo(n,r) {
6507 for(var i = n; i < this.t; ++i) r[i-n] = this[i];
6508 r.t = Math.max(this.t-n,0);
6509 r.s = this.s;
6510}
6511
6512// (protected) r = this << n
6513function bnpLShiftTo(n,r) {
6514 var bs = n%this.DB;
6515 var cbs = this.DB-bs;
6516 var bm = (1<<cbs)-1;
6517 var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i;
6518 for(i = this.t-1; i >= 0; --i) {
6519 r[i+ds+1] = (this[i]>>cbs)|c;
6520 c = (this[i]&bm)<<bs;
6521 }
6522 for(i = ds-1; i >= 0; --i) r[i] = 0;
6523 r[ds] = c;
6524 r.t = this.t+ds+1;
6525 r.s = this.s;
6526 r.clamp();
6527}
6528
6529// (protected) r = this >> n
6530function bnpRShiftTo(n,r) {
6531 r.s = this.s;
6532 var ds = Math.floor(n/this.DB);
6533 if(ds >= this.t) { r.t = 0; return; }
6534 var bs = n%this.DB;
6535 var cbs = this.DB-bs;
6536 var bm = (1<<bs)-1;
6537 r[0] = this[ds]>>bs;
6538 for(var i = ds+1; i < this.t; ++i) {
6539 r[i-ds-1] |= (this[i]&bm)<<cbs;
6540 r[i-ds] = this[i]>>bs;
6541 }
6542 if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs;
6543 r.t = this.t-ds;
6544 r.clamp();
6545}
6546
6547// (protected) r = this - a
6548function bnpSubTo(a,r) {
6549 var i = 0, c = 0, m = Math.min(a.t,this.t);
6550 while(i < m) {
6551 c += this[i]-a[i];
6552 r[i++] = c&this.DM;
6553 c >>= this.DB;
6554 }
6555 if(a.t < this.t) {
6556 c -= a.s;
6557 while(i < this.t) {
6558 c += this[i];
6559 r[i++] = c&this.DM;
6560 c >>= this.DB;
6561 }
6562 c += this.s;
6563 }
6564 else {
6565 c += this.s;
6566 while(i < a.t) {
6567 c -= a[i];
6568 r[i++] = c&this.DM;
6569 c >>= this.DB;
6570 }
6571 c -= a.s;
6572 }
6573 r.s = (c<0)?-1:0;
6574 if(c < -1) r[i++] = this.DV+c;
6575 else if(c > 0) r[i++] = c;
6576 r.t = i;
6577 r.clamp();
6578}
6579
6580// (protected) r = this * a, r != this,a (HAC 14.12)
6581// "this" should be the larger one if appropriate.
6582function bnpMultiplyTo(a,r) {
6583 var x = this.abs(), y = a.abs();
6584 var i = x.t;
6585 r.t = i+y.t;
6586 while(--i >= 0) r[i] = 0;
6587 for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t);
6588 r.s = 0;
6589 r.clamp();
6590 if(this.s != a.s) BigInteger.ZERO.subTo(r,r);
6591}
6592
6593// (protected) r = this^2, r != this (HAC 14.16)
6594function bnpSquareTo(r) {
6595 var x = this.abs();
6596 var i = r.t = 2*x.t;
6597 while(--i >= 0) r[i] = 0;
6598 for(i = 0; i < x.t-1; ++i) {
6599 var c = x.am(i,x[i],r,2*i,0,1);
6600 if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) {
6601 r[i+x.t] -= x.DV;
6602 r[i+x.t+1] = 1;
6603 }
6604 }
6605 if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1);
6606 r.s = 0;
6607 r.clamp();
6608}
6609
6610// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
6611// r != q, this != m. q or r may be null.
6612function bnpDivRemTo(m,q,r) {
6613 var pm = m.abs();
6614 if(pm.t <= 0) return;
6615 var pt = this.abs();
6616 if(pt.t < pm.t) {
6617 if(q != null) q.fromInt(0);
6618 if(r != null) this.copyTo(r);
6619 return;
6620 }
6621 if(r == null) r = nbi();
6622 var y = nbi(), ts = this.s, ms = m.s;
6623 var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus
6624 if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); }
6625 else { pm.copyTo(y); pt.copyTo(r); }
6626 var ys = y.t;
6627 var y0 = y[ys-1];
6628 if(y0 == 0) return;
6629 var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0);
6630 var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
6631 var i = r.t, j = i-ys, t = (q==null)?nbi():q;
6632 y.dlShiftTo(j,t);
6633 if(r.compareTo(t) >= 0) {
6634 r[r.t++] = 1;
6635 r.subTo(t,r);
6636 }
6637 BigInteger.ONE.dlShiftTo(ys,t);
6638 t.subTo(y,y); // "negative" y so we can replace sub with am later
6639 while(y.t < ys) y[y.t++] = 0;
6640 while(--j >= 0) {
6641 // Estimate quotient digit
6642 var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);
6643 if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out
6644 y.dlShiftTo(j,t);
6645 r.subTo(t,r);
6646 while(r[i] < --qd) r.subTo(t,r);
6647 }
6648 }
6649 if(q != null) {
6650 r.drShiftTo(ys,q);
6651 if(ts != ms) BigInteger.ZERO.subTo(q,q);
6652 }
6653 r.t = ys;
6654 r.clamp();
6655 if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder
6656 if(ts < 0) BigInteger.ZERO.subTo(r,r);
6657}
6658
6659// (public) this mod a
6660function bnMod(a) {
6661 var r = nbi();
6662 this.abs().divRemTo(a,null,r);
6663 if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r);
6664 return r;
6665}
6666
6667// Modular reduction using "classic" algorithm
6668function Classic(m) { this.m = m; }
6669function cConvert(x) {
6670 if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
6671 else return x;
6672}
6673function cRevert(x) { return x; }
6674function cReduce(x) { x.divRemTo(this.m,null,x); }
6675function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
6676function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
6677
6678Classic.prototype.convert = cConvert;
6679Classic.prototype.revert = cRevert;
6680Classic.prototype.reduce = cReduce;
6681Classic.prototype.mulTo = cMulTo;
6682Classic.prototype.sqrTo = cSqrTo;
6683
6684// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
6685// justification:
6686// xy == 1 (mod m)
6687// xy = 1+km
6688// xy(2-xy) = (1+km)(1-km)
6689// x[y(2-xy)] = 1-k^2m^2
6690// x[y(2-xy)] == 1 (mod m^2)
6691// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
6692// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
6693// JS multiply "overflows" differently from C/C++, so care is needed here.
6694function bnpInvDigit() {
6695 if(this.t < 1) return 0;
6696 var x = this[0];
6697 if((x&1) == 0) return 0;
6698 var y = x&3; // y == 1/x mod 2^2
6699 y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4
6700 y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8
6701 y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16
6702 // last step - calculate inverse mod DV directly;
6703 // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
6704 y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits
6705 // we really want the negative inverse, and -DV < y < DV
6706 return (y>0)?this.DV-y:-y;
6707}
6708
6709// Montgomery reduction
6710function Montgomery(m) {
6711 this.m = m;
6712 this.mp = m.invDigit();
6713 this.mpl = this.mp&0x7fff;
6714 this.mph = this.mp>>15;
6715 this.um = (1<<(m.DB-15))-1;
6716 this.mt2 = 2*m.t;
6717}
6718
6719// xR mod m
6720function montConvert(x) {
6721 var r = nbi();
6722 x.abs().dlShiftTo(this.m.t,r);
6723 r.divRemTo(this.m,null,r);
6724 if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r);
6725 return r;
6726}
6727
6728// x/R mod m
6729function montRevert(x) {
6730 var r = nbi();
6731 x.copyTo(r);
6732 this.reduce(r);
6733 return r;
6734}
6735
6736// x = x/R mod m (HAC 14.32)
6737function montReduce(x) {
6738 while(x.t <= this.mt2) // pad x so am has enough room later
6739 x[x.t++] = 0;
6740 for(var i = 0; i < this.m.t; ++i) {
6741 // faster way of calculating u0 = x[i]*mp mod DV
6742 var j = x[i]&0x7fff;
6743 var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM;
6744 // use am to combine the multiply-shift-add into one call
6745 j = i+this.m.t;
6746 x[j] += this.m.am(0,u0,x,i,0,this.m.t);
6747 // propagate carry
6748 while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; }
6749 }
6750 x.clamp();
6751 x.drShiftTo(this.m.t,x);
6752 if(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
6753}
6754
6755// r = "x^2/R mod m"; x != r
6756function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
6757
6758// r = "xy/R mod m"; x,y != r
6759function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
6760
6761Montgomery.prototype.convert = montConvert;
6762Montgomery.prototype.revert = montRevert;
6763Montgomery.prototype.reduce = montReduce;
6764Montgomery.prototype.mulTo = montMulTo;
6765Montgomery.prototype.sqrTo = montSqrTo;
6766
6767// (protected) true iff this is even
6768function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; }
6769
6770// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
6771function bnpExp(e,z) {
6772 if(e > 0xffffffff || e < 1) return BigInteger.ONE;
6773 var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1;
6774 g.copyTo(r);
6775 while(--i >= 0) {
6776 z.sqrTo(r,r2);
6777 if((e&(1<<i)) > 0) z.mulTo(r2,g,r);
6778 else { var t = r; r = r2; r2 = t; }
6779 }
6780 return z.revert(r);
6781}
6782
6783// (public) this^e % m, 0 <= e < 2^32
6784function bnModPowInt(e,m) {
6785 var z;
6786 if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
6787 return this.exp(e,z);
6788}
6789
6790// protected
6791BigInteger.prototype.copyTo = bnpCopyTo;
6792BigInteger.prototype.fromInt = bnpFromInt;
6793BigInteger.prototype.fromString = bnpFromString;
6794BigInteger.prototype.clamp = bnpClamp;
6795BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
6796BigInteger.prototype.drShiftTo = bnpDRShiftTo;
6797BigInteger.prototype.lShiftTo = bnpLShiftTo;
6798BigInteger.prototype.rShiftTo = bnpRShiftTo;
6799BigInteger.prototype.subTo = bnpSubTo;
6800BigInteger.prototype.multiplyTo = bnpMultiplyTo;
6801BigInteger.prototype.squareTo = bnpSquareTo;
6802BigInteger.prototype.divRemTo = bnpDivRemTo;
6803BigInteger.prototype.invDigit = bnpInvDigit;
6804BigInteger.prototype.isEven = bnpIsEven;
6805BigInteger.prototype.exp = bnpExp;
6806
6807// public
6808BigInteger.prototype.toString = bnToString;
6809BigInteger.prototype.negate = bnNegate;
6810BigInteger.prototype.abs = bnAbs;
6811BigInteger.prototype.compareTo = bnCompareTo;
6812BigInteger.prototype.bitLength = bnBitLength;
6813BigInteger.prototype.mod = bnMod;
6814BigInteger.prototype.modPowInt = bnModPowInt;
6815
6816// "constants"
6817BigInteger.ZERO = nbv(0);
6818BigInteger.ONE = nbv(1);
6819// Copyright (c) 2005-2009 Tom Wu
6820// All Rights Reserved.
6821// See "LICENSE" for details.
6822
6823// Extended JavaScript BN functions, required for RSA private ops.
6824
6825// Version 1.1: new BigInteger("0", 10) returns "proper" zero
6826
6827// (public)
6828function bnClone() { var r = nbi(); this.copyTo(r); return r; }
6829
6830// (public) return value as integer
6831function bnIntValue() {
6832 if(this.s < 0) {
6833 if(this.t == 1) return this[0]-this.DV;
6834 else if(this.t == 0) return -1;
6835 }
6836 else if(this.t == 1) return this[0];
6837 else if(this.t == 0) return 0;
6838 // assumes 16 < DB < 32
6839 return ((this[1]&((1<<(32-this.DB))-1))<<this.DB)|this[0];
6840}
6841
6842// (public) return value as byte
6843function bnByteValue() { return (this.t==0)?this.s:(this[0]<<24)>>24; }
6844
6845// (public) return value as short (assumes DB>=16)
6846function bnShortValue() { return (this.t==0)?this.s:(this[0]<<16)>>16; }
6847
6848// (protected) return x s.t. r^x < DV
6849function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); }
6850
6851// (public) 0 if this == 0, 1 if this > 0
6852function bnSigNum() {
6853 if(this.s < 0) return -1;
6854 else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
6855 else return 1;
6856}
6857
6858// (protected) convert to radix string
6859function bnpToRadix(b) {
6860 if(b == null) b = 10;
6861 if(this.signum() == 0 || b < 2 || b > 36) return "0";
6862 var cs = this.chunkSize(b);
6863 var a = Math.pow(b,cs);
6864 var d = nbv(a), y = nbi(), z = nbi(), r = "";
6865 this.divRemTo(d,y,z);
6866 while(y.signum() > 0) {
6867 r = (a+z.intValue()).toString(b).substr(1) + r;
6868 y.divRemTo(d,y,z);
6869 }
6870 return z.intValue().toString(b) + r;
6871}
6872
6873// (protected) convert from radix string
6874function bnpFromRadix(s,b) {
6875 this.fromInt(0);
6876 if(b == null) b = 10;
6877 var cs = this.chunkSize(b);
6878 var d = Math.pow(b,cs), mi = false, j = 0, w = 0;
6879 for(var i = 0; i < s.length; ++i) {
6880 var x = intAt(s,i);
6881 if(x < 0) {
6882 if(s.charAt(i) == "-" && this.signum() == 0) mi = true;
6883 continue;
6884 }
6885 w = b*w+x;
6886 if(++j >= cs) {
6887 this.dMultiply(d);
6888 this.dAddOffset(w,0);
6889 j = 0;
6890 w = 0;
6891 }
6892 }
6893 if(j > 0) {
6894 this.dMultiply(Math.pow(b,j));
6895 this.dAddOffset(w,0);
6896 }
6897 if(mi) BigInteger.ZERO.subTo(this,this);
6898}
6899
6900// (protected) alternate constructor
6901function bnpFromNumber(a,b,c) {
6902 if("number" == typeof b) {
6903 // new BigInteger(int,int,RNG)
6904 if(a < 2) this.fromInt(1);
6905 else {
6906 this.fromNumber(a,c);
6907 if(!this.testBit(a-1)) // force MSB set
6908 this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this);
6909 if(this.isEven()) this.dAddOffset(1,0); // force odd
6910 while(!this.isProbablePrime(b)) {
6911 this.dAddOffset(2,0);
6912 if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this);
6913 }
6914 }
6915 }
6916 else {
6917 // new BigInteger(int,RNG)
6918 var x = new Array(), t = a&7;
6919 x.length = (a>>3)+1;
6920 b.nextBytes(x);
6921 if(t > 0) x[0] &= ((1<<t)-1); else x[0] = 0;
6922 this.fromString(x,256);
6923 }
6924}
6925
6926// (public) convert to bigendian byte array
6927function bnToByteArray() {
6928 var i = this.t, r = new Array();
6929 r[0] = this.s;
6930 var p = this.DB-(i*this.DB)%8, d, k = 0;
6931 if(i-- > 0) {
6932 if(p < this.DB && (d = this[i]>>p) != (this.s&this.DM)>>p)
6933 r[k++] = d|(this.s<<(this.DB-p));
6934 while(i >= 0) {
6935 if(p < 8) {
6936 d = (this[i]&((1<<p)-1))<<(8-p);
6937 d |= this[--i]>>(p+=this.DB-8);
6938 }
6939 else {
6940 d = (this[i]>>(p-=8))&0xff;
6941 if(p <= 0) { p += this.DB; --i; }
6942 }
6943 if((d&0x80) != 0) d |= -256;
6944 if(k == 0 && (this.s&0x80) != (d&0x80)) ++k;
6945 if(k > 0 || d != this.s) r[k++] = d;
6946 }
6947 }
6948 return r;
6949}
6950
6951function bnEquals(a) { return(this.compareTo(a)==0); }
6952function bnMin(a) { return(this.compareTo(a)<0)?this:a; }
6953function bnMax(a) { return(this.compareTo(a)>0)?this:a; }
6954
6955// (protected) r = this op a (bitwise)
6956function bnpBitwiseTo(a,op,r) {
6957 var i, f, m = Math.min(a.t,this.t);
6958 for(i = 0; i < m; ++i) r[i] = op(this[i],a[i]);
6959 if(a.t < this.t) {
6960 f = a.s&this.DM;
6961 for(i = m; i < this.t; ++i) r[i] = op(this[i],f);
6962 r.t = this.t;
6963 }
6964 else {
6965 f = this.s&this.DM;
6966 for(i = m; i < a.t; ++i) r[i] = op(f,a[i]);
6967 r.t = a.t;
6968 }
6969 r.s = op(this.s,a.s);
6970 r.clamp();
6971}
6972
6973// (public) this & a
6974function op_and(x,y) { return x&y; }
6975function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; }
6976
6977// (public) this | a
6978function op_or(x,y) { return x|y; }
6979function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; }
6980
6981// (public) this ^ a
6982function op_xor(x,y) { return x^y; }
6983function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; }
6984
6985// (public) this & ~a
6986function op_andnot(x,y) { return x&~y; }
6987function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; }
6988
6989// (public) ~this
6990function bnNot() {
6991 var r = nbi();
6992 for(var i = 0; i < this.t; ++i) r[i] = this.DM&~this[i];
6993 r.t = this.t;
6994 r.s = ~this.s;
6995 return r;
6996}
6997
6998// (public) this << n
6999function bnShiftLeft(n) {
7000 var r = nbi();
7001 if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r);
7002 return r;
7003}
7004
7005// (public) this >> n
7006function bnShiftRight(n) {
7007 var r = nbi();
7008 if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r);
7009 return r;
7010}
7011
7012// return index of lowest 1-bit in x, x < 2^31
7013function lbit(x) {
7014 if(x == 0) return -1;
7015 var r = 0;
7016 if((x&0xffff) == 0) { x >>= 16; r += 16; }
7017 if((x&0xff) == 0) { x >>= 8; r += 8; }
7018 if((x&0xf) == 0) { x >>= 4; r += 4; }
7019 if((x&3) == 0) { x >>= 2; r += 2; }
7020 if((x&1) == 0) ++r;
7021 return r;
7022}
7023
7024// (public) returns index of lowest 1-bit (or -1 if none)
7025function bnGetLowestSetBit() {
7026 for(var i = 0; i < this.t; ++i)
7027 if(this[i] != 0) return i*this.DB+lbit(this[i]);
7028 if(this.s < 0) return this.t*this.DB;
7029 return -1;
7030}
7031
7032// return number of 1 bits in x
7033function cbit(x) {
7034 var r = 0;
7035 while(x != 0) { x &= x-1; ++r; }
7036 return r;
7037}
7038
7039// (public) return number of set bits
7040function bnBitCount() {
7041 var r = 0, x = this.s&this.DM;
7042 for(var i = 0; i < this.t; ++i) r += cbit(this[i]^x);
7043 return r;
7044}
7045
7046// (public) true iff nth bit is set
7047function bnTestBit(n) {
7048 var j = Math.floor(n/this.DB);
7049 if(j >= this.t) return(this.s!=0);
7050 return((this[j]&(1<<(n%this.DB)))!=0);
7051}
7052
7053// (protected) this op (1<<n)
7054function bnpChangeBit(n,op) {
7055 var r = BigInteger.ONE.shiftLeft(n);
7056 this.bitwiseTo(r,op,r);
7057 return r;
7058}
7059
7060// (public) this | (1<<n)
7061function bnSetBit(n) { return this.changeBit(n,op_or); }
7062
7063// (public) this & ~(1<<n)
7064function bnClearBit(n) { return this.changeBit(n,op_andnot); }
7065
7066// (public) this ^ (1<<n)
7067function bnFlipBit(n) { return this.changeBit(n,op_xor); }
7068
7069// (protected) r = this + a
7070function bnpAddTo(a,r) {
7071 var i = 0, c = 0, m = Math.min(a.t,this.t);
7072 while(i < m) {
7073 c += this[i]+a[i];
7074 r[i++] = c&this.DM;
7075 c >>= this.DB;
7076 }
7077 if(a.t < this.t) {
7078 c += a.s;
7079 while(i < this.t) {
7080 c += this[i];
7081 r[i++] = c&this.DM;
7082 c >>= this.DB;
7083 }
7084 c += this.s;
7085 }
7086 else {
7087 c += this.s;
7088 while(i < a.t) {
7089 c += a[i];
7090 r[i++] = c&this.DM;
7091 c >>= this.DB;
7092 }
7093 c += a.s;
7094 }
7095 r.s = (c<0)?-1:0;
7096 if(c > 0) r[i++] = c;
7097 else if(c < -1) r[i++] = this.DV+c;
7098 r.t = i;
7099 r.clamp();
7100}
7101
7102// (public) this + a
7103function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; }
7104
7105// (public) this - a
7106function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; }
7107
7108// (public) this * a
7109function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; }
7110
7111// (public) this / a
7112function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; }
7113
7114// (public) this % a
7115function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; }
7116
7117// (public) [this/a,this%a]
7118function bnDivideAndRemainder(a) {
7119 var q = nbi(), r = nbi();
7120 this.divRemTo(a,q,r);
7121 return new Array(q,r);
7122}
7123
7124// (protected) this *= n, this >= 0, 1 < n < DV
7125function bnpDMultiply(n) {
7126 this[this.t] = this.am(0,n-1,this,0,0,this.t);
7127 ++this.t;
7128 this.clamp();
7129}
7130
7131// (protected) this += n << w words, this >= 0
7132function bnpDAddOffset(n,w) {
7133 if(n == 0) return;
7134 while(this.t <= w) this[this.t++] = 0;
7135 this[w] += n;
7136 while(this[w] >= this.DV) {
7137 this[w] -= this.DV;
7138 if(++w >= this.t) this[this.t++] = 0;
7139 ++this[w];
7140 }
7141}
7142
7143// A "null" reducer
7144function NullExp() {}
7145function nNop(x) { return x; }
7146function nMulTo(x,y,r) { x.multiplyTo(y,r); }
7147function nSqrTo(x,r) { x.squareTo(r); }
7148
7149NullExp.prototype.convert = nNop;
7150NullExp.prototype.revert = nNop;
7151NullExp.prototype.mulTo = nMulTo;
7152NullExp.prototype.sqrTo = nSqrTo;
7153
7154// (public) this^e
7155function bnPow(e) { return this.exp(e,new NullExp()); }
7156
7157// (protected) r = lower n words of "this * a", a.t <= n
7158// "this" should be the larger one if appropriate.
7159function bnpMultiplyLowerTo(a,n,r) {
7160 var i = Math.min(this.t+a.t,n);
7161 r.s = 0; // assumes a,this >= 0
7162 r.t = i;
7163 while(i > 0) r[--i] = 0;
7164 var j;
7165 for(j = r.t-this.t; i < j; ++i) r[i+this.t] = this.am(0,a[i],r,i,0,this.t);
7166 for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a[i],r,i,0,n-i);
7167 r.clamp();
7168}
7169
7170// (protected) r = "this * a" without lower n words, n > 0
7171// "this" should be the larger one if appropriate.
7172function bnpMultiplyUpperTo(a,n,r) {
7173 --n;
7174 var i = r.t = this.t+a.t-n;
7175 r.s = 0; // assumes a,this >= 0
7176 while(--i >= 0) r[i] = 0;
7177 for(i = Math.max(n-this.t,0); i < a.t; ++i)
7178 r[this.t+i-n] = this.am(n-i,a[i],r,0,0,this.t+i-n);
7179 r.clamp();
7180 r.drShiftTo(1,r);
7181}
7182
7183// Barrett modular reduction
7184function Barrett(m) {
7185 // setup Barrett
7186 this.r2 = nbi();
7187 this.q3 = nbi();
7188 BigInteger.ONE.dlShiftTo(2*m.t,this.r2);
7189 this.mu = this.r2.divide(m);
7190 this.m = m;
7191}
7192
7193function barrettConvert(x) {
7194 if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m);
7195 else if(x.compareTo(this.m) < 0) return x;
7196 else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; }
7197}
7198
7199function barrettRevert(x) { return x; }
7200
7201// x = x mod m (HAC 14.42)
7202function barrettReduce(x) {
7203 x.drShiftTo(this.m.t-1,this.r2);
7204 if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); }
7205 this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3);
7206 this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);
7207 while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1);
7208 x.subTo(this.r2,x);
7209 while(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
7210}
7211
7212// r = x^2 mod m; x != r
7213function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
7214
7215// r = x*y mod m; x,y != r
7216function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
7217
7218Barrett.prototype.convert = barrettConvert;
7219Barrett.prototype.revert = barrettRevert;
7220Barrett.prototype.reduce = barrettReduce;
7221Barrett.prototype.mulTo = barrettMulTo;
7222Barrett.prototype.sqrTo = barrettSqrTo;
7223
7224// (public) this^e % m (HAC 14.85)
7225function bnModPow(e,m) {
7226 var i = e.bitLength(), k, r = nbv(1), z;
7227 if(i <= 0) return r;
7228 else if(i < 18) k = 1;
7229 else if(i < 48) k = 3;
7230 else if(i < 144) k = 4;
7231 else if(i < 768) k = 5;
7232 else k = 6;
7233 if(i < 8)
7234 z = new Classic(m);
7235 else if(m.isEven())
7236 z = new Barrett(m);
7237 else
7238 z = new Montgomery(m);
7239
7240 // precomputation
7241 var g = new Array(), n = 3, k1 = k-1, km = (1<<k)-1;
7242 g[1] = z.convert(this);
7243 if(k > 1) {
7244 var g2 = nbi();
7245 z.sqrTo(g[1],g2);
7246 while(n <= km) {
7247 g[n] = nbi();
7248 z.mulTo(g2,g[n-2],g[n]);
7249 n += 2;
7250 }
7251 }
7252
7253 var j = e.t-1, w, is1 = true, r2 = nbi(), t;
7254 i = nbits(e[j])-1;
7255 while(j >= 0) {
7256 if(i >= k1) w = (e[j]>>(i-k1))&km;
7257 else {
7258 w = (e[j]&((1<<(i+1))-1))<<(k1-i);
7259 if(j > 0) w |= e[j-1]>>(this.DB+i-k1);
7260 }
7261
7262 n = k;
7263 while((w&1) == 0) { w >>= 1; --n; }
7264 if((i -= n) < 0) { i += this.DB; --j; }
7265 if(is1) { // ret == 1, don't bother squaring or multiplying it
7266 g[w].copyTo(r);
7267 is1 = false;
7268 }
7269 else {
7270 while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; }
7271 if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; }
7272 z.mulTo(r2,g[w],r);
7273 }
7274
7275 while(j >= 0 && (e[j]&(1<<i)) == 0) {
7276 z.sqrTo(r,r2); t = r; r = r2; r2 = t;
7277 if(--i < 0) { i = this.DB-1; --j; }
7278 }
7279 }
7280 return z.revert(r);
7281}
7282
7283// (public) gcd(this,a) (HAC 14.54)
7284function bnGCD(a) {
7285 var x = (this.s<0)?this.negate():this.clone();
7286 var y = (a.s<0)?a.negate():a.clone();
7287 if(x.compareTo(y) < 0) { var t = x; x = y; y = t; }
7288 var i = x.getLowestSetBit(), g = y.getLowestSetBit();
7289 if(g < 0) return x;
7290 if(i < g) g = i;
7291 if(g > 0) {
7292 x.rShiftTo(g,x);
7293 y.rShiftTo(g,y);
7294 }
7295 while(x.signum() > 0) {
7296 if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x);
7297 if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y);
7298 if(x.compareTo(y) >= 0) {
7299 x.subTo(y,x);
7300 x.rShiftTo(1,x);
7301 }
7302 else {
7303 y.subTo(x,y);
7304 y.rShiftTo(1,y);
7305 }
7306 }
7307 if(g > 0) y.lShiftTo(g,y);
7308 return y;
7309}
7310
7311// (protected) this % n, n < 2^26
7312function bnpModInt(n) {
7313 if(n <= 0) return 0;
7314 var d = this.DV%n, r = (this.s<0)?n-1:0;
7315 if(this.t > 0)
7316 if(d == 0) r = this[0]%n;
7317 else for(var i = this.t-1; i >= 0; --i) r = (d*r+this[i])%n;
7318 return r;
7319}
7320
7321// (public) 1/this % m (HAC 14.61)
7322function bnModInverse(m) {
7323 var ac = m.isEven();
7324 if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
7325 var u = m.clone(), v = this.clone();
7326 var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
7327 while(u.signum() != 0) {
7328 while(u.isEven()) {
7329 u.rShiftTo(1,u);
7330 if(ac) {
7331 if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); }
7332 a.rShiftTo(1,a);
7333 }
7334 else if(!b.isEven()) b.subTo(m,b);
7335 b.rShiftTo(1,b);
7336 }
7337 while(v.isEven()) {
7338 v.rShiftTo(1,v);
7339 if(ac) {
7340 if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); }
7341 c.rShiftTo(1,c);
7342 }
7343 else if(!d.isEven()) d.subTo(m,d);
7344 d.rShiftTo(1,d);
7345 }
7346 if(u.compareTo(v) >= 0) {
7347 u.subTo(v,u);
7348 if(ac) a.subTo(c,a);
7349 b.subTo(d,b);
7350 }
7351 else {
7352 v.subTo(u,v);
7353 if(ac) c.subTo(a,c);
7354 d.subTo(b,d);
7355 }
7356 }
7357 if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
7358 if(d.compareTo(m) >= 0) return d.subtract(m);
7359 if(d.signum() < 0) d.addTo(m,d); else return d;
7360 if(d.signum() < 0) return d.add(m); else return d;
7361}
7362
7363var 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];
7364var lplim = (1<<26)/lowprimes[lowprimes.length-1];
7365
7366// (public) test primality with certainty >= 1-.5^t
7367function bnIsProbablePrime(t) {
7368 var i, x = this.abs();
7369 if(x.t == 1 && x[0] <= lowprimes[lowprimes.length-1]) {
7370 for(i = 0; i < lowprimes.length; ++i)
7371 if(x[0] == lowprimes[i]) return true;
7372 return false;
7373 }
7374 if(x.isEven()) return false;
7375 i = 1;
7376 while(i < lowprimes.length) {
7377 var m = lowprimes[i], j = i+1;
7378 while(j < lowprimes.length && m < lplim) m *= lowprimes[j++];
7379 m = x.modInt(m);
7380 while(i < j) if(m%lowprimes[i++] == 0) return false;
7381 }
7382 return x.millerRabin(t);
7383}
7384
7385// (protected) true if probably prime (HAC 4.24, Miller-Rabin)
7386function bnpMillerRabin(t) {
7387 var n1 = this.subtract(BigInteger.ONE);
7388 var k = n1.getLowestSetBit();
7389 if(k <= 0) return false;
7390 var r = n1.shiftRight(k);
7391 t = (t+1)>>1;
7392 if(t > lowprimes.length) t = lowprimes.length;
7393 var a = nbi();
7394 for(var i = 0; i < t; ++i) {
7395 a.fromInt(lowprimes[i]);
7396 var y = a.modPow(r,this);
7397 if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {
7398 var j = 1;
7399 while(j++ < k && y.compareTo(n1) != 0) {
7400 y = y.modPowInt(2,this);
7401 if(y.compareTo(BigInteger.ONE) == 0) return false;
7402 }
7403 if(y.compareTo(n1) != 0) return false;
7404 }
7405 }
7406 return true;
7407}
7408
7409// protected
7410BigInteger.prototype.chunkSize = bnpChunkSize;
7411BigInteger.prototype.toRadix = bnpToRadix;
7412BigInteger.prototype.fromRadix = bnpFromRadix;
7413BigInteger.prototype.fromNumber = bnpFromNumber;
7414BigInteger.prototype.bitwiseTo = bnpBitwiseTo;
7415BigInteger.prototype.changeBit = bnpChangeBit;
7416BigInteger.prototype.addTo = bnpAddTo;
7417BigInteger.prototype.dMultiply = bnpDMultiply;
7418BigInteger.prototype.dAddOffset = bnpDAddOffset;
7419BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo;
7420BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo;
7421BigInteger.prototype.modInt = bnpModInt;
7422BigInteger.prototype.millerRabin = bnpMillerRabin;
7423
7424// public
7425BigInteger.prototype.clone = bnClone;
7426BigInteger.prototype.intValue = bnIntValue;
7427BigInteger.prototype.byteValue = bnByteValue;
7428BigInteger.prototype.shortValue = bnShortValue;
7429BigInteger.prototype.signum = bnSigNum;
7430BigInteger.prototype.toByteArray = bnToByteArray;
7431BigInteger.prototype.equals = bnEquals;
7432BigInteger.prototype.min = bnMin;
7433BigInteger.prototype.max = bnMax;
7434BigInteger.prototype.and = bnAnd;
7435BigInteger.prototype.or = bnOr;
7436BigInteger.prototype.xor = bnXor;
7437BigInteger.prototype.andNot = bnAndNot;
7438BigInteger.prototype.not = bnNot;
7439BigInteger.prototype.shiftLeft = bnShiftLeft;
7440BigInteger.prototype.shiftRight = bnShiftRight;
7441BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit;
7442BigInteger.prototype.bitCount = bnBitCount;
7443BigInteger.prototype.testBit = bnTestBit;
7444BigInteger.prototype.setBit = bnSetBit;
7445BigInteger.prototype.clearBit = bnClearBit;
7446BigInteger.prototype.flipBit = bnFlipBit;
7447BigInteger.prototype.add = bnAdd;
7448BigInteger.prototype.subtract = bnSubtract;
7449BigInteger.prototype.multiply = bnMultiply;
7450BigInteger.prototype.divide = bnDivide;
7451BigInteger.prototype.remainder = bnRemainder;
7452BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder;
7453BigInteger.prototype.modPow = bnModPow;
7454BigInteger.prototype.modInverse = bnModInverse;
7455BigInteger.prototype.pow = bnPow;
7456BigInteger.prototype.gcd = bnGCD;
7457BigInteger.prototype.isProbablePrime = bnIsProbablePrime;
7458
7459// BigInteger interfaces not implemented in jsbn:
7460
7461// BigInteger(int signum, byte[] magnitude)
7462// double doubleValue()
7463// float floatValue()
7464// int hashCode()
7465// long longValue()
7466// static BigInteger valueOf(long val)
Wentao Shangb42483a2013-01-03 15:32:32 -08007467/**
7468 * @author: Meki Cherkaoui, Jeff Thompson, Wentao Shang
7469 * See COPYING for copyright and distribution information.
7470 * This class represents the top-level object for communicating with an NDN host.
7471 */
7472
7473var LOG = 0;
7474
7475/**
7476 * settings is an associative array with the following defaults:
7477 * {
7478 * getTransport: function() { return new WebSocketTransport(); }
7479 * getHostAndPort: transport.defaultGetHostAndPort,
Jeff Thompsond771b122013-01-26 19:04:41 -08007480 * host: null, // If null, use getHostAndPort when connecting.
Wentao Shangb42483a2013-01-03 15:32:32 -08007481 * port: 9696,
7482 * onopen: function() { if (LOG > 3) console.log("NDN connection established."); }
7483 * onclose: function() { if (LOG > 3) console.log("NDN connection closed."); }
7484 * }
7485 *
7486 * getHostAndPort is a function, on each call it returns a new { host: host, port: port } or
7487 * null if there are no more hosts.
7488 */
7489var NDN = function NDN(settings) {
7490 settings = (settings || {});
7491 var getTransport = (settings.getTransport || function() { return new WebSocketTransport(); });
7492 this.transport = getTransport();
7493 this.getHostAndPort = (settings.getHostAndPort || this.transport.defaultGetHostAndPort);
Jeff Thompsond771b122013-01-26 19:04:41 -08007494 this.host = (settings.host !== undefined ? settings.host : null);
Wentao Shangb42483a2013-01-03 15:32:32 -08007495 this.port = (settings.port || 9696);
7496 this.readyStatus = NDN.UNOPEN;
Wentao Shangd4607392013-01-24 23:08:49 -08007497 this.verify = (settings.verify !== undefined ? settings.verify : true);
Wentao Shangb42483a2013-01-03 15:32:32 -08007498 // Event handler
7499 this.onopen = (settings.onopen || function() { if (LOG > 3) console.log("NDN connection established."); });
7500 this.onclose = (settings.onclose || function() { if (LOG > 3) console.log("NDN connection closed."); });
Jeff Thompsona46083c2013-01-20 23:55:21 -08007501 this.ccndid = null;
Wentao Shangb42483a2013-01-03 15:32:32 -08007502};
7503
7504NDN.UNOPEN = 0; // created but not opened yet
7505NDN.OPENED = 1; // connection to ccnd opened
7506NDN.CLOSED = 2; // connection to ccnd closed
7507
7508NDN.ccndIdFetcher = new Name('/%C1.M.S.localhost/%C1.M.SRV/ccnd/KEY');
7509
7510NDN.prototype.createRoute = function(host, port) {
7511 this.host=host;
7512 this.port=port;
7513};
7514
7515
7516NDN.KeyStore = new Array();
7517
7518var KeyStoreEntry = function KeyStoreEntry(name, rsa, time) {
7519 this.keyName = name; // KeyName
7520 this.rsaKey = rsa; // RSA key
7521 this.timeStamp = time; // Time Stamp
7522};
7523
7524NDN.addKeyEntry = function(/* KeyStoreEntry */ keyEntry) {
7525 var result = NDN.getKeyByName(keyEntry.keyName);
7526 if (result == null)
7527 NDN.KeyStore.push(keyEntry);
7528 else
7529 result = keyEntry;
7530};
7531
7532NDN.getKeyByName = function(/* KeyName */ name) {
7533 var result = null;
7534
7535 for (var i = 0; i < NDN.KeyStore.length; i++) {
7536 if (NDN.KeyStore[i].keyName.contentName.match(name.contentName)) {
7537 if (result == null ||
7538 NDN.KeyStore[i].keyName.contentName.components.length > result.keyName.contentName.components.length)
7539 result = NDN.KeyStore[i];
7540 }
7541 }
7542
7543 return result;
7544};
7545
7546// For fetching data
7547NDN.PITTable = new Array();
7548
7549var PITEntry = function PITEntry(interest, closure) {
7550 this.interest = interest; // Interest
7551 this.closure = closure; // Closure
Wentao Shangfcb16262013-01-20 14:42:46 -08007552 this.timerID = -1; // Timer ID
Wentao Shangb42483a2013-01-03 15:32:32 -08007553};
7554
7555// Return the longest entry from NDN.PITTable that matches name.
7556NDN.getEntryForExpressedInterest = function(/*Name*/ name) {
7557 // TODO: handle multiple matches? Maybe not from registerPrefix because multiple ContentObject
7558 // could be sent for one Interest?
7559 var result = null;
7560
7561 for (var i = 0; i < NDN.PITTable.length; i++) {
7562 if (NDN.PITTable[i].interest.matches_name(name)) {
7563 if (result == null ||
7564 NDN.PITTable[i].interest.name.components.length > result.interest.name.components.length)
7565 result = NDN.PITTable[i];
7566 }
7567 }
7568
7569 return result;
7570};
7571
Jeff Thompsona46083c2013-01-20 23:55:21 -08007572// For publishing data
7573NDN.CSTable = new Array();
7574
7575var CSEntry = function CSEntry(name, closure) {
7576 this.name = name; // String
7577 this.closure = closure; // Closure
7578};
7579
7580function getEntryForRegisteredPrefix(name) {
7581 for (var i = 0; i < NDN.CSTable.length; i++) {
7582 if (NDN.CSTable[i].name.match(name) != null)
7583 return NDN.CSTable[i];
7584 }
7585 return null;
7586}
7587
Wentao Shangb42483a2013-01-03 15:32:32 -08007588/*
7589 * Return a function that selects a host at random from hostList and returns { host: host, port: port }.
7590 * If no more hosts remain, return null.
7591 */
7592NDN.makeShuffledGetHostAndPort = function(hostList, port) {
7593 // Make a copy.
7594 hostList = hostList.slice(0, hostList.length);
7595 DataUtils.shuffle(hostList);
7596
7597 return function() {
7598 if (hostList.length == 0)
7599 return null;
7600
7601 return { host: hostList.splice(0, 1)[0], port: port };
7602 };
7603};
7604
7605/** Encode name as an Interest. If template is not null, use its attributes.
7606 * Send the interest to host:port, read the entire response and call
7607 * closure.upcall(Closure.UPCALL_CONTENT (or Closure.UPCALL_CONTENT_UNVERIFIED),
7608 * new UpcallInfo(this, interest, 0, contentObject)).
7609 */
7610NDN.prototype.expressInterest = function(
7611 // Name
7612 name,
7613 // Closure
7614 closure,
7615 // Interest
7616 template) {
7617 var interest = new Interest(name);
7618 if (template != null) {
7619 interest.minSuffixComponents = template.minSuffixComponents;
7620 interest.maxSuffixComponents = template.maxSuffixComponents;
7621 interest.publisherPublicKeyDigest = template.publisherPublicKeyDigest;
7622 interest.exclude = template.exclude;
7623 interest.childSelector = template.childSelector;
7624 interest.answerOriginKind = template.answerOriginKind;
7625 interest.scope = template.scope;
7626 interest.interestLifetime = template.interestLifetime;
7627 }
7628 else
7629 interest.interestLifetime = 4000; // default interest timeout value in milliseconds.
7630
7631 if (this.host == null || this.port == null) {
7632 if (this.getHostAndPort == null)
7633 console.log('ERROR: host OR port NOT SET');
Jeff Thompsona5668d52013-01-26 16:23:27 -08007634 else {
7635 var thisNDN = this;
7636 this.connectAndExecute
Jeff Thompsonf668acb2013-01-26 20:29:46 -08007637 (function() { thisNDN.reconnectAndExpressInterest(interest, closure); });
Jeff Thompsona5668d52013-01-26 16:23:27 -08007638 }
Wentao Shangb42483a2013-01-03 15:32:32 -08007639 }
7640 else
Jeff Thompsonf668acb2013-01-26 20:29:46 -08007641 this.reconnectAndExpressInterest(interest, closure);
Wentao Shangb42483a2013-01-03 15:32:32 -08007642};
7643
Jeff Thompson537ce142013-01-26 20:02:48 -08007644/*
Jeff Thompsonf668acb2013-01-26 20:29:46 -08007645 * If the host and port are different than the ones in this.transport, then call
7646 * this.transport.connect to change the connection (or connect for the first time).
7647 * Then call expressInterestHelper.
7648 */
7649NDN.prototype.reconnectAndExpressInterest = function(interest, closure) {
7650 if (this.transport.connectedHost != this.host || this.transport.connectedPort != this.port) {
7651 var thisNDN = this;
7652 this.transport.connect(thisNDN, function() { thisNDN.expressInterestHelper(interest, closure); });
7653 }
7654 else
7655 this.expressInterestHelper(interest, closure);
7656};
7657
7658/*
7659 * Do the work of reconnectAndExpressInterest once we know we are connected. Set the PITTable and call
Jeff Thompson537ce142013-01-26 20:02:48 -08007660 * this.transport.send to send the interest.
7661 */
7662NDN.prototype.expressInterestHelper = function(interest, closure) {
7663 //TODO: check local content store first
7664 if (closure != null) {
7665 var pitEntry = new PITEntry(interest, closure);
7666 // TODO: This needs to be a single thread-safe transaction on a global object.
7667 NDN.PITTable.push(pitEntry);
7668 closure.pitEntry = pitEntry;
7669 }
7670
7671 // Set interest timer
7672 var thisNDN = this;
7673 if (closure != null) {
7674 pitEntry.timerID = setTimeout(function() {
7675 if (LOG > 3) console.log("Interest time out.");
7676
7677 // Remove PIT entry from NDN.PITTable.
7678 // TODO: Make this a thread-safe operation on the global PITTable.
7679 var index = NDN.PITTable.indexOf(pitEntry);
7680 //console.log(NDN.PITTable);
7681 if (index >= 0)
7682 NDN.PITTable.splice(index, 1);
7683 //console.log(NDN.PITTable);
7684 //console.log(pitEntry.interest.name.getName());
7685
7686 // Raise closure callback
7687 closure.upcall(Closure.UPCALL_INTEREST_TIMED_OUT, new UpcallInfo(thisNDN, interest, 0, null));
7688 }, interest.interestLifetime); // interestLifetime is in milliseconds.
7689 //console.log(closure.timerID);
7690 }
7691
7692 this.transport.send(encodeToBinaryInterest(interest));
7693};
7694
Wentao Shangb42483a2013-01-03 15:32:32 -08007695NDN.prototype.registerPrefix = function(name, closure, flag) {
Jeff Thompsond771b122013-01-26 19:04:41 -08007696 var thisNDN = this;
7697 var onConnected = function() {
7698 if (thisNDN.ccndid == null) {
7699 // Fetch ccndid first, then register.
7700 var interest = new Interest(NDN.ccndIdFetcher);
7701 interest.interestLifetime = 4000; // milliseconds
7702 if (LOG>3) console.log('Expressing interest for ccndid from ccnd.');
Jeff Thompsonf668acb2013-01-26 20:29:46 -08007703 thisNDN.reconnectAndExpressInterest
7704 (interest, new NDN.FetchCcndidClosure(thisNDN, name, closure, flag));
Jeff Thompsond771b122013-01-26 19:04:41 -08007705 }
7706 else
7707 thisNDN.registerPrefixHelper(name, closure, flag);
7708 };
Jeff Thompsona46083c2013-01-20 23:55:21 -08007709
Jeff Thompsond771b122013-01-26 19:04:41 -08007710 if (this.host == null || this.port == null) {
7711 if (this.getHostAndPort == null)
7712 console.log('ERROR: host OR port NOT SET');
7713 else
7714 this.connectAndExecute(onConnected);
7715 }
7716 else
7717 onConnected();
7718};
7719
7720/*
7721 * This is a closure to receive the ContentObject for NDN.ccndIdFetcher and call
7722 * registerPrefixHelper(name, callerClosure, flag).
7723 */
7724NDN.FetchCcndidClosure = function FetchCcndidClosure(ndn, name, callerClosure, flag) {
7725 // Inherit from Closure.
7726 Closure.call(this);
7727
7728 this.ndn = ndn;
7729 this.name = name;
7730 this.callerClosure = callerClosure;
7731 this.flag = flag;
7732};
7733
7734NDN.FetchCcndidClosure.prototype.upcall = function(kind, upcallInfo) {
7735 if (kind == Closure.UPCALL_INTEREST_TIMED_OUT) {
7736 console.log("Timeout while requesting the ccndid. Cannot registerPrefix for " +
7737 this.name.to_uri() + " .");
7738 return Closure.RESULT_OK;
7739 }
7740 if (!(kind == Closure.UPCALL_CONTENT ||
7741 kind == Closure.UPCALL_CONTENT_UNVERIFIED))
7742 // The upcall is not for us.
7743 return Closure.RESULT_ERR;
7744
7745 var co = upcallInfo.contentObject;
7746 if (!co.signedInfo || !co.signedInfo.publisher
7747 || !co.signedInfo.publisher.publisherPublicKeyDigest)
7748 console.log
7749 ("ContentObject doesn't have a publisherPublicKeyDigest. Cannot set ccndid and registerPrefix for "
7750 + this.name.to_uri() + " .");
7751 else {
7752 if (LOG>3) console.log('Got ccndid from ccnd.');
7753 this.ndn.ccndid = co.signedInfo.publisher.publisherPublicKeyDigest;
7754 if (LOG>3) console.log(this.ndn.ccndid);
7755
7756 this.ndn.registerPrefixHelper(this.name, this.callerClosure, this.flag);
Jeff Thompsona46083c2013-01-20 23:55:21 -08007757 }
Jeff Thompsond771b122013-01-26 19:04:41 -08007758
7759 return Closure.RESULT_OK;
7760};
7761
Jeff Thompson537ce142013-01-26 20:02:48 -08007762/*
7763 * Do the work of registerPrefix once we know we are connected with a ccndid.
7764 */
Jeff Thompsond771b122013-01-26 19:04:41 -08007765NDN.prototype.registerPrefixHelper = function(name, closure, flag) {
Jeff Thompsona46083c2013-01-20 23:55:21 -08007766 var fe = new ForwardingEntry('selfreg', name, null, null, 3, 2147483647);
7767 var bytes = encodeForwardingEntry(fe);
7768
7769 var si = new SignedInfo();
7770 si.setFields();
7771
7772 var co = new ContentObject(new Name(), si, bytes, new Signature());
7773 co.sign();
7774 var coBinary = encodeToBinaryContentObject(co);
7775
7776 //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');
7777 var nodename = this.ccndid;
7778 var interestName = new Name(['ccnx', nodename, 'selfreg', coBinary]);
7779
7780 var interest = new Interest(interestName);
7781 interest.scope = 1;
7782 if (LOG > 3) console.log('Send Interest registration packet.');
7783
7784 var csEntry = new CSEntry(name.getName(), closure);
7785 NDN.CSTable.push(csEntry);
7786
7787 this.transport.send(encodeToBinaryInterest(interest));
Jeff Thompsona46083c2013-01-20 23:55:21 -08007788};
7789
7790/*
7791 * This is called when an entire binary XML element is received, such as a ContentObject or Interest.
7792 * Look up in the PITTable and call the closure callback.
7793 */
7794NDN.prototype.onReceivedElement = function(element) {
7795 if (LOG>3) console.log('Complete element received. Length ' + element.length + '. Start decoding.');
7796 var decoder = new BinaryXMLDecoder(element);
7797 // Dispatch according to packet type
7798 if (decoder.peekStartElement(CCNProtocolDTags.Interest)) { // Interest packet
7799 if (LOG > 3) console.log('Interest packet received.');
7800
7801 var interest = new Interest();
7802 interest.from_ccnb(decoder);
7803 if (LOG > 3) console.log(interest);
7804 var nameStr = escape(interest.name.getName());
7805 if (LOG > 3) console.log(nameStr);
7806
7807 var entry = getEntryForRegisteredPrefix(nameStr);
7808 if (entry != null) {
7809 //console.log(entry);
7810 var info = new UpcallInfo(this, interest, 0, null);
7811 var ret = entry.closure.upcall(Closure.UPCALL_INTEREST, info);
7812 if (ret == Closure.RESULT_INTEREST_CONSUMED && info.contentObject != null)
7813 this.transport.send(encodeToBinaryContentObject(info.contentObject));
7814 }
7815 } else if (decoder.peekStartElement(CCNProtocolDTags.ContentObject)) { // Content packet
7816 if (LOG > 3) console.log('ContentObject packet received.');
7817
7818 var co = new ContentObject();
7819 co.from_ccnb(decoder);
7820
Jeff Thompsond771b122013-01-26 19:04:41 -08007821 var pitEntry = NDN.getEntryForExpressedInterest(co.name);
7822 if (pitEntry != null) {
7823 //console.log(pitEntry);
7824 // Remove PIT entry from NDN.PITTable
7825 var index = NDN.PITTable.indexOf(pitEntry);
7826 if (index >= 0)
7827 NDN.PITTable.splice(index, 1);
Jeff Thompsona46083c2013-01-20 23:55:21 -08007828
Jeff Thompsond771b122013-01-26 19:04:41 -08007829 var currentClosure = pitEntry.closure;
Jeff Thompsona46083c2013-01-20 23:55:21 -08007830
Jeff Thompsond771b122013-01-26 19:04:41 -08007831 // Cancel interest timer
7832 clearTimeout(pitEntry.timerID);
7833 //console.log("Clear interest timer");
7834 //console.log(currentClosure.timerID);
7835
7836 if (this.verify == false) {
7837 // Pass content up without verifying the signature
7838 currentClosure.upcall(Closure.UPCALL_CONTENT_UNVERIFIED, new UpcallInfo(this, null, 0, co));
7839 return;
Jeff Thompsona46083c2013-01-20 23:55:21 -08007840 }
Wentao Shangd4607392013-01-24 23:08:49 -08007841
Jeff Thompsond771b122013-01-26 19:04:41 -08007842 // Key verification
7843
7844 // Recursive key fetching & verification closure
7845 var KeyFetchClosure = function KeyFetchClosure(content, closure, key, sig, wit) {
7846 this.contentObject = content; // unverified content object
7847 this.closure = closure; // closure corresponding to the contentObject
7848 this.keyName = key; // name of current key to be fetched
7849 this.sigHex = sig; // hex signature string to be verified
7850 this.witness = wit;
7851
7852 Closure.call(this);
7853 };
7854
7855 var thisNDN = this;
7856 KeyFetchClosure.prototype.upcall = function(kind, upcallInfo) {
7857 if (kind == Closure.UPCALL_INTEREST_TIMED_OUT) {
7858 console.log("In KeyFetchClosure.upcall: interest time out.");
7859 console.log(this.keyName.contentName.getName());
7860 } else if (kind == Closure.UPCALL_CONTENT) {
7861 //console.log("In KeyFetchClosure.upcall: signature verification passed");
7862
7863 var rsakey = decodeSubjectPublicKeyInfo(upcallInfo.contentObject.content);
7864 var verified = rsakey.verifyByteArray(this.contentObject.rawSignatureData, this.witness, this.sigHex);
7865
7866 var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
7867 //console.log("raise encapsulated closure");
7868 this.closure.upcall(flag, new UpcallInfo(thisNDN, null, 0, this.contentObject));
7869
7870 // Store key in cache
7871 var keyEntry = new KeyStoreEntry(keylocator.keyName, rsakey, new Date().getTime());
7872 NDN.addKeyEntry(keyEntry);
7873 //console.log(NDN.KeyStore);
7874 } else if (kind == Closure.UPCALL_CONTENT_BAD) {
7875 console.log("In KeyFetchClosure.upcall: signature verification failed");
Wentao Shangd4607392013-01-24 23:08:49 -08007876 }
Jeff Thompsond771b122013-01-26 19:04:41 -08007877 };
Jeff Thompsona46083c2013-01-20 23:55:21 -08007878
Jeff Thompsond771b122013-01-26 19:04:41 -08007879 if (co.signedInfo && co.signedInfo.locator && co.signature) {
7880 if (LOG > 3) console.log("Key verification...");
7881 var sigHex = DataUtils.toHex(co.signature.signature).toLowerCase();
Jeff Thompsona46083c2013-01-20 23:55:21 -08007882
Jeff Thompsond771b122013-01-26 19:04:41 -08007883 var wit = null;
7884 if (co.signature.Witness != null) {
7885 wit = new Witness();
7886 wit.decode(co.signature.Witness);
7887 }
Jeff Thompsona46083c2013-01-20 23:55:21 -08007888
Jeff Thompsond771b122013-01-26 19:04:41 -08007889 var keylocator = co.signedInfo.locator;
7890 if (keylocator.type == KeyLocatorType.KEYNAME) {
7891 if (LOG > 3) console.log("KeyLocator contains KEYNAME");
7892 //var keyname = keylocator.keyName.contentName.getName();
7893 //console.log(nameStr);
7894 //console.log(keyname);
Jeff Thompsona46083c2013-01-20 23:55:21 -08007895
Jeff Thompsond771b122013-01-26 19:04:41 -08007896 if (keylocator.keyName.contentName.match(co.name)) {
7897 if (LOG > 3) console.log("Content is key itself");
Jeff Thompsona46083c2013-01-20 23:55:21 -08007898
Jeff Thompsond771b122013-01-26 19:04:41 -08007899 var rsakey = decodeSubjectPublicKeyInfo(co.content);
7900 var verified = rsakey.verifyByteArray(co.rawSignatureData, wit, sigHex);
7901 var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
7902
7903 currentClosure.upcall(flag, new UpcallInfo(this, null, 0, co));
7904
7905 // SWT: We don't need to store key here since the same key will be
7906 // stored again in the closure.
7907 //var keyEntry = new KeyStoreEntry(keylocator.keyName, rsakey, new Date().getTime());
7908 //NDN.addKeyEntry(keyEntry);
7909 //console.log(NDN.KeyStore);
7910 } else {
7911 // Check local key store
7912 var keyEntry = NDN.getKeyByName(keylocator.keyName);
7913 if (keyEntry) {
7914 // Key found, verify now
7915 if (LOG > 3) console.log("Local key cache hit");
7916 var rsakey = keyEntry.rsaKey;
Jeff Thompsona46083c2013-01-20 23:55:21 -08007917 var verified = rsakey.verifyByteArray(co.rawSignatureData, wit, sigHex);
7918 var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
Jeff Thompsona46083c2013-01-20 23:55:21 -08007919
Jeff Thompsond771b122013-01-26 19:04:41 -08007920 // Raise callback
7921 currentClosure.upcall(flag, new UpcallInfo(this, null, 0, co));
7922 } else {
7923 // Not found, fetch now
7924 if (LOG > 3) console.log("Fetch key according to keylocator");
7925 var nextClosure = new KeyFetchClosure(co, currentClosure, keylocator.keyName, sigHex, wit);
7926 this.expressInterest(keylocator.keyName.contentName.getPrefix(4), nextClosure);
Jeff Thompsona46083c2013-01-20 23:55:21 -08007927 }
Jeff Thompsona46083c2013-01-20 23:55:21 -08007928 }
Jeff Thompsond771b122013-01-26 19:04:41 -08007929 } else if (keylocator.type == KeyLocatorType.KEY) {
7930 if (LOG > 3) console.log("Keylocator contains KEY");
7931
7932 var rsakey = decodeSubjectPublicKeyInfo(co.signedInfo.locator.publicKey);
7933 var verified = rsakey.verifyByteArray(co.rawSignatureData, wit, sigHex);
7934
7935 var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
7936 // Raise callback
7937 currentClosure.upcall(Closure.UPCALL_CONTENT, new UpcallInfo(this, null, 0, co));
7938
7939 // Since KeyLocator does not contain key name for this key,
7940 // we have no way to store it as a key entry in KeyStore.
7941 } else {
7942 var cert = keylocator.certificate;
7943 console.log("KeyLocator contains CERT");
7944 console.log(cert);
7945
7946 // TODO: verify certificate
Jeff Thompsona46083c2013-01-20 23:55:21 -08007947 }
7948 }
7949 }
7950 } else
7951 console.log('Incoming packet is not Interest or ContentObject. Discard now.');
Wentao Shangb42483a2013-01-03 15:32:32 -08007952};
7953
7954/*
7955 * Assume this.getHostAndPort is not null. This is called when this.host is null or its host
Jeff Thompsona5668d52013-01-26 16:23:27 -08007956 * is not alive. Get a host and port, connect, then execute onConnected().
Wentao Shangb42483a2013-01-03 15:32:32 -08007957 */
Jeff Thompsona5668d52013-01-26 16:23:27 -08007958NDN.prototype.connectAndExecute = function(onConnected) {
Wentao Shangb42483a2013-01-03 15:32:32 -08007959 var hostAndPort = this.getHostAndPort();
7960 if (hostAndPort == null) {
7961 console.log('ERROR: No more hosts from getHostAndPort');
7962 this.host = null;
7963 return;
7964 }
7965
7966 if (hostAndPort.host == this.host && hostAndPort.port == this.port) {
7967 console.log('ERROR: The host returned by getHostAndPort is not alive: ' +
7968 this.host + ":" + this.port);
7969 return;
7970 }
7971
7972 this.host = hostAndPort.host;
7973 this.port = hostAndPort.port;
Jeff Thompsona5668d52013-01-26 16:23:27 -08007974 if (LOG>3) console.log("Connect: trying host from getHostAndPort: " + this.host);
Wentao Shangb42483a2013-01-03 15:32:32 -08007975
Jeff Thompsona46083c2013-01-20 23:55:21 -08007976 // Fetch any content.
7977 var interest = new Interest(new Name("/"));
Wentao Shangb42483a2013-01-03 15:32:32 -08007978 interest.interestLifetime = 4000; // milliseconds
7979
7980 var thisNDN = this;
7981 var timerID = setTimeout(function() {
Jeff Thompsona5668d52013-01-26 16:23:27 -08007982 if (LOG>3) console.log("Connect: timeout waiting for host " + thisNDN.host);
Wentao Shangb42483a2013-01-03 15:32:32 -08007983 // Try again.
Jeff Thompsona5668d52013-01-26 16:23:27 -08007984 thisNDN.connectAndExecute(onConnected);
Wentao Shangb42483a2013-01-03 15:32:32 -08007985 }, 3000);
7986
Jeff Thompsonf668acb2013-01-26 20:29:46 -08007987 this.reconnectAndExpressInterest
7988 (interest, new NDN.ConnectClosure(this, onConnected, timerID));
Wentao Shangb42483a2013-01-03 15:32:32 -08007989};
7990
Jeff Thompsona5668d52013-01-26 16:23:27 -08007991NDN.ConnectClosure = function ConnectClosure(ndn, onConnected, timerID) {
Wentao Shangb42483a2013-01-03 15:32:32 -08007992 // Inherit from Closure.
7993 Closure.call(this);
7994
7995 this.ndn = ndn;
Jeff Thompsona5668d52013-01-26 16:23:27 -08007996 this.onConnected = onConnected;
Wentao Shangb42483a2013-01-03 15:32:32 -08007997 this.timerID = timerID;
7998};
7999
8000NDN.ConnectClosure.prototype.upcall = function(kind, upcallInfo) {
8001 if (!(kind == Closure.UPCALL_CONTENT ||
Jeff Thompsona46083c2013-01-20 23:55:21 -08008002 kind == Closure.UPCALL_CONTENT_UNVERIFIED))
Wentao Shangb42483a2013-01-03 15:32:32 -08008003 // The upcall is not for us.
8004 return Closure.RESULT_ERR;
8005
Jeff Thompsona5668d52013-01-26 16:23:27 -08008006 // The host is alive, so cancel the timeout and continue with onConnected().
Wentao Shangb42483a2013-01-03 15:32:32 -08008007 clearTimeout(this.timerID);
Jeff Thompsond771b122013-01-26 19:04:41 -08008008
8009 // Call NDN.onopen after success
8010 this.ndn.readyStatus = NDN.OPENED;
8011 this.ndn.onopen();
8012
Jeff Thompsona5668d52013-01-26 16:23:27 -08008013 this.onConnected();
Wentao Shangb42483a2013-01-03 15:32:32 -08008014
8015 return Closure.RESULT_OK;
8016};
8017
Jeff Thompsona46083c2013-01-20 23:55:21 -08008018/*
8019 * A BinaryXmlElementReader lets you call onReceivedData multiple times which uses a
8020 * BinaryXMLStructureDecoder to detect the end of a binary XML element and calls
8021 * elementListener.onReceivedElement(element) with the element.
8022 * This handles the case where a single call to onReceivedData may contain multiple elements.
8023 */
8024var BinaryXmlElementReader = function BinaryXmlElementReader(elementListener) {
8025 this.elementListener = elementListener;
8026 this.dataParts = [];
8027 this.structureDecoder = new BinaryXMLStructureDecoder();
8028};
8029
8030BinaryXmlElementReader.prototype.onReceivedData = function(/* Uint8Array */ rawData) {
8031 // Process multiple objects in the data.
8032 while(true) {
8033 // Scan the input to check if a whole ccnb object has been read.
8034 this.structureDecoder.seek(0);
8035 if (this.structureDecoder.findElementEnd(rawData)) {
8036 // Got the remainder of an object. Report to the caller.
8037 this.dataParts.push(rawData.subarray(0, this.structureDecoder.offset));
Jeff Thompson537ce142013-01-26 20:02:48 -08008038 var element = DataUtils.concatArrays(this.dataParts);
8039 this.dataParts = [];
8040 try {
8041 this.elementListener.onReceivedElement(element);
8042 } catch (ex) {
8043 console.log("BinaryXmlElementReader: ignoring exception from onReceivedElement: " + ex);
8044 }
Jeff Thompsona46083c2013-01-20 23:55:21 -08008045
8046 // Need to read a new object.
8047 rawData = rawData.subarray(this.structureDecoder.offset, rawData.length);
Jeff Thompsona46083c2013-01-20 23:55:21 -08008048 this.structureDecoder = new BinaryXMLStructureDecoder();
8049 if (rawData.length == 0)
8050 // No more data in the packet.
8051 return;
8052
8053 // else loop back to decode.
8054 }
8055 else {
8056 // Save for a later call to concatArrays so that we only copy data once.
8057 this.dataParts.push(rawData);
8058 if (LOG>3) console.log('Incomplete packet received. Length ' + rawData.length + '. Wait for more input.');
8059 return;
8060 }
8061 }
8062}