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