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