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