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