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