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