blob: e15a29022b9197d73c549efa3a30fc9ebd330aa7 [file] [log] [blame]
Jeff Thompson745026e2012-10-13 12:49:20 -07001/* This file is created by running make-ndn-js.jsm.sh in this directory.
2 * It concatenates ndn-js-header.txt with all the ndn-js source files to
3 * make ndn-js.jsm .
Jeff Thompson754652d2012-11-24 16:23:43 -08004 * author: Jeff Thompson
Jeff Thompson745026e2012-10-13 12:49:20 -07005 * See COPYING for copyright and distribution information.
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07006 */
7
Jeff Thompsone769c512012-11-04 17:25:07 -08008var EXPORTED_SYMBOLS = ["NDN", "Closure", "Name", "Interest", "ContentObject",
Jeff Thompson17a9da82012-11-12 01:11:01 -08009 "DataUtils", "MimeTypes", "XpcomTransport"];
Jeff Thompson08ab3cd2012-10-08 02:56:20 -070010
11Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
12Components.utils.import("resource://gre/modules/NetUtil.jsm");
13
14// LOG is used by some of the NDN code.
15var LOG = 0;
16
17// jsbn.js needs the navigator object which isn't defined in XPCOM, so make a local hack.
18var navigator = {
19 appName: "Netscape"
20};
21
22// Some code calls console.log without checking LOG>0. Until this is cleaned up, make a local hack console.
23var console = {
24 log: function(message) {
25 dump(message + "\n");
26 }
27};
28
Jeff Thompson34419762012-10-15 22:24:12 -070029/*
Jeff Thompson754652d2012-11-24 16:23:43 -080030 * @author: Jeff Thompson
Jeff Thompson34419762012-10-15 22:24:12 -070031 * See COPYING for copyright and distribution information.
32 * Provide the callback closure for the async communication methods in the NDN class.
33 * This is a port of Closure.py from PyCCN, written by:
34 * Derek Kulinski <takeda@takeda.tk>
35 * Jeff Burke <jburke@ucla.edu>
36 */
37
38/*
39 * Create a subclass of Closure and pass an object to async calls.
40 */
41var Closure = function Closure() {
42 // I don't think storing NDN's closure is needed
43 // and it creates a reference loop, as of now both
44 // of those variables are never set -- Derek
45 //
46 // Use instance variables to return data to callback
47 this.ndn_data = null; // this holds the ndn_closure
48 this.ndn_data_dirty = false;
49};
50
51// Upcall result
52Closure.RESULT_ERR = -1; // upcall detected an error
53Closure.RESULT_OK = 0; // normal upcall return
54Closure.RESULT_REEXPRESS = 1; // reexpress the same interest again
55Closure.RESULT_INTEREST_CONSUMED = 2; // upcall claims to consume interest
56Closure.RESULT_VERIFY = 3; // force an unverified result to be verified
Jeff Thompsoncab74c32012-10-21 13:27:28 -070057Closure.RESULT_FETCHKEY = 4; // get the key in the key locator and re-call the interest
58 // with the key available in the local storage
Jeff Thompson34419762012-10-15 22:24:12 -070059
60// Upcall kind
61Closure.UPCALL_FINAL = 0; // handler is about to be deregistered
62Closure.UPCALL_INTEREST = 1; // incoming interest
63Closure.UPCALL_CONSUMED_INTEREST = 2; // incoming interest, someone has answered
64Closure.UPCALL_CONTENT = 3; // incoming verified content
65Closure.UPCALL_INTEREST_TIMED_OUT = 4; // interest timed out
66Closure.UPCALL_CONTENT_UNVERIFIED = 5; // content that has not been verified
67Closure.UPCALL_CONTENT_BAD = 6; // verification failed
68
69/*
70 * Override this in your subclass.
71 * If you're getting strange errors in upcall()
72 * check your code whether you're returning a value.
73 */
74Closure.prototype.upcall = function(kind, upcallInfo) {
75 //dump('upcall ' + this + " " + kind + " " + upcallInfo + "\n");
76 return Closure.RESULT_OK;
77};
78
79var UpcallInfo = function UpcallInfo(ndn, interest, matchedComps, contentObject) {
80 this.ndn = ndn; // NDN object (not used)
81 this.interest = interest; // Interest object
82 this.matchedComps = matchedComps; // int
83 this.contentObject = contentObject; // Content object
84};
85
86UpcallInfo.prototype.toString = function() {
87 var ret = "ndn = " + this.ndn;
88 ret += "\nInterest = " + this.interest;
89 ret += "\nmatchedComps = " + this.matchedComps;
90 ret += "\nContentObject: " + this.contentObject;
91 return ret;
92}
93
Jeff Thompson745026e2012-10-13 12:49:20 -070094/*
Jeff Thompson17a9da82012-11-12 01:11:01 -080095 * @author: Meki Cherkaoui, Jeff Thompson, Wentao Shang
Jeff Thompson745026e2012-10-13 12:49:20 -070096 * See COPYING for copyright and distribution information.
97 * This class represents the top-level object for communicating with an NDN host.
98 */
Jeff Thompson08ab3cd2012-10-08 02:56:20 -070099
Jeff Thompson17a9da82012-11-12 01:11:01 -0800100var LOG = 3;
101
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700102/**
Jeff Thompson17a9da82012-11-12 01:11:01 -0800103 * settings is an associative array with the following defaults:
104 * {
105 * host: 'localhost',
106 * port: 9696,
107 * getTransport: function() { return new WebSocketTransport(); }
108 * }
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700109 */
Jeff Thompson17a9da82012-11-12 01:11:01 -0800110var NDN = function NDN(settings) {
111 settings = (settings || {});
112 this.host = (settings.host || "localhost");
113 this.port = (settings.port || 9696);
114 var getTransport = (settings.getTransport || function() { return new WebSocketTransport(); });
115 this.transport = getTransport();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700116};
117
Jeff Thompson17a9da82012-11-12 01:11:01 -0800118
119/* Java Socket Bridge and XPCOM transport */
120
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700121NDN.prototype.createRoute = function(host,port){
122 this.host=host;
123 this.port=port;
124}
125
Jeff Thompson34419762012-10-15 22:24:12 -0700126/** Encode name as an Interest. If template is not null, use its attributes.
127 * Send the interest to host:port, read the entire response and call
128 * closure.upcall(Closure.UPCALL_CONTENT (or Closure.UPCALL_CONTENT_UNVERIFIED),
Jeff Thompson97f27432012-10-16 00:28:03 -0700129 * new UpcallInfo(this, interest, 0, contentObject)).
Jeff Thompson34419762012-10-15 22:24:12 -0700130 */
131NDN.prototype.expressInterest = function(
132 // Name
133 name,
134 // Closure
135 closure,
136 // Interest
137 template) {
138 if (this.host == null || this.port == null) {
139 dump('ERROR host OR port NOT SET\n');
140 return;
141 }
142
Jeff Thompson17a9da82012-11-12 01:11:01 -0800143 var interest = new Interest(name);
Jeff Thompson34419762012-10-15 22:24:12 -0700144 if (template != null) {
Jeff Thompsoncab74c32012-10-21 13:27:28 -0700145 interest.minSuffixComponents = template.minSuffixComponents;
146 interest.maxSuffixComponents = template.maxSuffixComponents;
147 interest.publisherPublicKeyDigest = template.publisherPublicKeyDigest;
148 interest.exclude = template.exclude;
149 interest.childSelector = template.childSelector;
150 interest.answerOriginKind = template.answerOriginKind;
151 interest.scope = template.scope;
152 interest.interestLifetime = template.interestLifetime;
Jeff Thompson34419762012-10-15 22:24:12 -0700153 }
154 else
Jeff Thompson741108b2012-10-15 23:07:09 -0700155 interest.interestLifetime = 4200;
Jeff Thompson97f27432012-10-16 00:28:03 -0700156
Jeff Thompson17a9da82012-11-12 01:11:01 -0800157 this.transport.expressInterest(this, interest, closure);
158};
159
160
161NDN.prototype.registerPrefix = function(name, closure, flag) {
162 return this.transport.registerPrefix(this, name, closure, flag);
163}
164
165/*
166 * @author: Jeff Thompson
167 * See COPYING for copyright and distribution information.
168 * Implement getAsync and putAsync used by NDN using nsISocketTransportService.
169 * This is used inside Firefox XPCOM modules.
170 */
171
172// Assume already imported the following:
173// Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
174// Components.utils.import("resource://gre/modules/NetUtil.jsm");
175
176var XpcomTransport = function XpcomTransport() {
177};
178
179XpcomTransport.prototype.expressInterest = function(ndn, interest, closure) {
180 var binaryInterest = encodeToBinaryInterest(interest);
181
182 var dataListener = {
Jeff Thompsoncab74c32012-10-21 13:27:28 -0700183 onReceivedData : function(data) {
184 if (data == null || data == undefined || data.length == 0)
185 dump("NDN.expressInterest: received empty data from socket.\n");
Jeff Thompson34419762012-10-15 22:24:12 -0700186 else {
Jeff Thompsoncab74c32012-10-21 13:27:28 -0700187 var decoder = new BinaryXMLDecoder(data);
Jeff Thompson34419762012-10-15 22:24:12 -0700188 var co = new ContentObject();
189 co.from_ccnb(decoder);
190
191 if(LOG>2) {
Jeff Thompsoncab74c32012-10-21 13:27:28 -0700192 dump("DECODED CONTENT OBJECT\n");
Jeff Thompson34419762012-10-15 22:24:12 -0700193 dump(co);
Jeff Thompsoncab74c32012-10-21 13:27:28 -0700194 dump("\n");
Jeff Thompson34419762012-10-15 22:24:12 -0700195 }
Jeff Thompson17a9da82012-11-12 01:11:01 -0800196
Jeff Thompson34419762012-10-15 22:24:12 -0700197 // TODO: verify the content object and set kind to UPCALL_CONTENT.
Jeff Thompson741108b2012-10-15 23:07:09 -0700198 var result = closure.upcall(Closure.UPCALL_CONTENT_UNVERIFIED,
Jeff Thompsoncab74c32012-10-21 13:27:28 -0700199 new UpcallInfo(ndn, interest, 0, co));
200 if (result == Closure.RESULT_OK) {
201 // success
202 }
203 else if (result == Closure.RESULT_ERR)
204 dump("NDN.expressInterest: upcall returned RESULT_ERR.\n");
205 else if (result == Closure.RESULT_REEXPRESS)
Jeff Thompson17a9da82012-11-12 01:11:01 -0800206 XpcomTransport.readAllFromSocket(ndn.host, ndn.port, binaryInterest, dataListener);
Jeff Thompsoncab74c32012-10-21 13:27:28 -0700207 else if (result == Closure.RESULT_VERIFY) {
208 // TODO: force verification of content.
209 }
210 else if (result == Closure.RESULT_FETCHKEY) {
211 // TODO: get the key in the key locator and re-call the interest
212 // with the key available in the local storage.
213 }
Jeff Thompson34419762012-10-15 22:24:12 -0700214 }
215 }
Jeff Thompson17a9da82012-11-12 01:11:01 -0800216 }
217
218 XpcomTransport.readAllFromSocket(ndn.host, ndn.port, binaryInterest, dataListener);
Jeff Thompson34419762012-10-15 22:24:12 -0700219};
220
Jeff Thompson17a9da82012-11-12 01:11:01 -0800221/** Send outputData (Uint8Array) to host:port, read the entire response and call
222 * listener.onReceivedData(data) where data is Uint8Array.
Jeff Thompson6aa338a2012-10-13 23:58:02 -0700223 * Code derived from http://stackoverflow.com/questions/7816386/why-nsiscriptableinputstream-is-not-working .
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700224 */
Jeff Thompson17a9da82012-11-12 01:11:01 -0800225XpcomTransport.readAllFromSocket = function(host, port, outputData, listener) {
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700226 var transportService = Components.classes["@mozilla.org/network/socket-transport-service;1"].getService
Jeff Thompsoncab74c32012-10-21 13:27:28 -0700227 (Components.interfaces.nsISocketTransportService);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700228 var pump = Components.classes["@mozilla.org/network/input-stream-pump;1"].createInstance
Jeff Thompsoncab74c32012-10-21 13:27:28 -0700229 (Components.interfaces.nsIInputStreamPump);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700230 var transport = transportService.createTransport(null, 0, host, port, null);
231 var outStream = transport.openOutputStream(1, 0, 0);
Jeff Thompsoncab74c32012-10-21 13:27:28 -0700232 var rawDataString = DataUtils.toString(outputData);
233 outStream.write(rawDataString, rawDataString.length);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700234 outStream.flush();
235 var inStream = transport.openInputStream(0, 0, 0);
236 var dataListener = {
Jeff Thompson17a9da82012-11-12 01:11:01 -0800237 data: new Uint8Array(0),
Jeff Thompsondad617b2012-10-14 17:11:41 -0700238 structureDecoder: new BinaryXMLStructureDecoder(),
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700239 calledOnReceivedData: false,
240
241 onStartRequest: function (request, context) {
242 },
243 onStopRequest: function (request, context, status) {
244 inStream.close();
245 outStream.close();
246 if (!this.calledOnReceivedData) {
247 this.calledOnReceivedData = true;
248 listener.onReceivedData(this.data);
249 }
250 },
251 onDataAvailable: function (request, context, _inputStream, offset, count) {
Jeff Thompsondad617b2012-10-14 17:11:41 -0700252 if (this.calledOnReceivedData)
253 // Already finished. Ignore extra data.
254 return;
255
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700256 try {
257 // Ignore _inputStream and use inStream.
258 // Use readInputStreamToString to handle binary data.
Jeff Thompson6aa338a2012-10-13 23:58:02 -0700259 var rawData = NetUtil.readInputStreamToString(inStream, count);
Jeff Thompson17a9da82012-11-12 01:11:01 -0800260 this.data = DataUtils.concatFromString(this.data, rawData);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700261
Jeff Thompsondad617b2012-10-14 17:11:41 -0700262 // Scan the input to check if a whole ccnb object has been read.
263 if (this.structureDecoder.findElementEnd(this.data))
264 // Finish.
265 this.onStopRequest();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700266 } catch (ex) {
Jeff Thompson34419762012-10-15 22:24:12 -0700267 dump("readAllFromSocket.onDataAvailable exception: " + ex + "\n");
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700268 }
269 }
270 };
271
272 pump.init(inStream, -1, -1, 0, 0, true);
273 pump.asyncRead(dataListener, null);
274}
275
Jeff Thompson97f27432012-10-16 00:28:03 -0700276
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700277/*
Jeff Thompson754652d2012-11-24 16:23:43 -0800278 * @author: Meki Cheraoui
Jeff Thompson745026e2012-10-13 12:49:20 -0700279 * See COPYING for copyright and distribution information.
280 * This class contains all CCNx tags
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700281 */
282
283
284var CCNProtocolDTags = {
285
286 /**
287 * Note if you add one of these, add it to the reverse string map as well.
288 * Emphasize getting the work done at compile time over trying to make something
289 * flexible and developer error-proof.
290 */
291
292 Any : 13,
293 Name : 14,
294 Component : 15,
295 Certificate : 16,
296 Collection : 17,
297 CompleteName : 18,
298 Content : 19,
299 SignedInfo : 20,
300 ContentDigest : 21,
301 ContentHash : 22,
302 Count : 24,
303 Header : 25,
304 Interest : 26, /* 20090915 */
305 Key : 27,
306 KeyLocator : 28,
307 KeyName : 29,
308 Length : 30,
309 Link : 31,
310 LinkAuthenticator : 32,
311 NameComponentCount : 33, /* DeprecatedInInterest */
312 RootDigest : 36,
313 Signature : 37,
314 Start : 38,
315 Timestamp : 39,
316 Type : 40,
317 Nonce : 41,
318 Scope : 42,
319 Exclude : 43,
320 Bloom : 44,
321 BloomSeed : 45,
322 AnswerOriginKind : 47,
323 InterestLifetime : 48,
324 Witness : 53,
325 SignatureBits : 54,
326 DigestAlgorithm : 55,
327 BlockSize : 56,
328 FreshnessSeconds : 58,
329 FinalBlockID : 59,
330 PublisherPublicKeyDigest : 60,
331 PublisherCertificateDigest : 61,
332 PublisherIssuerKeyDigest : 62,
333 PublisherIssuerCertificateDigest : 63,
334 ContentObject : 64, /* 20090915 */
335 WrappedKey : 65,
336 WrappingKeyIdentifier : 66,
337 WrapAlgorithm : 67,
338 KeyAlgorithm : 68,
339 Label : 69,
340 EncryptedKey : 70,
341 EncryptedNonceKey : 71,
342 WrappingKeyName : 72,
343 Action : 73,
344 FaceID : 74,
345 IPProto : 75,
346 Host : 76,
347 Port : 77,
348 MulticastInterface : 78,
349 ForwardingFlags : 79,
350 FaceInstance : 80,
351 ForwardingEntry : 81,
352 MulticastTTL : 82,
353 MinSuffixComponents : 83,
354 MaxSuffixComponents : 84,
355 ChildSelector : 85,
356 RepositoryInfo : 86,
357 Version : 87,
358 RepositoryVersion : 88,
359 GlobalPrefix : 89,
360 LocalName : 90,
361 Policy : 91,
362 Namespace : 92,
363 GlobalPrefixName : 93,
364 PolicyVersion : 94,
365 KeyValueSet : 95,
366 KeyValuePair : 96,
367 IntegerValue : 97,
368 DecimalValue : 98,
369 StringValue : 99,
370 BinaryValue : 100,
371 NameValue : 101,
372 Entry : 102,
373 ACL : 103,
374 ParameterizedName : 104,
375 Prefix : 105,
376 Suffix : 106,
377 Root : 107,
378 ProfileName : 108,
379 Parameters : 109,
380 InfoString : 110,
381 // 111 unallocated
382 StatusResponse : 112,
383 StatusCode : 113,
384 StatusText : 114,
385
386 // Sync protocol
387 SyncNode : 115,
388 SyncNodeKind : 116,
389 SyncNodeElement : 117,
390 SyncVersion : 118,
391 SyncNodeElements : 119,
392 SyncContentHash : 120,
393 SyncLeafCount : 121,
394 SyncTreeDepth : 122,
395 SyncByteCount : 123,
396 ConfigSlice : 124,
397 ConfigSliceList : 125,
398 ConfigSliceOp : 126,
399
400 // Remember to keep in sync with schema/tagnames.csvsdict
401 CCNProtocolDataUnit : 17702112,
402 CCNPROTOCOL_DATA_UNIT : "CCNProtocolDataUnit"
403};
404
405var CCNProtocolDTagsStrings = [
406 null, null, null, null, null, null, null, null, null, null, null,
407 null, null,
408 "Any", "Name", "Component", "Certificate", "Collection", "CompleteName",
409 "Content", "SignedInfo", "ContentDigest", "ContentHash", null, "Count", "Header",
410 "Interest", "Key", "KeyLocator", "KeyName", "Length", "Link", "LinkAuthenticator",
411 "NameComponentCount", null, null, "RootDigest", "Signature", "Start", "Timestamp", "Type",
412 "Nonce", "Scope", "Exclude", "Bloom", "BloomSeed", null, "AnswerOriginKind",
413 "InterestLifetime", null, null, null, null, "Witness", "SignatureBits", "DigestAlgorithm", "BlockSize",
414 null, "FreshnessSeconds", "FinalBlockID", "PublisherPublicKeyDigest", "PublisherCertificateDigest",
415 "PublisherIssuerKeyDigest", "PublisherIssuerCertificateDigest", "ContentObject",
416 "WrappedKey", "WrappingKeyIdentifier", "WrapAlgorithm", "KeyAlgorithm", "Label",
417 "EncryptedKey", "EncryptedNonceKey", "WrappingKeyName", "Action", "FaceID", "IPProto",
418 "Host", "Port", "MulticastInterface", "ForwardingFlags", "FaceInstance",
419 "ForwardingEntry", "MulticastTTL", "MinSuffixComponents", "MaxSuffixComponents", "ChildSelector",
420 "RepositoryInfo", "Version", "RepositoryVersion", "GlobalPrefix", "LocalName",
421 "Policy", "Namespace", "GlobalPrefixName", "PolicyVersion", "KeyValueSet", "KeyValuePair",
422 "IntegerValue", "DecimalValue", "StringValue", "BinaryValue", "NameValue", "Entry",
423 "ACL", "ParameterizedName", "Prefix", "Suffix", "Root", "ProfileName", "Parameters",
424 "InfoString", null,
425 "StatusResponse", "StatusCode", "StatusText", "SyncNode", "SyncNodeKind", "SyncNodeElement",
426 "SyncVersion", "SyncNodeElements", "SyncContentHash", "SyncLeafCount", "SyncTreeDepth", "SyncByteCount",
427 "ConfigSlice", "ConfigSliceList", "ConfigSliceOp" ];
428
429
430//TESTING
431//console.log(exports.CCNProtocolDTagsStrings[17]);
432
433
434/*
Jeff Thompson754652d2012-11-24 16:23:43 -0800435 * @author: Meki Cheraoui
Jeff Thompson745026e2012-10-13 12:49:20 -0700436 * See COPYING for copyright and distribution information.
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700437 * This class represents CCNTime Objects
438 */
439
440var CCNTime = function CCNTime(
441
442 input) {
443
444
445
446
447 this.NANOS_MAX = 999877929;
448
449 /*if(typeof input =='object'){
450 this.longDate = DataUtils.byteArrayToUnsignedLong(input);
451 this.binaryDate = input;
452 }*/
453 if(typeof input =='number'){
454 this.msec = input;
455 //this.binaryDate = DataUtils.unsignedLongToByteArray(input);
456
457 }
458 else{
459 if(LOG>1) console.log('UNRECOGNIZED TYPE FOR TIME');
460 }
461};
462
463
464CCNTime.prototype.getJavascriptDate = function(){
465 var d = new Date();
466 d.setTime( this.msec );
467 return d
468};
469
470 /**
471 * Create a CCNTime
472 * @param timestamp source timestamp to initialize from, some precision will be lost
473 */
474
475
476 /**
477 * Create a CCNTime from its binary encoding
478 * @param binaryTime12 the binary representation of a CCNTime
479 */
480/*CCNTime.prototype.setDateBinary = function(
481 //byte []
482 binaryTime12) {
483
484
485 if ((null == binaryTime12) || (binaryTime12.length == 0)) {
486 throw new IllegalArgumentException("Invalid binary time!");
487 }
488
489
490 value = 0;
491 for(i = 0; i < binaryTime12.length; i++) {
492 value = value << 8;
493 b = (binaryTime12[i]) & 0xFF;
494 value |= b;
495 }
496
497 //this.date = new Date(value);
498
499};
500
501//byte[]
502CCNTime.prototype.toBinaryTime = function() {
503
504 return this.msec; //unsignedLongToByteArray(this.date.getTime());
505
506}*/
507/*
508unsignedLongToByteArray= function( value) {
509 if( 0 == value )
510 return [0];
511
512 if( 0 <= value && value <= 0x00FF ) {
513 //byte []
514 bb = new Array[1];
515 bb[0] = (value & 0x00FF);
516 return bb;
517 }
518
519
520 //byte []
521 out = null;
522 //int
523 offset = -1;
524 for(var i = 7; i >=0; --i) {
525 //byte
526 b = ((value >> (i * 8)) & 0xFF);
527 if( out == null && b != 0 ) {
528 out = new Array(i+1);//byte[i+1];
529 offset = i;
530 }
531 if( out != null )
532 out[ offset - i ] = b;
533 }
534 return out;
535}*/
536
537
538/*
Jeff Thompson754652d2012-11-24 16:23:43 -0800539 * @author: Meki Cheraoui, Jeff Thompson
Jeff Thompson745026e2012-10-13 12:49:20 -0700540 * See COPYING for copyright and distribution information.
Jeff Thompson10de4592012-10-21 23:54:18 -0700541 * This class represents a Name as an array of components where each is a byte array.
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700542 */
543
Jeff Thompson754652d2012-11-24 16:23:43 -0800544/*
545 * Create a new Name from _components.
546 * If _components is a string, parse it as a URI. Otherwise it is an array of components
547 * where each is a string, byte array, ArrayBuffer or Uint8Array.
548 * Convert and store as an array of Uint8Array.
549 * If a component is a string, encode as utf8.
550 */
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700551var Name = function Name(_components){
Jeff Thompson754652d2012-11-24 16:23:43 -0800552 if( typeof _components == 'string') {
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700553 if(LOG>3)console.log('Content Name String '+_components);
Jeff Thompson754652d2012-11-24 16:23:43 -0800554 this.components = Name.createNameArray(_components);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700555 }
Jeff Thompson754652d2012-11-24 16:23:43 -0800556 else if(typeof _components === 'object'){
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700557 if(LOG>4)console.log('Content Name Array '+_components);
Jeff Thompson754652d2012-11-24 16:23:43 -0800558 this.components = [];
559 for (var i = 0; i < _components.length; ++i)
560 this.add(_components[i]);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700561 }
Jeff Thompson754652d2012-11-24 16:23:43 -0800562 else if(_components==null)
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700563 this.components =[];
Jeff Thompson754652d2012-11-24 16:23:43 -0800564 else
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700565 if(LOG>1)console.log("NO CONTENT NAME GIVEN");
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700566};
567
Jeff Thompsone769c512012-11-04 17:25:07 -0800568Name.prototype.getName = function() {
569 return this.to_uri();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700570};
571
Jeff Thompson754652d2012-11-24 16:23:43 -0800572/* Parse name as a URI and return an array of Uint8Array components.
573 *
574 */
Jeff Thompsone769c512012-11-04 17:25:07 -0800575Name.createNameArray = function(name) {
576 name = name.trim();
577 if (name.length <= 0)
578 return [];
579
580 var iColon = name.indexOf(':');
581 if (iColon >= 0) {
582 // Make sure the colon came before a '/'.
583 var iFirstSlash = name.indexOf('/');
584 if (iFirstSlash < 0 || iColon < iFirstSlash)
585 // Omit the leading protocol such as ccnx:
586 name = name.substr(iColon + 1, name.length - iColon - 1).trim();
Jeff Thompson10de4592012-10-21 23:54:18 -0700587 }
Jeff Thompsone769c512012-11-04 17:25:07 -0800588
589 if (name[0] == '/') {
590 if (name.length >= 2 && name[1] == '/') {
591 // Strip the authority following "//".
592 var iAfterAuthority = name.indexOf('/', 2);
593 if (iAfterAuthority < 0)
594 // Unusual case: there was only an authority.
595 return [];
596 else
597 name = name.substr(iAfterAuthority + 1, name.length - iAfterAuthority - 1).trim();
598 }
599 else
600 name = name.substr(1, name.length - 1).trim();
601 }
602
603 var array = name.split('/');
Jeff Thompson10de4592012-10-21 23:54:18 -0700604
605 // Unescape the components.
606 for (var i = 0; i < array.length; ++i) {
Jeff Thompsone769c512012-11-04 17:25:07 -0800607 var component = unescape(array[i].trim());
Jeff Thompson10de4592012-10-21 23:54:18 -0700608
609 if (component.match(/[^.]/) == null) {
Jeff Thompsone769c512012-11-04 17:25:07 -0800610 // Special case for component of only periods.
611 if (component.length <= 2) {
612 // Zero, one or two periods is illegal. Ignore this componenent to be
613 // consistent with the C implmentation.
614 // This also gets rid of a trailing '/'.
615 array = array.slice(0, i).concat(array.slice(i + 1, array.length));
616 --i;
617 }
Jeff Thompson10de4592012-10-21 23:54:18 -0700618 else
Jeff Thompsone769c512012-11-04 17:25:07 -0800619 // Remove 3 periods.
Jeff Thompson10de4592012-10-21 23:54:18 -0700620 array[i] = component.substr(3, component.length - 3);
621 }
622 else
623 array[i] = component;
Jeff Thompson754652d2012-11-24 16:23:43 -0800624
625 // Change the component to Uint8Array now.
626 array[i] = DataUtils.toNumbersFromString(array[i]);
Jeff Thompson10de4592012-10-21 23:54:18 -0700627 }
628
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700629 return array;
630}
631
632
633Name.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
634 decoder.readStartElement(this.getElementLabel());
635
636
637 this.components = new Array(); //new ArrayList<byte []>();
638
639 while (decoder.peekStartElement(CCNProtocolDTags.Component)) {
640 this.add(decoder.readBinaryElement(CCNProtocolDTags.Component));
641 }
642
643 decoder.readEndElement();
644};
645
646Name.prototype.to_ccnb = function(/*XMLEncoder*/ encoder) {
647
648 if( this.components ==null )
649 throw new Error("CANNOT ENCODE EMPTY CONTENT NAME");
650
651 encoder.writeStartElement(this.getElementLabel());
652 var count = this.components.length;
653 for (var i=0; i < count; i++) {
654 encoder.writeElement(CCNProtocolDTags.Component, this.components[i]);
655 }
656 encoder.writeEndElement();
657};
658
659Name.prototype.getElementLabel = function(){
660 return CCNProtocolDTags.Name;
661};
662
Jeff Thompson754652d2012-11-24 16:23:43 -0800663/*
664 * component is a string, byte array, ArrayBuffer or Uint8Array.
665 * Convert to Uint8Array and add to this Name.
666 * If a component is a string, encode as utf8.
667 * Return the converted value.
668 */
669Name.prototype.add = function(component){
670 var result = null;
671 if(typeof component == 'string')
672 result = DataUtils.stringToUtf8Array(component);
673 else if(typeof component == 'object' && component instanceof Array)
674 result = new Uint8Array(component);
675 else if(typeof component == 'object' && component instanceof Uint8Array)
676 result = new Uint8Array(component);
677 else if(typeof component == 'object' && component instanceof ArrayBuffer)
678 // Make a copy.
679 result = new Uint8Array(component.slice(0, component.byteLength));
680 else
681 if(LOG>4)console.log('NAME COMPONENT INVALID');
682
683 return this.components.push(result);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700684};
685
Jeff Thompson10de4592012-10-21 23:54:18 -0700686// Return the escaped name string according to "CCNx URI Scheme". Does not include "ccnx:".
687Name.prototype.to_uri = function() {
688 var result = "";
689
690 for(var i = 0; i < this.components.length; ++i)
691 result += "/"+ Name.toEscapedString(this.components[i]);
692
693 return result;
694};
695
Jeff Thompson754652d2012-11-24 16:23:43 -0800696/*
697 * Return a new Name with the first nComponents components of this Name.
698 */
699Name.prototype.getPrefix = function(nComponents) {
700 return new Name(this.components.slice(0, nComponents));
701}
702
703/*
704 * Return a new ArrayBuffer of the component at i.
705 */
706Name.prototype.getComponent = function(i) {
707 var result = new ArrayBuffer(this.components[i].length);
708 new Uint8Array(result).set(this.components[i]);
709 return result;
710}
711
Jeff Thompson10de4592012-10-21 23:54:18 -0700712/**
713 * Return component as an escaped string according to "CCNx URI Scheme".
714 * We can't use encodeURIComponent because that doesn't encode all the characters we want to.
715 */
716Name.toEscapedString = function(component) {
717 var result = "";
718 var gotNonDot = false;
719 for (var i = 0; i < component.length; ++i) {
720 if (component[i] != 0x2e) {
721 gotNonDot = true;
722 break;
723 }
724 }
725 if (!gotNonDot) {
726 // Special case for component of zero or more periods. Add 3 periods.
727 result = "...";
728 for (var i = 0; i < component.length; ++i)
729 result += ".";
730 }
731 else {
732 for (var i = 0; i < component.length; ++i) {
733 var value = component[i];
734 // Check for 0-9, A-Z, a-z, (+), (-), (.), (_)
735 if (value >= 0x30 && value <= 0x39 || value >= 0x41 && value <= 0x5a ||
736 value >= 0x61 && value <= 0x7a || value == 0x2b || value == 0x2d ||
737 value == 0x2e || value == 0x5f)
738 result += String.fromCharCode(value);
739 else
740 result += "%" + (value < 16 ? "0" : "") + value.toString(16).toUpperCase();
741 }
742 }
743 return result;
744};
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700745
746/*
Jeff Thompson754652d2012-11-24 16:23:43 -0800747 * @author: Meki Cheraoui
Jeff Thompson745026e2012-10-13 12:49:20 -0700748 * See COPYING for copyright and distribution information.
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700749 * This class represents ContentObject Objects
750 */
751var ContentObject = function ContentObject(_name,_signedInfo,_content,_signature){
752
753
754 if (typeof _name === 'string'){
755 this.name = new Name(_name);
756 }
757 else{
758 //TODO Check the class of _name
759 this.name = _name;
760 }
761 this.signedInfo = _signedInfo;
762 this.content=_content;
763 this.signature = _signature;
764
765
766 this.startSIG = null;
767 this.endSIG = null;
768
769 this.startSignedInfo = null;
770 this.endContent = null;
771
772 this.rawSignatureData = null;
773};
774
775ContentObject.prototype.sign = function(){
776
777 var n1 = this.encodeObject(this.name);
778 var n2 = this.encodeObject(this.signedInfo);
779 var n3 = this.encodeContent();
Jeff Thompson17a9da82012-11-12 01:11:01 -0800780 /*console.log('sign: ');
781 console.log(n1);
782 console.log(n2);
783 console.log(n3);*/
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700784
Jeff Thompson17a9da82012-11-12 01:11:01 -0800785 //var n = n1.concat(n2,n3);
786 var tempBuf = new ArrayBuffer(n1.length + n2.length + n3.length);
787 var n = new Uint8Array(tempBuf);
788 //console.log(n);
789 n.set(n1, 0);
790 //console.log(n);
791 n.set(n2, n1.length);
792 //console.log(n);
793 n.set(n3, n1.length + n2.length);
794 //console.log(n);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700795
Jeff Thompson17a9da82012-11-12 01:11:01 -0800796 if(LOG>4)console.log('Signature Data is (binary) '+n);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700797
Jeff Thompson17a9da82012-11-12 01:11:01 -0800798 if(LOG>4)console.log('Signature Data is (RawString)');
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700799
Jeff Thompson17a9da82012-11-12 01:11:01 -0800800 if(LOG>4)console.log( DataUtils.toString(n) );
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700801
Jeff Thompson17a9da82012-11-12 01:11:01 -0800802 //var sig = DataUtils.toString(n);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700803
804
805 var rsa = new RSAKey();
806
807 rsa.readPrivateKeyFromPEMString(globalKeyManager.privateKey);
808
809 //var hSig = rsa.signString(sig, "sha256");
810
811 var hSig = rsa.signByteArrayWithSHA256(n);
812
813
Jeff Thompson17a9da82012-11-12 01:11:01 -0800814 if(LOG>4)console.log('SIGNATURE SAVED IS');
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700815
Jeff Thompson17a9da82012-11-12 01:11:01 -0800816 if(LOG>4)console.log(hSig);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700817
Jeff Thompson17a9da82012-11-12 01:11:01 -0800818 if(LOG>4)console.log( DataUtils.toNumbers(hSig.trim()));
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700819
820 this.signature.signature = DataUtils.toNumbers(hSig.trim());
821
822
823};
824
825ContentObject.prototype.encodeObject = function encodeObject(obj){
826 var enc = new BinaryXMLEncoder();
827
828 obj.to_ccnb(enc);
829
830 var num = enc.getReducedOstream();
831
832 return num;
833
834
835};
836
837ContentObject.prototype.encodeContent = function encodeContent(obj){
838 var enc = new BinaryXMLEncoder();
839
840 enc.writeElement(CCNProtocolDTags.Content, this.content);
841
842 var num = enc.getReducedOstream();
843
844 return num;
845
846
847};
848
849ContentObject.prototype.saveRawData = function(bytes){
850
Jeff Thompson17a9da82012-11-12 01:11:01 -0800851 var sigBits = bytes.subarray(this.startSIG, this.endSIG);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -0700852
853 this.rawSignatureData = sigBits;
854};
855
856ContentObject.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
857
858 // TODO VALIDATE THAT ALL FIELDS EXCEPT SIGNATURE ARE PRESENT
859
860 decoder.readStartElement(this.getElementLabel());
861
862
863 if( decoder.peekStartElement(CCNProtocolDTags.Signature) ){
864 this.signature = new Signature();
865 this.signature.from_ccnb(decoder);
866 }
867
868 //this.endSIG = decoder.offset;
869
870 this.startSIG = decoder.offset;
871
872 this.name = new Name();
873 this.name.from_ccnb(decoder);
874
875 //this.startSignedInfo = decoder.offset;
876
877
878 if( decoder.peekStartElement(CCNProtocolDTags.SignedInfo) ){
879 this.signedInfo = new SignedInfo();
880 this.signedInfo.from_ccnb(decoder);
881 }
882
883 this.content = decoder.readBinaryElement(CCNProtocolDTags.Content);
884
885
886 //this.endContent = decoder.offset;
887 this.endSIG = decoder.offset;
888
889
890 decoder.readEndElement();
891
892 this.saveRawData(decoder.istream);
893};
894
895ContentObject.prototype.to_ccnb = function(/*XMLEncoder*/ encoder) {
896
897 //TODO verify name, SignedInfo and Signature is present
898
899
900 encoder.writeStartElement(this.getElementLabel());
901
902
903
904
905 if(null!=this.signature) this.signature.to_ccnb(encoder);
906
907
908 this.startSIG = encoder.offset;
909
910
911 if(null!=this.name) this.name.to_ccnb(encoder);
912
913 //this.endSIG = encoder.offset;
914 //this.startSignedInfo = encoder.offset;
915
916
917 if(null!=this.signedInfo) this.signedInfo.to_ccnb(encoder);
918
919 encoder.writeElement(CCNProtocolDTags.Content, this.content);
920
921
922 this.endSIG = encoder.offset;
923
924 //this.endContent = encoder.offset;
925
926
927 encoder.writeEndElement();
928
929 this.saveRawData(encoder.ostream);
930
931};
932
933ContentObject.prototype.getElementLabel= function(){return CCNProtocolDTags.ContentObject;};
934
935/**
936 * Signature
937 */
938var Signature = function Signature(_witness,_signature,_digestAlgorithm) {
939
940 this.Witness = _witness;//byte [] _witness;
941 this.signature = _signature;//byte [] _signature;
942 this.digestAlgorithm = _digestAlgorithm//String _digestAlgorithm;
943};
944
945var generateSignature = function(contentName,content,signedinfo){
946
947 var enc = new BinaryXMLEncoder();
948 contentName.to_ccnb(enc);
949 var hex1 = toHex(enc.getReducedOstream());
950
951 var enc = new BinaryXMLEncoder();
952 content.to_ccnb(enc);
953 var hex2 = toHex(enc.getReducedOstream());
954
955 var enc = new BinaryXMLEncoder();
956 signedinfo.to_ccnb(enc);
957 var hex3 = toHex(enc.getReducedOstream());
958
959 var hex = hex1+hex2+hex3;
960
961 //globalKeyManager.sig
962
963};
964
965Signature.prototype.from_ccnb =function( decoder) {
966 decoder.readStartElement(this.getElementLabel());
967
968 if(LOG>4)console.log('STARTED DECODING SIGNATURE ');
969
970 if (decoder.peekStartElement(CCNProtocolDTags.DigestAlgorithm)) {
971
972 if(LOG>4)console.log('DIGIEST ALGORITHM FOUND');
973 this.digestAlgorithm = decoder.readUTF8Element(CCNProtocolDTags.DigestAlgorithm);
974 }
975 if (decoder.peekStartElement(CCNProtocolDTags.Witness)) {
976 if(LOG>4)console.log('WITNESS FOUND FOUND');
977 this.Witness = decoder.readBinaryElement(CCNProtocolDTags.Witness);
978 }
979
980 //FORCE TO READ A SIGNATURE
981
982 //if(LOG>4)console.log('SIGNATURE FOUND ');
983 this.signature = decoder.readBinaryElement(CCNProtocolDTags.SignatureBits);
984 if(LOG>4)console.log('READ SIGNATURE ');
985
986 decoder.readEndElement();
987
988};
989
990
991Signature.prototype.to_ccnb= function( encoder){
992
993 if (!this.validate()) {
994 throw new Error("Cannot encode: field values missing.");
995 }
996
997 encoder.writeStartElement(this.getElementLabel());
998
999 if ((null != this.digestAlgorithm) && (!this.digestAlgorithm.equals(CCNDigestHelper.DEFAULT_DIGEST_ALGORITHM))) {
1000 encoder.writeElement(CCNProtocolDTags.DigestAlgorithm, OIDLookup.getDigestOID(this.DigestAlgorithm));
1001 }
1002
1003 if (null != this.Witness) {
1004 // needs to handle null witness
1005 encoder.writeElement(CCNProtocolDTags.Witness, this.Witness);
1006 }
1007
1008 encoder.writeElement(CCNProtocolDTags.SignatureBits, this.signature);
1009
1010 encoder.writeEndElement();
1011};
1012
1013Signature.prototype.getElementLabel = function() { return CCNProtocolDTags.Signature; };
1014
1015
1016Signature.prototype.validate = function() {
1017 return null != this.signature;
1018};
1019
1020
1021/**
1022 * SignedInfo
1023 */
1024var ContentType = {DATA:0, ENCR:1, GONE:2, KEY:3, LINK:4, NACK:5};
1025var ContentTypeValue = {0:0x0C04C0, 1:0x10D091,2:0x18E344,3:0x28463F,4:0x2C834A,5:0x34008A};
1026var ContentTypeValueReverse = {0x0C04C0:0, 0x10D091:1,0x18E344:2,0x28463F:3,0x2C834A:4,0x34008A:5};
1027
1028var SignedInfo = function SignedInfo(_publisher,_timestamp,_type,_locator,_freshnessSeconds,_finalBlockID){
1029
1030 //TODO, Check types
1031
1032 this.publisher = _publisher; //publisherPublicKeyDigest
1033 this.timestamp=_timestamp; // CCN Time
1034 this.type=_type; // ContentType
1035 this.locator =_locator;//KeyLocator
1036 this.freshnessSeconds =_freshnessSeconds; // Integer
1037 this.finalBlockID=_finalBlockID; //byte array
1038
1039};
1040
1041SignedInfo.prototype.setFields = function(){
1042 //BASE64 -> RAW STRING
1043
1044 //this.locator = new KeyLocator( DataUtils.toNumbersFromString(stringCertificate) ,KeyLocatorType.CERTIFICATE );
1045
1046 var publicKeyHex = globalKeyManager.publicKey;
1047
Jeff Thompson17a9da82012-11-12 01:11:01 -08001048 if(LOG>4)console.log('PUBLIC KEY TO WRITE TO CONTENT OBJECT IS ');
1049 if(LOG>4)console.log(publicKeyHex);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001050
1051 var publicKeyBytes = DataUtils.toNumbers(globalKeyManager.publicKey) ;
1052
1053
1054
1055 //var stringCertificate = DataUtils.base64toString(globalKeyManager.certificate);
1056
1057 //if(LOG>3)console.log('string Certificate is '+stringCertificate);
1058
1059 //HEX -> BYTE ARRAY
1060 //var publisherkey = DataUtils.toNumbers(hex_sha256(stringCertificate));
1061
1062 //if(LOG>3)console.log('publisher key is ');
1063 //if(LOG>3)console.log(publisherkey);
1064
1065 var publisherKeyDigest = hex_sha256_from_bytes(publicKeyBytes);
1066
1067 this.publisher = new PublisherPublicKeyDigest( DataUtils.toNumbers( publisherKeyDigest ) );
1068
1069 //this.publisher = new PublisherPublicKeyDigest(publisherkey);
1070
1071 var d = new Date();
1072
1073 var time = d.getTime();
1074
1075
1076 this.timestamp = new CCNTime( time );
1077
1078 if(LOG>4)console.log('TIME msec is');
1079
1080 if(LOG>4)console.log(this.timestamp.msec);
1081
1082 //DATA
1083 this.type = 0;//0x0C04C0;//ContentTypeValue[ContentType.DATA];
1084
1085 //if(LOG>4)console.log('toNumbersFromString(stringCertificate) '+DataUtils.toNumbersFromString(stringCertificate));
1086
Jeff Thompson17a9da82012-11-12 01:11:01 -08001087 if(LOG>4)console.log('PUBLIC KEY TO WRITE TO CONTENT OBJECT IS ');
1088 if(LOG>4)console.log(publicKeyBytes);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001089
1090 this.locator = new KeyLocator( publicKeyBytes ,KeyLocatorType.KEY );
1091
1092 //this.locator = new KeyLocator( DataUtils.toNumbersFromString(stringCertificate) ,KeyLocatorType.CERTIFICATE );
1093
1094};
1095
1096SignedInfo.prototype.from_ccnb = function( decoder){
1097
1098 decoder.readStartElement( this.getElementLabel() );
1099
1100 if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
1101 if(LOG>3) console.log('DECODING PUBLISHER KEY');
1102 this.publisher = new PublisherPublicKeyDigest();
1103 this.publisher.from_ccnb(decoder);
1104 }
1105
1106 if (decoder.peekStartElement(CCNProtocolDTags.Timestamp)) {
1107 this.timestamp = decoder.readDateTime(CCNProtocolDTags.Timestamp);
1108 if(LOG>4)console.log('TIMESTAMP FOUND IS '+this.timestamp);
1109
1110 }
1111
1112 if (decoder.peekStartElement(CCNProtocolDTags.Type)) {
1113 binType = decoder.readBinaryElement(CCNProtocolDTags.Type);//byte []
1114
1115
1116 //TODO Implement type of Key Reading
1117
1118 if(LOG>4)console.log('Binary Type of of Signed Info is '+binType);
1119
1120 this.type = binType;
1121
1122
1123 //TODO Implement type of Key Reading
1124
1125
1126 if (null == this.type) {
1127 throw new Error("Cannot parse signedInfo type: bytes.");
1128 }
1129
1130 } else {
1131 this.type = ContentType.DATA; // default
1132 }
1133
1134 if (decoder.peekStartElement(CCNProtocolDTags.FreshnessSeconds)) {
1135 this.freshnessSeconds = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
1136 if(LOG>4) console.log('FRESHNESS IN SECONDS IS '+ this.freshnessSeconds);
1137 }
1138
1139 if (decoder.peekStartElement(CCNProtocolDTags.FinalBlockID)) {
1140 this.finalBlockID = decoder.readBinaryElement(CCNProtocolDTags.FinalBlockID);
1141 }
1142
1143 if (decoder.peekStartElement(CCNProtocolDTags.KeyLocator)) {
1144 this.locator = new KeyLocator();
1145 this.locator.from_ccnb(decoder);
1146 }
1147
1148 decoder.readEndElement();
1149};
1150
1151SignedInfo.prototype.to_ccnb = function( encoder) {
1152 if (!this.validate()) {
1153 throw new Error("Cannot encode : field values missing.");
1154 }
1155 encoder.writeStartElement(this.getElementLabel());
1156
1157 if (null!=this.publisher) {
1158 if(LOG>3) console.log('ENCODING PUBLISHER KEY' + this.publisher.publisherPublicKeyDigest);
1159
1160 this.publisher.to_ccnb(encoder);
1161 }
1162
1163 if (null!=this.timestamp) {
1164 encoder.writeDateTime(CCNProtocolDTags.Timestamp, this.timestamp );
1165 }
1166
1167 if (null!=this.type && this.type !=0) {
1168
1169 encoder.writeElement(CCNProtocolDTags.type, this.type);
1170 }
1171
1172 if (null!=this.freshnessSeconds) {
1173 encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.freshnessSeconds);
1174 }
1175
1176 if (null!=this.finalBlockID) {
1177 encoder.writeElement(CCNProtocolDTags.FinalBlockID, this.finalBlockID);
1178 }
1179
1180 if (null!=this.locator) {
1181 this.locator.to_ccnb(encoder);
1182 }
1183
1184 encoder.writeEndElement();
1185};
1186
1187SignedInfo.prototype.valueToType = function(){
1188 //for (Entry<byte [], ContentType> entry : ContentValueTypes.entrySet()) {
1189 //if (Arrays.equals(value, entry.getKey()))
1190 //return entry.getValue();
1191 //}
1192 return null;
1193
1194};
1195
1196SignedInfo.prototype.getElementLabel = function() {
1197 return CCNProtocolDTags.SignedInfo;
1198};
1199
1200SignedInfo.prototype.validate = function() {
1201 // We don't do partial matches any more, even though encoder/decoder
1202 // is still pretty generous.
1203 if (null ==this.publisher || null==this.timestamp ||null== this.locator)
1204 return false;
1205 return true;
1206};
1207
1208/*
1209 * Date Format 1.2.3
1210 * (c) 2007-2009 Steven Levithan <stevenlevithan.com>
1211 * MIT license
1212 *
1213 * Includes enhancements by Scott Trenda <scott.trenda.net>
1214 * and Kris Kowal <cixar.com/~kris.kowal/>
1215 *
1216 * Accepts a date, a mask, or a date and a mask.
1217 * Returns a formatted version of the given date.
1218 * The date defaults to the current date/time.
1219 * The mask defaults to dateFormat.masks.default.
1220 */
1221
1222var DateFormat = function () {
1223 var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
1224 timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
1225 timezoneClip = /[^-+\dA-Z]/g,
1226 pad = function (val, len) {
1227 val = String(val);
1228 len = len || 2;
1229 while (val.length < len) val = "0" + val;
1230 return val;
1231 };
1232
1233 // Regexes and supporting functions are cached through closure
1234 return function (date, mask, utc) {
1235 var dF = dateFormat;
1236
1237 // You can't provide utc if you skip other args (use the "UTC:" mask prefix)
1238 if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) {
1239 mask = date;
1240 date = undefined;
1241 }
1242
1243 // Passing date through Date applies Date.parse, if necessary
1244 date = date ? new Date(date) : new Date;
1245 if (isNaN(date)) throw SyntaxError("invalid date");
1246
1247 mask = String(dF.masks[mask] || mask || dF.masks["default"]);
1248
1249 // Allow setting the utc argument via the mask
1250 if (mask.slice(0, 4) == "UTC:") {
1251 mask = mask.slice(4);
1252 utc = true;
1253 }
1254
1255 var _ = utc ? "getUTC" : "get",
1256 d = date[_ + "Date"](),
1257 D = date[_ + "Day"](),
1258 m = date[_ + "Month"](),
1259 y = date[_ + "FullYear"](),
1260 H = date[_ + "Hours"](),
1261 M = date[_ + "Minutes"](),
1262 s = date[_ + "Seconds"](),
1263 L = date[_ + "Milliseconds"](),
1264 o = utc ? 0 : date.getTimezoneOffset(),
1265 flags = {
1266 d: d,
1267 dd: pad(d),
1268 ddd: dF.i18n.dayNames[D],
1269 dddd: dF.i18n.dayNames[D + 7],
1270 m: m + 1,
1271 mm: pad(m + 1),
1272 mmm: dF.i18n.monthNames[m],
1273 mmmm: dF.i18n.monthNames[m + 12],
1274 yy: String(y).slice(2),
1275 yyyy: y,
1276 h: H % 12 || 12,
1277 hh: pad(H % 12 || 12),
1278 H: H,
1279 HH: pad(H),
1280 M: M,
1281 MM: pad(M),
1282 s: s,
1283 ss: pad(s),
1284 l: pad(L, 3),
1285 L: pad(L > 99 ? Math.round(L / 10) : L),
1286 t: H < 12 ? "a" : "p",
1287 tt: H < 12 ? "am" : "pm",
1288 T: H < 12 ? "A" : "P",
1289 TT: H < 12 ? "AM" : "PM",
1290 Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
1291 o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
1292 S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
1293 };
1294
1295 return mask.replace(token, function ($0) {
1296 return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
1297 });
1298 };
1299}();
1300
1301// Some common format strings
1302DateFormat.masks = {
1303 "default": "ddd mmm dd yyyy HH:MM:ss",
1304 shortDate: "m/d/yy",
1305 mediumDate: "mmm d, yyyy",
1306 longDate: "mmmm d, yyyy",
1307 fullDate: "dddd, mmmm d, yyyy",
1308 shortTime: "h:MM TT",
1309 mediumTime: "h:MM:ss TT",
1310 longTime: "h:MM:ss TT Z",
1311 isoDate: "yyyy-mm-dd",
1312 isoTime: "HH:MM:ss",
1313 isoDateTime: "yyyy-mm-dd'T'HH:MM:ss",
1314 isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
1315};
1316
1317// Internationalization strings
1318DateFormat.i18n = {
1319 dayNames: [
1320 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
1321 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
1322 ],
1323 monthNames: [
1324 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
1325 "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
1326 ]
1327};
1328
1329// For convenience...
1330Date.prototype.format = function (mask, utc) {
1331 return dateFormat(this, mask, utc);
1332};
1333
1334 /*
Jeff Thompson754652d2012-11-24 16:23:43 -08001335 * @author: Meki Cheraoui
Jeff Thompson745026e2012-10-13 12:49:20 -07001336 * See COPYING for copyright and distribution information.
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001337 * This class represents Interest Objects
1338 */
1339
1340var Interest = function Interest(_name,_faceInstance,_minSuffixComponents,_maxSuffixComponents,_publisherPublicKeyDigest, _exclude, _childSelector,_answerOriginKind,_scope,_interestLifetime,_nonce){
1341
1342 this.name = _name;
1343 this.faceInstance = _faceInstance;
1344 this.maxSuffixComponents = _maxSuffixComponents;
1345 this.minSuffixComponents = _minSuffixComponents;
1346
1347 this.publisherPublicKeyDigest = _publisherPublicKeyDigest;
1348 this.exclude = _exclude;
1349 this.childSelector = _childSelector;
1350 this.answerOriginKind = _answerOriginKind;
1351 this.scope = _scope;
Jeff Thompson754652d2012-11-24 16:23:43 -08001352 this.interestLifetime = _interestLifetime; // number of seconds
1353 this.nonce = _nonce;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001354
1355 this.RECURSIVE_POSTFIX = "*";
1356
1357 this.CHILD_SELECTOR_LEFT = 0;
1358 this.CHILD_SELECTOR_RIGHT = 1;
1359 this.ANSWER_CONTENT_STORE = 1;
1360 this.ANSWER_GENERATED = 2;
1361 this.ANSWER_STALE = 4; // Stale answer OK
1362 this.MARK_STALE = 16; // Must have scope 0. Michael calls this a "hack"
1363
1364 this.DEFAULT_ANSWER_ORIGIN_KIND = this.ANSWER_CONTENT_STORE | this.ANSWER_GENERATED;
1365
1366};
1367
1368Interest.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
1369
1370 decoder.readStartElement(CCNProtocolDTags.Interest);
1371
1372 this.name = new Name();
1373 this.name.from_ccnb(decoder);
1374
Jeff Thompson754652d2012-11-24 16:23:43 -08001375 if (decoder.peekStartElement(CCNProtocolDTags.MinSuffixComponents))
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001376 this.minSuffixComponents = decoder.readIntegerElement(CCNProtocolDTags.MinSuffixComponents);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001377
Jeff Thompson754652d2012-11-24 16:23:43 -08001378 if (decoder.peekStartElement(CCNProtocolDTags.MaxSuffixComponents))
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001379 this.maxSuffixComponents = decoder.readIntegerElement(CCNProtocolDTags.MaxSuffixComponents);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001380
1381 if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
Jeff Thompson754652d2012-11-24 16:23:43 -08001382 this.publisherPublicKeyDigest = new PublisherPublicKeyDigest();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001383 this.publisherPublicKeyDigest.from_ccnb(decoder);
1384 }
1385
1386 if (decoder.peekStartElement(CCNProtocolDTags.Exclude)) {
1387 this.exclude = new Exclude();
1388 this.exclude.from_ccnb(decoder);
1389 }
1390
Jeff Thompson754652d2012-11-24 16:23:43 -08001391 if (decoder.peekStartElement(CCNProtocolDTags.ChildSelector))
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001392 this.childSelector = decoder.readIntegerElement(CCNProtocolDTags.ChildSelector);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001393
Jeff Thompson754652d2012-11-24 16:23:43 -08001394 if (decoder.peekStartElement(CCNProtocolDTags.AnswerOriginKind))
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001395 this.answerOriginKind = decoder.readIntegerElement(CCNProtocolDTags.AnswerOriginKind);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001396
Jeff Thompson754652d2012-11-24 16:23:43 -08001397 if (decoder.peekStartElement(CCNProtocolDTags.Scope))
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001398 this.scope = decoder.readIntegerElement(CCNProtocolDTags.Scope);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001399
Jeff Thompson754652d2012-11-24 16:23:43 -08001400 if (decoder.peekStartElement(CCNProtocolDTags.InterestLifetime))
1401 this.interestLifetime = DataUtils.bigEndianToUnsignedInt
1402 (decoder.readBinaryElement(CCNProtocolDTags.InterestLifetime)) / 4096;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001403
Jeff Thompson754652d2012-11-24 16:23:43 -08001404 if (decoder.peekStartElement(CCNProtocolDTags.Nonce))
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001405 this.nonce = decoder.readBinaryElement(CCNProtocolDTags.Nonce);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001406
1407 decoder.readEndElement();
1408};
1409
1410Interest.prototype.to_ccnb = function(/*XMLEncoder*/ encoder){
1411 //Could check if name is present
1412
1413 encoder.writeStartElement(CCNProtocolDTags.Interest);
1414
1415 this.name.to_ccnb(encoder);
1416
1417 if (null != this.minSuffixComponents)
1418 encoder.writeElement(CCNProtocolDTags.MinSuffixComponents, this.minSuffixComponents);
1419
1420 if (null != this.maxSuffixComponents)
1421 encoder.writeElement(CCNProtocolDTags.MaxSuffixComponents, this.maxSuffixComponents);
1422
1423 if (null != this.publisherPublicKeyDigest)
1424 this.publisherPublicKeyDigest.to_ccnb(encoder);
1425
1426 if (null != this.exclude)
1427 this.exclude.to_ccnb(encoder);
1428
1429 if (null != this.childSelector)
1430 encoder.writeElement(CCNProtocolDTags.ChildSelector, this.childSelector);
1431
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001432 if (this.DEFAULT_ANSWER_ORIGIN_KIND != this.answerOriginKind && this.answerOriginKind!=null)
1433 encoder.writeElement(CCNProtocolDTags.AnswerOriginKind, this.answerOriginKind);
1434
1435 if (null != this.scope)
1436 encoder.writeElement(CCNProtocolDTags.Scope, this.scope);
1437
Jeff Thompson754652d2012-11-24 16:23:43 -08001438 if (null != this.interestLifetime)
1439 encoder.writeElement(CCNProtocolDTags.InterestLifetime,
1440 DataUtils.nonNegativeIntToBigEndian(this.interestLifetime * 4096));
1441
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001442 if (null != this.nonce)
1443 encoder.writeElement(CCNProtocolDTags.Nonce, this.nonce);
1444
1445 encoder.writeEndElement();
1446
1447};
1448
1449Interest.prototype.matches_name = function(/*Name*/ name){
1450 var i_name = this.name.components;
1451 var o_name = name.components;
1452
1453 // The intrest name is longer than the name we are checking it against.
1454 if (i_name.length > o_name.length)
1455 return false;
1456
1457 // Check if at least one of given components doesn't match.
1458 for (var i = 0; i < i_name.length; ++i) {
1459 if (!DataUtils.arraysEqual(i_name[i], o_name[i]))
1460 return false;
1461 }
1462
1463 return true;
1464}
1465
1466/**
1467 * Exclude
1468 */
1469var Exclude = function Exclude(_values){
1470
1471 this.OPTIMUM_FILTER_SIZE = 100;
1472
1473
1474 this.values = _values; //array of elements
1475
1476}
1477
1478Exclude.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
1479
1480
1481
1482 decoder.readStartElement(this.getElementLabel());
1483
1484 //TODO APPLY FILTERS/EXCLUDE
1485
1486 //TODO
1487 /*var component;
1488 var any = false;
1489 while ((component = decoder.peekStartElement(CCNProtocolDTags.Component)) ||
1490 (any = decoder.peekStartElement(CCNProtocolDTags.Any)) ||
1491 decoder.peekStartElement(CCNProtocolDTags.Bloom)) {
1492 var ee = component?new ExcludeComponent(): any ? new ExcludeAny() : new BloomFilter();
1493 ee.decode(decoder);
1494 _values.add(ee);
1495 }*/
1496
1497 decoder.readEndElement();
1498
1499};
1500
1501Exclude.prototype.to_ccnb=function(/*XMLEncoder*/ encoder) {
1502 if (!validate()) {
1503 throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
1504 }
1505
1506 if (empty())
1507 return;
1508
1509 encoder.writeStartElement(getElementLabel());
1510
1511 encoder.writeEndElement();
1512
1513 };
1514
1515Exclude.prototype.getElementLabel = function() { return CCNProtocolDTags.Exclude; };
1516
1517
1518/**
1519 * ExcludeAny
1520 */
1521var ExcludeAny = function ExcludeAny() {
1522
1523};
1524
1525ExcludeAny.prototype.from_ccnb = function(decoder) {
1526 decoder.readStartElement(this.getElementLabel());
1527 decoder.readEndElement();
1528};
1529
1530
1531ExcludeAny.prototype.to_ccnb = function( encoder) {
1532 encoder.writeStartElement(this.getElementLabel());
1533 encoder.writeEndElement();
1534};
1535
1536ExcludeAny.prototype.getElementLabel=function() { return CCNProtocolDTags.Any; };
1537
1538
1539/**
1540 * ExcludeComponent
1541 */
1542var ExcludeComponent = function ExcludeComponent(_body) {
1543
1544 //TODO Check BODY is an Array of componenets.
1545
1546 this.body = _body
1547};
1548
1549ExcludeComponent.prototype.from_ccnb = function( decoder) {
1550 this.body = decoder.readBinaryElement(this.getElementLabel());
1551};
1552
1553ExcludeComponent.prototype.to_ccnb = function(encoder) {
1554 encoder.writeElement(this.getElementLabel(), this.body);
1555};
1556
1557ExcludeComponent.prototype.getElementLabel = function() { return CCNProtocolDTags.Component; };
1558
1559/*
Jeff Thompson754652d2012-11-24 16:23:43 -08001560 * @author: Meki Cheraoui
Jeff Thompson745026e2012-10-13 12:49:20 -07001561 * See COPYING for copyright and distribution information.
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001562 * This class represents Key Objects
1563 */
1564
1565var Key = function Key(){
1566 /* TODO: Port from PyCCN:
1567 generateRSA()
1568 privateToDER()
1569 publicToDER()
1570 privateToPEM()
1571 publicToPEM()
1572 fromDER()
1573 fromPEM()
1574 */
1575}
1576
1577/**
1578 * KeyLocator
1579 */
1580var KeyLocatorType = {
1581 NAME:1,
1582 KEY:2,
1583 CERTIFICATE:3
1584};
1585
1586var KeyLocator = function KeyLocator(_input,_type){
1587
1588 this.type=_type;
1589
1590 if (_type==KeyLocatorType.NAME){
1591 this.keyName = _input;
1592 }
1593 else if(_type==KeyLocatorType.KEY){
Jeff Thompson17a9da82012-11-12 01:11:01 -08001594 if(LOG>4)console.log('SET KEY');
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001595 this.publicKey = _input;
1596 }
1597 else if(_type==KeyLocatorType.CERTIFICATE){
1598 this.certificate = _input;
1599 }
1600
1601};
1602
1603KeyLocator.prototype.from_ccnb = function(decoder) {
1604
1605 decoder.readStartElement(this.getElementLabel());
1606
1607 if (decoder.peekStartElement(CCNProtocolDTags.Key)) {
1608 try {
1609 encodedKey = decoder.readBinaryElement(CCNProtocolDTags.Key);
1610 // This is a DER-encoded SubjectPublicKeyInfo.
1611
1612 //TODO FIX THIS, This should create a Key Object instead of keeping bytes
1613
1614 this.publicKey = encodedKey;//CryptoUtil.getPublicKey(encodedKey);
1615 this.type = 2;
1616
1617
1618 if(LOG>4) console.log('PUBLIC KEY FOUND: '+ this.publicKey);
1619 //this.publicKey = encodedKey;
1620
1621
1622 } catch (e) {
1623 throw new Error("Cannot parse key: ", e);
1624 }
1625
1626 if (null == this.publicKey) {
1627 throw new Error("Cannot parse key: ");
1628 }
1629
1630 } else if ( decoder.peekStartElement(CCNProtocolDTags.Certificate)) {
1631 try {
1632 encodedCert = decoder.readBinaryElement(CCNProtocolDTags.Certificate);
1633
1634 /*
1635 * Certificates not yet working
1636 */
1637
1638 //CertificateFactory factory = CertificateFactory.getInstance("X.509");
1639 //this.certificate = (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(encodedCert));
1640
1641
1642 this.certificate = encodedCert;
1643 this.type = 3;
1644
1645 if(LOG>4) console.log('CERTIFICATE FOUND: '+ this.certificate);
1646
1647 } catch ( e) {
1648 throw new Error("Cannot decode certificate: " + e);
1649 }
1650 if (null == this.certificate) {
1651 throw new Error("Cannot parse certificate! ");
1652 }
1653 } else {
1654 this.type = 1;
1655
1656
1657 this.keyName = new KeyName();
1658 this.keyName.from_ccnb(decoder);
1659 }
1660 decoder.readEndElement();
1661 }
1662
1663
1664 KeyLocator.prototype.to_ccnb = function( encoder) {
1665
Jeff Thompson17a9da82012-11-12 01:11:01 -08001666 if(LOG>4) console.log('type is is ' + this.type);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001667 //TODO Check if Name is missing
1668 if (!this.validate()) {
1669 throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
1670 }
1671
1672
1673 //TODO FIX THIS TOO
1674 encoder.writeStartElement(this.getElementLabel());
1675
1676 if (this.type == KeyLocatorType.KEY) {
1677 if(LOG>5)console.log('About to encode a public key' +this.publicKey);
1678 encoder.writeElement(CCNProtocolDTags.Key, this.publicKey);
1679
1680 } else if (this.type == KeyLocatorType.CERTIFICATE) {
1681
1682 try {
1683 encoder.writeElement(CCNProtocolDTags.Certificate, this.certificate);
1684 } catch ( e) {
1685 throw new Error("CertificateEncodingException attempting to write key locator: " + e);
1686 }
1687
1688 } else if (this.type == KeyLocatorType.NAME) {
1689
1690 this.keyName.to_ccnb(encoder);
1691 }
1692 encoder.writeEndElement();
1693
1694};
1695
1696KeyLocator.prototype.getElementLabel = function() {
1697 return CCNProtocolDTags.KeyLocator;
1698};
1699
1700KeyLocator.prototype.validate = function() {
1701 return ( (null != this.keyName) || (null != this.publicKey) || (null != this.certificate) );
1702};
1703
1704/**
1705 * KeyName is only used by KeyLocator.
1706 */
1707var KeyName = function KeyName() {
1708
1709
1710 this.contentName = this.contentName;//contentName
1711 this.publisherID =this.publisherID;//publisherID
1712
1713};
1714
1715KeyName.prototype.from_ccnb=function( decoder){
1716
1717
1718 decoder.readStartElement(this.getElementLabel());
1719
1720 this.contentName = new Name();
1721 this.contentName.from_ccnb(decoder);
1722
1723 if(LOG>4) console.log('KEY NAME FOUND: ');
1724
1725 if ( PublisherID.peek(decoder) ) {
1726 this.publisherID = new PublisherID();
1727 this.publisherID.from_ccnb(decoder);
1728 }
1729
1730 decoder.readEndElement();
1731};
1732
1733KeyName.prototype.to_ccnb = function( encoder) {
1734 if (!this.validate()) {
1735 throw new Error("Cannot encode : field values missing.");
1736 }
1737
1738 encoder.writeStartElement(this.getElementLabel());
1739
1740 this.contentName.to_ccnb(encoder);
1741 if (null != this.publisherID)
1742 this.publisherID.to_ccnb(encoder);
1743
1744 encoder.writeEndElement();
1745};
1746
1747KeyName.prototype.getElementLabel = function() { return CCNProtocolDTags.KeyName; };
1748
1749KeyName.prototype.validate = function() {
1750 // DKS -- do we do recursive validation?
1751 // null signedInfo ok
1752 return (null != this.contentName);
1753};
1754
1755/*
Jeff Thompson754652d2012-11-24 16:23:43 -08001756 * @author: Meki Cheraoui
Jeff Thompson745026e2012-10-13 12:49:20 -07001757 * See COPYING for copyright and distribution information.
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001758 * This class represents Publisher and PublisherType Objects
1759 */
1760
1761
1762var PublisherType = function PublisherType(_tag){
1763 this.KEY =(CCNProtocolDTags.PublisherPublicKeyDigest);
1764 this.CERTIFICATE= (CCNProtocolDTags.PublisherCertificateDigest);
1765 this.ISSUER_KEY= (CCNProtocolDTags.PublisherIssuerKeyDigest);
1766 this.ISSUER_CERTIFICATE =(CCNProtocolDTags.PublisherIssuerCertificateDigest);
1767
1768 this.Tag = _tag;
1769};
1770
1771var isTypeTagVal = function(tagVal) {
1772 if ((tagVal == CCNProtocolDTags.PublisherPublicKeyDigest) ||
1773 (tagVal == CCNProtocolDTags.PublisherCertificateDigest) ||
1774 (tagVal == CCNProtocolDTags.PublisherIssuerKeyDigest) ||
1775 (tagVal == CCNProtocolDTags.PublisherIssuerCertificateDigest)) {
1776 return true;
1777 }
1778 return false;
1779};
1780
1781
1782
1783
1784var PublisherID = function PublisherID() {
1785
1786 this.PUBLISHER_ID_DIGEST_ALGORITHM = "SHA-256";
1787 this.PUBLISHER_ID_LEN = 256/8;
1788
1789 //TODO, implement publisherID creation and key creation
1790
1791 //TODO implement generatePublicKeyDigest
1792 this.publisherID =null;//= generatePublicKeyDigest(key);//ByteArray
1793
1794 //TODO implement generate key
1795 //CryptoUtil.generateKeyID(PUBLISHER_ID_DIGEST_ALGORITHM, key);
1796 this.publisherType = null;//isIssuer ? PublisherType.ISSUER_KEY : PublisherType.KEY;//publisher Type
1797
1798};
1799
1800
1801PublisherID.prototype.from_ccnb = function(decoder) {
1802
1803 // We have a choice here of one of 4 binary element types.
1804 var nextTag = decoder.peekStartElementAsLong();
1805
1806 if (null == nextTag) {
1807 throw new Error("Cannot parse publisher ID.");
1808 }
1809
1810 this.publisherType = new PublisherType(nextTag);
1811
1812 if (!isTypeTagVal(nextTag)) {
1813 throw new Error("Invalid publisher ID, got unexpected type: " + nextTag);
1814 }
1815 this.publisherID = decoder.readBinaryElement(nextTag);
1816 if (null == this.publisherID) {
Jeff Thompsoncab74c32012-10-21 13:27:28 -07001817 throw new ContentDecodingException(new Error("Cannot parse publisher ID of type : " + nextTag + "."));
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001818 }
1819};
1820
1821PublisherID.prototype.to_ccnb = function(encoder) {
1822 if (!this.validate()) {
1823 throw new Error("Cannot encode " + this.getClass().getName() + ": field values missing.");
1824 }
1825
1826 encoder.writeElement(this.getElementLabel(), this.publisherID);
1827};
1828
1829PublisherID.peek = function(/* XMLDecoder */ decoder) {
1830
1831 //Long
1832 nextTag = decoder.peekStartElementAsLong();
1833
1834 if (null == nextTag) {
1835 // on end element
1836 return false;
1837 }
1838 return (isTypeTagVal(nextTag));
1839 };
1840
1841PublisherID.prototype.getElementLabel = function() {
1842 return this.publisherType.Tag;
1843};
1844
1845PublisherID.prototype.validate = function(){
1846 return ((null != id() && (null != type())));
1847};
1848
1849
1850
1851
1852/*
Jeff Thompson754652d2012-11-24 16:23:43 -08001853 * @author: Meki Cheraoui
Jeff Thompson745026e2012-10-13 12:49:20 -07001854 * See COPYING for copyright and distribution information.
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001855 * This class represents PublisherPublicKeyDigest Objects
1856 */
1857var PublisherPublicKeyDigest = function PublisherPublicKeyDigest(_pkd){
1858
1859 //this.PUBLISHER_ID_LEN = 256/8;
1860 this.PUBLISHER_ID_LEN = 512/8;
1861
1862
1863 this.publisherPublicKeyDigest = _pkd;
1864 //if( typeof _pkd == "object") this.publisherPublicKeyDigest = _pkd; // Byte Array
1865 //else if( typeof _pkd == "PublicKey") ;//TODO...
1866
1867};
1868
1869PublisherPublicKeyDigest.prototype.from_ccnb = function( decoder) {
1870
1871 this.publisherPublicKeyDigest = decoder.readBinaryElement(this.getElementLabel());
1872
1873 if(LOG>4)console.log('Publisher public key digest is ' + this.publisherPublicKeyDigest);
1874
1875 if (null == this.publisherPublicKeyDigest) {
1876 throw new Error("Cannot parse publisher key digest.");
1877 }
1878
1879 //TODO check if the length of the PublisherPublicKeyDigest is correct ( Security reason)
1880
1881 if (this.publisherPublicKeyDigest.length != this.PUBLISHER_ID_LEN) {
Jeff Thompson10de4592012-10-21 23:54:18 -07001882 if (LOG > 0)
1883 console.log('LENGTH OF PUBLISHER ID IS WRONG! Expected ' + this.PUBLISHER_ID_LEN + ", got " + this.publisherPublicKeyDigest.length);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001884
Jeff Thompson10de4592012-10-21 23:54:18 -07001885 //this.publisherPublicKeyDigest = new PublisherPublicKeyDigest(this.PublisherPublicKeyDigest).PublisherKeyDigest;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001886 }
1887 };
1888
1889PublisherPublicKeyDigest.prototype.to_ccnb= function( encoder) {
1890 //TODO Check that the ByteArray for the key is present
1891 if (!this.validate()) {
1892 throw new Error("Cannot encode : field values missing.");
1893 }
1894 if(LOG>3) console.log('PUBLISHER KEY DIGEST IS'+this.publisherPublicKeyDigest);
1895 encoder.writeElement(this.getElementLabel(), this.publisherPublicKeyDigest);
1896};
1897
1898PublisherPublicKeyDigest.prototype.getElementLabel = function() { return CCNProtocolDTags.PublisherPublicKeyDigest; };
1899
1900PublisherPublicKeyDigest.prototype.validate =function() {
1901 return (null != this.publisherPublicKeyDigest);
1902};
1903
1904/*
Jeff Thompson754652d2012-11-24 16:23:43 -08001905 * @author: Meki Cheraoui
Jeff Thompson745026e2012-10-13 12:49:20 -07001906 * See COPYING for copyright and distribution information.
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07001907 * This class represents Face Instances
1908 */
1909
1910var NetworkProtocol = { TCP:6, UDP:17};
1911
1912var FaceInstance = function FaceInstance(
1913 _action,
1914 _publisherPublicKeyDigest,
1915 _faceID,
1916 _ipProto,
1917 _host,
1918 _port,
1919 _multicastInterface,
1920 _multicastTTL,
1921 _freshnessSeconds){
1922
1923
1924 this.action = _action;
1925 this.publisherPublicKeyDigest = _publisherPublicKeyDigest;
1926 this.faceID = _faceID;
1927 this.ipProto = _ipProto;
1928 this.host = _host;
1929 this.Port = _port;
1930 this.multicastInterface =_multicastInterface;
1931 this.multicastTTL =_multicastTTL;
1932 this.freshnessSeconds = _freshnessSeconds;
1933
1934 //action ::= ("newface" | "destroyface" | "queryface")
1935 //publisherPublicKeyDigest ::= SHA-256 digest
1936 //faceID ::= nonNegativeInteger
1937 //ipProto ::= nonNegativeInteger [IANA protocol number, 6=TCP, 17=UDP]
1938 //Host ::= textual representation of numeric IPv4 or IPv6 address
1939 //Port ::= nonNegativeInteger [1..65535]
1940 //MulticastInterface ::= textual representation of numeric IPv4 or IPv6 address
1941 //MulticastTTL ::= nonNegativeInteger [1..255]
1942 //freshnessSeconds ::= nonNegativeInteger
1943
1944};
1945
1946/**
1947 * Used by NetworkObject to decode the object from a network stream.
1948 * @see org.ccnx.ccn.impl.encoding.XMLEncodable
1949 */
1950FaceInstance.prototype.from_ccnb = function(//XMLDecoder
1951 decoder) {
1952
1953 decoder.readStartElement(this.getElementLabel());
1954
1955 if (decoder.peekStartElement(CCNProtocolDTags.Action)) {
1956
1957 this.action = decoder.readUTF8Element(CCNProtocolDTags.Action);
1958
1959 }
1960 if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
1961
1962 this.publisherPublicKeyDigest = new PublisherPublicKeyDigest();
1963 this.publisherPublicKeyDigest.from_ccnb(decoder);
1964
1965 }
1966 if (decoder.peekStartElement(CCNProtocolDTags.FaceID)) {
1967
1968 this.faceID = decoder.readIntegerElement(CCNProtocolDTags.FaceID);
1969
1970 }
1971 if (decoder.peekStartElement(CCNProtocolDTags.IPProto)) {
1972
1973 //int
1974 var pI = decoder.readIntegerElement(CCNProtocolDTags.IPProto);
1975
1976 this.ipProto = null;
1977
1978 if (NetworkProtocol.TCP == pI) {
1979
1980 this.ipProto = NetworkProtocol.TCP;
1981
1982 } else if (NetworkProtocol.UDP == pI) {
1983
1984 this.ipProto = NetworkProtocol.UDP;
1985
1986 } else {
1987
1988 throw new Error("FaceInstance.decoder. Invalid " +
1989 CCNProtocolDTags.tagToString(CCNProtocolDTags.IPProto) + " field: " + pI);
1990
1991 }
1992 }
1993
1994 if (decoder.peekStartElement(CCNProtocolDTags.Host)) {
1995
1996 this.host = decoder.readUTF8Element(CCNProtocolDTags.Host);
1997
1998 }
1999
2000 if (decoder.peekStartElement(CCNProtocolDTags.Port)) {
2001 this.Port = decoder.readIntegerElement(CCNProtocolDTags.Port);
2002 }
2003
2004 if (decoder.peekStartElement(CCNProtocolDTags.MulticastInterface)) {
2005 this.multicastInterface = decoder.readUTF8Element(CCNProtocolDTags.MulticastInterface);
2006 }
2007
2008 if (decoder.peekStartElement(CCNProtocolDTags.MulticastTTL)) {
2009 this.multicastTTL = decoder.readIntegerElement(CCNProtocolDTags.MulticastTTL);
2010 }
2011
2012 if (decoder.peekStartElement(CCNProtocolDTags.FreshnessSeconds)) {
2013 this.freshnessSeconds = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
2014 }
2015 decoder.readEndElement();
2016}
2017
2018/**
2019 * Used by NetworkObject to encode the object to a network stream.
2020 * @see org.ccnx.ccn.impl.encoding.XMLEncodable
2021 */
2022FaceInstance.prototype.to_ccnb = function(//XMLEncoder
2023 encoder){
2024
2025 //if (!this.validate()) {
2026 //throw new Error("Cannot encode : field values missing.");
2027 //throw new Error("")
2028 //}
2029 encoder.writeStartElement(this.getElementLabel());
2030
2031 if (null != this.action && this.action.length != 0)
2032 encoder.writeElement(CCNProtocolDTags.Action, this.action);
2033
2034 if (null != this.publisherPublicKeyDigest) {
2035 this.publisherPublicKeyDigest.to_ccnb(encoder);
2036 }
2037 if (null != this.faceID) {
2038 encoder.writeElement(CCNProtocolDTags.FaceID, this.faceID);
2039 }
2040 if (null != this.ipProto) {
2041 //encoder.writeElement(CCNProtocolDTags.IPProto, this.IpProto.value());
2042 encoder.writeElement(CCNProtocolDTags.IPProto, this.ipProto);
2043 }
2044 if (null != this.host && this.host.length != 0) {
2045 encoder.writeElement(CCNProtocolDTags.Host, this.host);
2046 }
2047 if (null != this.Port) {
2048 encoder.writeElement(CCNProtocolDTags.Port, this.Port);
2049 }
2050 if (null != this.multicastInterface && this.multicastInterface.length != 0) {
2051 encoder.writeElement(CCNProtocolDTags.MulticastInterface, this.multicastInterface);
2052 }
2053 if (null != this.multicastTTL) {
2054 encoder.writeElement(CCNProtocolDTags.MulticastTTL, this.multicastTTL);
2055 }
2056 if (null != this.freshnessSeconds) {
2057 encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.freshnessSeconds);
2058 }
2059 encoder.writeEndElement();
2060}
2061
2062
2063FaceInstance.prototype.getElementLabel= function(){return CCNProtocolDTags.FaceInstance;};
2064
2065
2066/*
Jeff Thompson754652d2012-11-24 16:23:43 -08002067 * @author: Meki Cheraoui
Jeff Thompson745026e2012-10-13 12:49:20 -07002068 * See COPYING for copyright and distribution information.
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002069 * This class represents Forwarding Entries
2070 */
2071
2072var ForwardingEntry = function ForwardingEntry(
2073 //ActionType
2074 _action,
2075 //Name
2076 _prefixName,
2077 //PublisherPublicKeyDigest
2078 _ccndId,
2079 //Integer
2080 _faceID,
2081 //Integer
2082 _flags,
2083 //Integer
2084 _lifetime){
2085
2086
2087
2088 //String
2089 this.action = _action;
2090 //Name\
2091 this.prefixName = _prefixName;
2092 //PublisherPublicKeyDigest
2093 this.ccndID = _ccndId;
2094 //Integer
2095 this.faceID = _faceID;
2096 //Integer
2097 this.flags = _flags;
2098 //Integer
2099 this.lifetime = _lifetime; // in seconds
2100
2101};
2102
2103ForwardingEntry.prototype.from_ccnb =function(
2104 //XMLDecoder
2105 decoder)
Jeff Thompson10de4592012-10-21 23:54:18 -07002106 //throws ContentDecodingException
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002107 {
2108 decoder.readStartElement(this.getElementLabel());
2109 if (decoder.peekStartElement(CCNProtocolDTags.Action)) {
2110 this.action = decoder.readUTF8Element(CCNProtocolDTags.Action);
2111 }
2112 if (decoder.peekStartElement(CCNProtocolDTags.Name)) {
2113 this.prefixName = new Name();
2114 this.prefixName.from_ccnb(decoder) ;
2115 }
2116 if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
2117 this.CcndId = new PublisherPublicKeyDigest();
2118 this.CcndId.from_ccnb(decoder);
2119 }
2120 if (decoder.peekStartElement(CCNProtocolDTags.FaceID)) {
2121 this.faceID = decoder.readIntegerElement(CCNProtocolDTags.FaceID);
2122 }
2123 if (decoder.peekStartElement(CCNProtocolDTags.ForwardingFlags)) {
2124 this.flags = decoder.readIntegerElement(CCNProtocolDTags.ForwardingFlags);
2125 }
2126 if (decoder.peekStartElement(CCNProtocolDTags.FreshnessSeconds)) {
2127 this.lifetime = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
2128 }
2129 decoder.readEndElement();
2130 };
2131
2132 /**
2133 * Used by NetworkObject to encode the object to a network stream.
2134 * @see org.ccnx.ccn.impl.encoding.XMLEncodable
2135 */
2136ForwardingEntry.prototype.to_ccnb =function(
2137 //XMLEncoder
2138encoder)
2139{
2140
2141
2142 //if (!validate()) {
2143 //throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
2144 //}
2145 encoder.writeStartElement(this.getElementLabel());
2146 if (null != this.action && this.action.length != 0)
2147 encoder.writeElement(CCNProtocolDTags.Action, this.action);
2148 if (null != this.prefixName) {
2149 this.prefixName.to_ccnb(encoder);
2150 }
2151 if (null != this.CcndId) {
2152 this.CcndId.to_ccnb(encoder);
2153 }
2154 if (null != this.faceID) {
2155 encoder.writeElement(CCNProtocolDTags.FaceID, this.faceID);
2156 }
2157 if (null != this.flags) {
2158 encoder.writeElement(CCNProtocolDTags.ForwardingFlags, this.flags);
2159 }
2160 if (null != this.lifetime) {
2161 encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.lifetime);
2162 }
2163 encoder.writeEndElement();
2164 };
2165
2166ForwardingEntry.prototype.getElementLabel = function() { return CCNProtocolDTags.ForwardingEntry; }
2167
2168/*
Jeff Thompsondad617b2012-10-14 17:11:41 -07002169 * This class is used to encode ccnb binary elements (blob, type/value pairs).
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002170 *
Jeff Thompson754652d2012-11-24 16:23:43 -08002171 * @author: Meki Cheraoui
Jeff Thompson745026e2012-10-13 12:49:20 -07002172 * See COPYING for copyright and distribution information.
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002173 */
2174
2175var XML_EXT = 0x00;
2176
2177var XML_TAG = 0x01;
2178
2179var XML_DTAG = 0x02;
2180
2181var XML_ATTR = 0x03;
2182
2183var XML_DATTR = 0x04;
2184
2185var XML_BLOB = 0x05;
2186
2187var XML_UDATA = 0x06;
2188
2189var XML_CLOSE = 0x0;
2190
2191var XML_SUBTYPE_PROCESSING_INSTRUCTIONS = 16;
2192
2193
2194var XML_TT_BITS = 3;
2195var XML_TT_MASK = ((1 << XML_TT_BITS) - 1);
2196var XML_TT_VAL_BITS = XML_TT_BITS + 1;
2197var XML_TT_VAL_MASK = ((1 << (XML_TT_VAL_BITS)) - 1);
2198var XML_REG_VAL_BITS = 7;
2199var XML_REG_VAL_MASK = ((1 << XML_REG_VAL_BITS) - 1);
2200var XML_TT_NO_MORE = (1 << XML_REG_VAL_BITS); // 0x80
2201var BYTE_MASK = 0xFF;
2202var LONG_BYTES = 8;
2203var LONG_BITS = 64;
2204
2205var bits_11 = 0x0000007FF;
2206var bits_18 = 0x00003FFFF;
2207var bits_32 = 0x0FFFFFFFF;
2208
2209
2210var BinaryXMLEncoder = function BinaryXMLEncoder(){
Jeff Thompson17a9da82012-11-12 01:11:01 -08002211 this.ostream = new Uint8Array(10000);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002212 this.offset =0;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002213 this.CODEC_NAME = "Binary";
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002214};
2215
Jeff Thompson754652d2012-11-24 16:23:43 -08002216/*
2217 * Encode utf8Content as utf8.
2218 */
Jeff Thompson17a9da82012-11-12 01:11:01 -08002219BinaryXMLEncoder.prototype.writeUString = function(/*String*/ utf8Content) {
Jeff Thompson754652d2012-11-24 16:23:43 -08002220 this.encodeUString(utf8Content, XML_UDATA);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002221};
2222
Jeff Thompson17a9da82012-11-12 01:11:01 -08002223
2224BinaryXMLEncoder.prototype.writeBlob = function(
2225 /*Uint8Array*/ binaryContent
Jeff Thompson17a9da82012-11-12 01:11:01 -08002226 ) {
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002227
2228 if(LOG >3) console.log(binaryContent);
2229
Jeff Thompson754652d2012-11-24 16:23:43 -08002230 this.encodeBlob(binaryContent, binaryContent.length);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002231};
2232
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002233
Jeff Thompson17a9da82012-11-12 01:11:01 -08002234BinaryXMLEncoder.prototype.writeStartElement = function(
2235 /*String*/ tag,
2236 /*TreeMap<String,String>*/ attributes
2237 ) {
2238
Jeff Thompson754652d2012-11-24 16:23:43 -08002239 /*Long*/ var dictionaryVal = tag; //stringToTag(tag);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002240
2241 if (null == dictionaryVal) {
Jeff Thompson754652d2012-11-24 16:23:43 -08002242 this.encodeUString(tag, XML_TAG);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002243 } else {
Jeff Thompson754652d2012-11-24 16:23:43 -08002244 this.encodeTypeAndVal(XML_DTAG, dictionaryVal);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002245 }
2246
2247 if (null != attributes) {
2248 this.writeAttributes(attributes);
2249 }
2250};
2251
2252
Jeff Thompson17a9da82012-11-12 01:11:01 -08002253BinaryXMLEncoder.prototype.writeEndElement = function() {
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002254 this.ostream[this.offset] = XML_CLOSE;
Jeff Thompson17a9da82012-11-12 01:11:01 -08002255 this.offset += 1;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002256}
2257
Jeff Thompson17a9da82012-11-12 01:11:01 -08002258
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002259BinaryXMLEncoder.prototype.writeAttributes = function(/*TreeMap<String,String>*/ attributes) {
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002260 if (null == attributes) {
2261 return;
2262 }
2263
2264 // the keySet of a TreeMap is sorted.
2265
2266 for(var i=0; i<attributes.length;i++){
2267 var strAttr = attributes[i].k;
2268 var strValue = attributes[i].v;
2269
2270 var dictionaryAttr = stringToTag(strAttr);
2271 if (null == dictionaryAttr) {
2272 // not in dictionary, encode as attr
2273 // compressed format wants length of tag represented as length-1
2274 // to save that extra bit, as tag cannot be 0 length.
2275 // encodeUString knows to do that.
Jeff Thompson754652d2012-11-24 16:23:43 -08002276 this.encodeUString(strAttr, XML_ATTR);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002277 } else {
Jeff Thompson754652d2012-11-24 16:23:43 -08002278 this.encodeTypeAndVal(XML_DATTR, dictionaryAttr);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002279 }
2280 // Write value
Jeff Thompson754652d2012-11-24 16:23:43 -08002281 this.encodeUString(strValue);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002282
2283 }
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002284}
2285
Jeff Thompson17a9da82012-11-12 01:11:01 -08002286
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002287//returns a string
2288stringToTag = function(/*long*/ tagVal) {
2289 if ((tagVal >= 0) && (tagVal < CCNProtocolDTagsStrings.length)) {
2290 return CCNProtocolDTagsStrings[tagVal];
2291 } else if (tagVal == CCNProtocolDTags.CCNProtocolDataUnit) {
2292 return CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT;
2293 }
2294 return null;
2295};
2296
2297//returns a Long
2298tagToString = function(/*String*/ tagName) {
2299 // the slow way, but right now we don't care.... want a static lookup for the forward direction
2300 for (var i=0; i < CCNProtocolDTagsStrings.length; ++i) {
2301 if ((null != CCNProtocolDTagsStrings[i]) && (CCNProtocolDTagsStrings[i] == tagName)) {
2302 return i;
2303 }
2304 }
2305 if (CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT == tagName) {
2306 return CCNProtocolDTags.CCNProtocolDataUnit;
2307 }
2308 return null;
2309};
2310
Jeff Thompson754652d2012-11-24 16:23:43 -08002311/*
2312 * If Content is a string, then encode as utf8 and write UDATA.
2313 */
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002314BinaryXMLEncoder.prototype.writeElement = function(
2315 //long
2316 tag,
2317 //byte[]
2318 Content,
2319 //TreeMap<String, String>
Jeff Thompson17a9da82012-11-12 01:11:01 -08002320 attributes
2321 ) {
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002322 this.writeStartElement(tag, attributes);
2323 // Will omit if 0-length
2324
2325 if(typeof Content === 'number') {
Jeff Thompson17a9da82012-11-12 01:11:01 -08002326 if(LOG>4) console.log('GOING TO WRITE THE NUMBER .charCodeAt(0) ' + Content.toString().charCodeAt(0) );
2327 if(LOG>4) console.log('GOING TO WRITE THE NUMBER ' + Content.toString() );
2328 if(LOG>4) console.log('type of number is ' + typeof Content.toString() );
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002329
2330 this.writeUString(Content.toString());
2331 //whatever
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002332 }
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002333 else if(typeof Content === 'string'){
Jeff Thompson17a9da82012-11-12 01:11:01 -08002334 if(LOG>4) console.log('GOING TO WRITE THE STRING ' + Content );
2335 if(LOG>4) console.log('type of STRING is ' + typeof Content );
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002336
2337 this.writeUString(Content);
2338 }
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002339 else{
Jeff Thompson17a9da82012-11-12 01:11:01 -08002340 if(LOG>4) console.log('GOING TO WRITE A BLOB ' + Content );
2341
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002342 this.writeBlob(Content);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002343 }
2344
2345 this.writeEndElement();
2346}
2347
Jeff Thompson17a9da82012-11-12 01:11:01 -08002348
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002349
2350var TypeAndVal = function TypeAndVal(_type,_val) {
2351 this.type = _type;
2352 this.val = _val;
2353
2354};
2355
Jeff Thompson17a9da82012-11-12 01:11:01 -08002356
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002357BinaryXMLEncoder.prototype.encodeTypeAndVal = function(
2358 //int
2359 type,
2360 //long
Jeff Thompson754652d2012-11-24 16:23:43 -08002361 val
Jeff Thompson17a9da82012-11-12 01:11:01 -08002362 ) {
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002363
Jeff Thompson17a9da82012-11-12 01:11:01 -08002364 if(LOG>4) console.log('Encoding type '+ type+ ' and value '+ val);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002365
Jeff Thompson17a9da82012-11-12 01:11:01 -08002366 if(LOG>4) console.log('OFFSET IS ' + this.offset);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002367
2368 if ((type > XML_UDATA) || (type < 0) || (val < 0)) {
2369 throw new Error("Tag and value must be positive, and tag valid.");
2370 }
2371
2372 // Encode backwards. Calculate how many bytes we need:
2373 var numEncodingBytes = this.numEncodingBytes(val);
2374
Jeff Thompson754652d2012-11-24 16:23:43 -08002375 if ((this.offset + numEncodingBytes) > this.ostream.length) {
2376 throw new Error("Buffer space of " + (this.ostream.length - this.offset) +
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002377 " bytes insufficient to hold " +
2378 numEncodingBytes + " of encoded type and value.");
2379 }
2380
2381 // Bottom 4 bits of val go in last byte with tag.
Jeff Thompson754652d2012-11-24 16:23:43 -08002382 this.ostream[this.offset + numEncodingBytes - 1] =
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002383 //(byte)
2384 (BYTE_MASK &
2385 (((XML_TT_MASK & type) |
2386 ((XML_TT_VAL_MASK & val) << XML_TT_BITS))) |
2387 XML_TT_NO_MORE); // set top bit for last byte
2388 val = val >>> XML_TT_VAL_BITS;;
2389
2390 // Rest of val goes into preceding bytes, 7 bits per byte, top bit
2391 // is "more" flag.
2392 var i = this.offset + numEncodingBytes - 2;
2393 while ((0 != val) && (i >= this.offset)) {
Jeff Thompson754652d2012-11-24 16:23:43 -08002394 this.ostream[i] = //(byte)
Jeff Thompson17a9da82012-11-12 01:11:01 -08002395 (BYTE_MASK & (val & XML_REG_VAL_MASK)); // leave top bit unset
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002396 val = val >>> XML_REG_VAL_BITS;
2397 --i;
2398 }
2399 if (val != 0) {
2400 throw new Error( "This should not happen: miscalculated encoding");
2401 //Log.warning(Log.FAC_ENCODING, "This should not happen: miscalculated encoding length, have " + val + " left.");
2402 }
2403 this.offset+= numEncodingBytes;
2404
2405 return numEncodingBytes;
2406};
2407
Jeff Thompson754652d2012-11-24 16:23:43 -08002408/*
2409 * Encode ustring as utf8.
2410 */
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002411BinaryXMLEncoder.prototype.encodeUString = function(
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002412 //String
2413 ustring,
2414 //byte
2415 type) {
2416
Jeff Thompson754652d2012-11-24 16:23:43 -08002417 if (null == ustring)
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002418 return;
Jeff Thompson754652d2012-11-24 16:23:43 -08002419 if (type == XML_TAG || type == XML_ATTR && ustring.length == 0)
2420 return;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002421
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002422 if(LOG>3) console.log("The string to write is ");
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002423 if(LOG>3) console.log(ustring);
2424
Jeff Thompson754652d2012-11-24 16:23:43 -08002425 var strBytes = DataUtils.stringToUtf8Array(ustring);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002426
2427 this.encodeTypeAndVal(type,
2428 (((type == XML_TAG) || (type == XML_ATTR)) ?
2429 (strBytes.length-1) :
Jeff Thompson754652d2012-11-24 16:23:43 -08002430 strBytes.length));
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002431
2432 if(LOG>3) console.log("THE string to write is ");
2433
2434 if(LOG>3) console.log(strBytes);
2435
2436 this.writeString(strBytes,this.offset);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002437 this.offset+= strBytes.length;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002438};
2439
2440
2441
2442BinaryXMLEncoder.prototype.encodeBlob = function(
Jeff Thompson17a9da82012-11-12 01:11:01 -08002443 //Uint8Array
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002444 blob,
2445 //int
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002446 length) {
2447
2448
Jeff Thompson6576bbb2012-10-28 22:20:02 -07002449 if (null == blob)
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002450 return;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002451
2452 if(LOG>4) console.log('LENGTH OF XML_BLOB IS '+length);
2453
Jeff Thompson17a9da82012-11-12 01:11:01 -08002454 /*blobCopy = new Array(blob.Length);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002455
Jeff Thompson17a9da82012-11-12 01:11:01 -08002456 for (i = 0; i < blob.length; i++) //in InStr.ToCharArray())
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002457 {
2458 blobCopy[i] = blob[i];
Jeff Thompson17a9da82012-11-12 01:11:01 -08002459 }*/
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002460
Jeff Thompson754652d2012-11-24 16:23:43 -08002461 this.encodeTypeAndVal(XML_BLOB, length);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002462
Jeff Thompson17a9da82012-11-12 01:11:01 -08002463 this.writeBlobArray(blob, this.offset);
2464 this.offset += length;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002465};
2466
2467var ENCODING_LIMIT_1_BYTE = ((1 << (XML_TT_VAL_BITS)) - 1);
2468var ENCODING_LIMIT_2_BYTES = ((1 << (XML_TT_VAL_BITS + XML_REG_VAL_BITS)) - 1);
2469var ENCODING_LIMIT_3_BYTES = ((1 << (XML_TT_VAL_BITS + 2 * XML_REG_VAL_BITS)) - 1);
2470
2471BinaryXMLEncoder.prototype.numEncodingBytes = function(
2472 //long
2473 x) {
2474 if (x <= ENCODING_LIMIT_1_BYTE) return (1);
2475 if (x <= ENCODING_LIMIT_2_BYTES) return (2);
2476 if (x <= ENCODING_LIMIT_3_BYTES) return (3);
2477
2478 var numbytes = 1;
2479
2480 // Last byte gives you XML_TT_VAL_BITS
2481 // Remainder each give you XML_REG_VAL_BITS
2482 x = x >>> XML_TT_VAL_BITS;
2483 while (x != 0) {
2484 numbytes++;
2485 x = x >>> XML_REG_VAL_BITS;
2486 }
2487 return (numbytes);
2488};
2489
2490BinaryXMLEncoder.prototype.writeDateTime = function(
2491 //String
2492 tag,
2493 //CCNTime
2494 dateTime) {
2495
2496 if(LOG>4)console.log('ENCODING DATE with LONG VALUE');
2497 if(LOG>4)console.log(dateTime.msec);
2498
2499 //var binarydate = DataUtils.unsignedLongToByteArray( Math.round((dateTime.msec/1000) * 4096) );
2500
2501
2502 //parse to hex
2503 var binarydate = Math.round((dateTime.msec/1000) * 4096).toString(16) ;
2504
2505 //HACK
2506 var binarydate = DataUtils.toNumbers( '0'.concat(binarydate,'0')) ;
2507
2508
2509 if(LOG>4)console.log('ENCODING DATE with BINARY VALUE');
2510 if(LOG>4)console.log(binarydate);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002511 if(LOG>4)console.log('ENCODING DATE with BINARY VALUE(HEX)');
2512 if(LOG>4)console.log(DataUtils.toHex(binarydate));
2513
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002514 this.writeElement(tag, binarydate);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002515};
2516
2517BinaryXMLEncoder.prototype.writeString = function(
2518 //String
2519 input,
2520 //CCNTime
2521 offset) {
2522
2523 if(typeof input === 'string'){
2524 //console.log('went here');
2525 if(LOG>4) console.log('GOING TO WRITE A STRING');
2526 if(LOG>4) console.log(input);
2527
Jeff Thompson17a9da82012-11-12 01:11:01 -08002528 for (i = 0; i < input.length; i++) {
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002529 if(LOG>4) console.log('input.charCodeAt(i)=' + input.charCodeAt(i));
2530 this.ostream[this.offset+i] = (input.charCodeAt(i));
2531 }
2532 }
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002533 else{
Jeff Thompson17a9da82012-11-12 01:11:01 -08002534 if(LOG>4) console.log('GOING TO WRITE A STRING IN BINARY FORM');
2535 if(LOG>4) console.log(input);
2536
2537 this.writeBlobArray(input);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002538 }
2539 /*
2540 else if(typeof input === 'object'){
2541
2542 }
2543 */
2544};
2545
Jeff Thompson17a9da82012-11-12 01:11:01 -08002546
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002547BinaryXMLEncoder.prototype.writeBlobArray = function(
Jeff Thompson17a9da82012-11-12 01:11:01 -08002548 //Uint8Array
2549 blob,
2550 //int
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002551 offset) {
2552
2553 if(LOG>4) console.log('GOING TO WRITE A BLOB');
2554
Jeff Thompson17a9da82012-11-12 01:11:01 -08002555 /*for (var i = 0; i < Blob.length; i++) {
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002556 this.ostream[this.offset+i] = Blob[i];
Jeff Thompson17a9da82012-11-12 01:11:01 -08002557 }*/
2558 this.ostream.set(blob, this.offset);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002559};
2560
2561
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002562BinaryXMLEncoder.prototype.getReducedOstream = function() {
Jeff Thompson17a9da82012-11-12 01:11:01 -08002563 return this.ostream.subarray(0, this.offset);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002564};
2565
2566
2567/*
Jeff Thompsondad617b2012-10-14 17:11:41 -07002568 * This class is used to decode ccnb binary elements (blob, type/value pairs).
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002569 *
Jeff Thompson754652d2012-11-24 16:23:43 -08002570 * @author: Meki Cheraoui
Jeff Thompson745026e2012-10-13 12:49:20 -07002571 * See COPYING for copyright and distribution information.
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002572 */
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002573
2574var XML_EXT = 0x00;
2575
2576var XML_TAG = 0x01;
2577
2578var XML_DTAG = 0x02;
2579
2580var XML_ATTR = 0x03;
2581
2582var XML_DATTR = 0x04;
2583
2584var XML_BLOB = 0x05;
2585
2586var XML_UDATA = 0x06;
2587
2588var XML_CLOSE = 0x0;
2589
2590var XML_SUBTYPE_PROCESSING_INSTRUCTIONS = 16;
2591
2592
2593var XML_TT_BITS = 3;
2594var XML_TT_MASK = ((1 << XML_TT_BITS) - 1);
2595var XML_TT_VAL_BITS = XML_TT_BITS + 1;
2596var XML_TT_VAL_MASK = ((1 << (XML_TT_VAL_BITS)) - 1);
2597var XML_REG_VAL_BITS = 7;
2598var XML_REG_VAL_MASK = ((1 << XML_REG_VAL_BITS) - 1);
2599var XML_TT_NO_MORE = (1 << XML_REG_VAL_BITS); // 0x80
2600var BYTE_MASK = 0xFF;
2601var LONG_BYTES = 8;
2602var LONG_BITS = 64;
2603
2604var bits_11 = 0x0000007FF;
2605var bits_18 = 0x00003FFFF;
2606var bits_32 = 0x0FFFFFFFF;
2607
2608
2609
2610//returns a string
2611tagToString = function(/*long*/ tagVal) {
2612 if ((tagVal >= 0) && (tagVal < CCNProtocolDTagsStrings.length)) {
2613 return CCNProtocolDTagsStrings[tagVal];
2614 } else if (tagVal == CCNProtocolDTags.CCNProtocolDataUnit) {
2615 return CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT;
2616 }
2617 return null;
2618};
2619
2620//returns a Long
2621stringToTag = function(/*String*/ tagName) {
2622 // the slow way, but right now we don't care.... want a static lookup for the forward direction
2623 for (var i=0; i < CCNProtocolDTagsStrings.length; ++i) {
2624 if ((null != CCNProtocolDTagsStrings[i]) && (CCNProtocolDTagsStrings[i] == tagName)) {
2625 return i;
2626 }
2627 }
2628 if (CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT == tagName) {
2629 return CCNProtocolDTags.CCNProtocolDataUnit;
2630 }
2631 return null;
2632};
2633
2634//console.log(stringToTag(64));
2635var BinaryXMLDecoder = function BinaryXMLDecoder(istream){
2636 var MARK_LEN=512;
2637 var DEBUG_MAX_LEN = 32768;
2638
2639 this.istream = istream;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002640 this.offset = 0;
2641};
2642
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002643BinaryXMLDecoder.prototype.readAttributes = function(
2644 //TreeMap<String,String>
2645 attributes){
2646
2647 if (null == attributes) {
2648 return;
2649 }
2650
2651 try {
2652
2653 //this.TypeAndVal
Jeff Thompson754652d2012-11-24 16:23:43 -08002654 var nextTV = this.peekTypeAndVal();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002655
2656 while ((null != nextTV) && ((XML_ATTR == nextTV.type()) ||
2657 (XML_DATTR == nextTV.type()))) {
2658
2659 //this.TypeAndVal
Jeff Thompson754652d2012-11-24 16:23:43 -08002660 var thisTV = this.decodeTypeAndVal();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002661
2662 var attributeName = null;
2663 if (XML_ATTR == thisTV.type()) {
2664
Jeff Thompsondad617b2012-10-14 17:11:41 -07002665 attributeName = this.decodeUString(thisTV.val()+1);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002666
2667 } else if (XML_DATTR == thisTV.type()) {
2668 // DKS TODO are attributes same or different dictionary?
2669 attributeName = tagToString(thisTV.val());
2670 if (null == attributeName) {
Jeff Thompsoncab74c32012-10-21 13:27:28 -07002671 throw new ContentDecodingException(new Error("Unknown DATTR value" + thisTV.val()));
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002672 }
2673 }
2674
Jeff Thompsondad617b2012-10-14 17:11:41 -07002675 var attributeValue = this.decodeUString();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002676
2677 attributes.put(attributeName, attributeValue);
2678
Jeff Thompsondad617b2012-10-14 17:11:41 -07002679 nextTV = this.peekTypeAndVal();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002680 }
2681
2682 } catch ( e) {
2683
Jeff Thompsoncab74c32012-10-21 13:27:28 -07002684 throw new ContentDecodingException(new Error("readStartElement", e));
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002685 }
2686};
2687
2688
2689BinaryXMLDecoder.prototype.initializeDecoding = function() {
2690 //if (!this.istream.markSupported()) {
2691 //throw new IllegalArgumentException(this.getClass().getName() + ": input stream must support marking!");
2692 //}
2693}
2694
2695BinaryXMLDecoder.prototype.readStartDocument = function(){
2696 // Currently no start document in binary encoding.
2697 }
2698
2699BinaryXMLDecoder.prototype.readEndDocument = function() {
2700 // Currently no end document in binary encoding.
2701 };
2702
2703BinaryXMLDecoder.prototype.readStartElement = function(
2704 //String
2705 startTag,
2706 //TreeMap<String, String>
2707 attributes) {
2708
2709
2710 //NOT SURE
2711 //if(typeof startTag == 'number')
2712 //startTag = tagToString(startTag);
2713
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002714 //TypeAndVal
Jeff Thompsondad617b2012-10-14 17:11:41 -07002715 tv = this.decodeTypeAndVal();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002716
2717 if (null == tv) {
Jeff Thompsoncab74c32012-10-21 13:27:28 -07002718 throw new ContentDecodingException(new Error("Expected start element: " + startTag + " got something not a tag."));
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002719 }
2720
2721 //String
Jeff Thompson754652d2012-11-24 16:23:43 -08002722 var decodedTag = null;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002723 //console.log(tv);
2724 //console.log(typeof tv);
2725
2726 //console.log(XML_TAG);
2727 if (tv.type() == XML_TAG) {
2728 //console.log('got here');
2729 //Log.info(Log.FAC_ENCODING, "Unexpected: got tag in readStartElement; looking for tag " + startTag + " got length: " + (int)tv.val()+1);
2730 // Tag value represents length-1 as tags can never be empty.
2731 var valval ;
2732 if(typeof tv.val() == 'string'){
2733 valval = (parseInt(tv.val())) + 1;
2734 }
2735 else
2736 valval = (tv.val())+ 1;
2737
2738 //console.log('valval is ' +valval);
2739
Jeff Thompsondad617b2012-10-14 17:11:41 -07002740 decodedTag = this.decodeUString(valval);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002741
2742 } else if (tv.type() == XML_DTAG) {
2743 //console.log('gothere');
2744 //console.log(tv.val());
2745 //decodedTag = tagToString(tv.val());
2746 //console.log()
2747 decodedTag = tv.val();
2748 }
2749
2750 //console.log(decodedTag);
2751 //console.log('startTag is '+startTag);
2752
2753
2754 if ((null == decodedTag) || decodedTag != startTag ) {
2755 console.log('expecting '+ startag + ' but got '+ decodedTag);
Jeff Thompsoncab74c32012-10-21 13:27:28 -07002756 throw new ContentDecodingException(new Error("Expected start element: " + startTag + " got: " + decodedTag + "(" + tv.val() + ")"));
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002757 }
2758
2759 // DKS: does not read attributes out of stream if caller doesn't
2760 // ask for them. Should possibly peek and skip over them regardless.
2761 // TODO: fix this
2762 if (null != attributes) {
2763 readAttributes(attributes);
2764 }
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002765 }
2766
2767
2768BinaryXMLDecoder.prototype.readAttributes = function(
2769 //TreeMap<String,String>
2770 attributes) {
2771
2772 if (null == attributes) {
2773 return;
2774 }
2775
2776 try {
2777 // Now need to get attributes.
2778 //TypeAndVal
Jeff Thompson754652d2012-11-24 16:23:43 -08002779 var nextTV = this.peekTypeAndVal();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002780
2781 while ((null != nextTV) && ((XML_ATTR == nextTV.type()) ||
2782 (XML_DATTR == nextTV.type()))) {
2783
2784 // Decode this attribute. First, really read the type and value.
2785 //this.TypeAndVal
Jeff Thompson754652d2012-11-24 16:23:43 -08002786 var thisTV = this.decodeTypeAndVal();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002787
2788 //String
Jeff Thompson754652d2012-11-24 16:23:43 -08002789 var attributeName = null;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002790 if (XML_ATTR == thisTV.type()) {
2791 // Tag value represents length-1 as attribute names cannot be empty.
2792 var valval ;
2793 if(typeof tv.val() == 'string'){
2794 valval = (parseInt(tv.val())) + 1;
2795 }
2796 else
2797 valval = (tv.val())+ 1;
2798
Jeff Thompsondad617b2012-10-14 17:11:41 -07002799 attributeName = this.decodeUString(valval);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002800
2801 } else if (XML_DATTR == thisTV.type()) {
2802 // DKS TODO are attributes same or different dictionary?
2803 attributeName = tagToString(thisTV.val());
2804 if (null == attributeName) {
Jeff Thompsoncab74c32012-10-21 13:27:28 -07002805 throw new ContentDecodingException(new Error("Unknown DATTR value" + thisTV.val()));
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002806 }
2807 }
2808 // Attribute values are always UDATA
2809 //String
Jeff Thompson754652d2012-11-24 16:23:43 -08002810 var attributeValue = this.decodeUString();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002811
2812 //
2813 attributes.push([attributeName, attributeValue]);
2814
Jeff Thompsondad617b2012-10-14 17:11:41 -07002815 nextTV = this.peekTypeAndVal();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002816 }
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002817 } catch ( e) {
Jeff Thompsoncab74c32012-10-21 13:27:28 -07002818 throw new ContentDecodingException(new Error("readStartElement", e));
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002819 }
2820};
2821
2822//returns a string
2823BinaryXMLDecoder.prototype.peekStartElementAsString = function() {
2824 //this.istream.mark(MARK_LEN);
2825
2826 //String
Jeff Thompson754652d2012-11-24 16:23:43 -08002827 var decodedTag = null;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002828 var previousOffset = this.offset;
2829 try {
2830 // Have to distinguish genuine errors from wrong tags. Could either use
2831 // a special exception subtype, or redo the work here.
2832 //this.TypeAndVal
Jeff Thompson754652d2012-11-24 16:23:43 -08002833 var tv = this.decodeTypeAndVal();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002834
2835 if (null != tv) {
2836
2837 if (tv.type() == XML_TAG) {
2838 /*if (tv.val()+1 > DEBUG_MAX_LEN) {
Jeff Thompsoncab74c32012-10-21 13:27:28 -07002839 throw new ContentDecodingException(new Error("Decoding error: length " + tv.val()+1 + " longer than expected maximum length!")(;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002840 }*/
2841
2842 // Tag value represents length-1 as tags can never be empty.
2843 var valval ;
2844 if(typeof tv.val() == 'string'){
2845 valval = (parseInt(tv.val())) + 1;
2846 }
2847 else
2848 valval = (tv.val())+ 1;
2849
Jeff Thompsondad617b2012-10-14 17:11:41 -07002850 decodedTag = this.decodeUString(valval);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002851
2852 //Log.info(Log.FAC_ENCODING, "Unexpected: got text tag in peekStartElement; length: " + valval + " decoded tag = " + decodedTag);
2853
2854 } else if (tv.type() == XML_DTAG) {
2855 decodedTag = tagToString(tv.val());
2856 }
2857
2858 } // else, not a type and val, probably an end element. rewind and return false.
2859
2860 } catch ( e) {
2861
2862 } finally {
2863 try {
2864 this.offset = previousOffset;
2865 } catch ( e) {
2866 Log.logStackTrace(Log.FAC_ENCODING, Level.WARNING, e);
Jeff Thompsoncab74c32012-10-21 13:27:28 -07002867 throw new ContentDecodingException(new Error("Cannot reset stream! " + e.getMessage(), e));
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002868 }
2869 }
2870 return decodedTag;
2871};
2872
2873BinaryXMLDecoder.prototype.peekStartElement = function(
2874 //String
2875 startTag) {
2876 //String
2877 if(typeof startTag == 'string'){
Jeff Thompson754652d2012-11-24 16:23:43 -08002878 var decodedTag = this.peekStartElementAsString();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002879
2880 if ((null != decodedTag) && decodedTag == startTag) {
2881 return true;
2882 }
2883 return false;
2884 }
2885 else if(typeof startTag == 'number'){
Jeff Thompson754652d2012-11-24 16:23:43 -08002886 var decodedTag = this.peekStartElementAsLong();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002887 if ((null != decodedTag) && decodedTag == startTag) {
2888 return true;
2889 }
2890 return false;
2891 }
2892 else{
Jeff Thompsoncab74c32012-10-21 13:27:28 -07002893 throw new ContentDecodingException(new Error("SHOULD BE STRING OR NUMBER"));
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002894 }
2895}
2896//returns Long
2897BinaryXMLDecoder.prototype.peekStartElementAsLong = function() {
2898 //this.istream.mark(MARK_LEN);
2899
2900 //Long
Jeff Thompson754652d2012-11-24 16:23:43 -08002901 var decodedTag = null;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002902
2903 var previousOffset = this.offset;
2904
2905 try {
2906 // Have to distinguish genuine errors from wrong tags. Could either use
2907 // a special exception subtype, or redo the work here.
2908 //this.TypeAndVal
Jeff Thompson754652d2012-11-24 16:23:43 -08002909 var tv = this.decodeTypeAndVal();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002910
2911 if (null != tv) {
2912
2913 if (tv.type() == XML_TAG) {
2914 if (tv.val()+1 > DEBUG_MAX_LEN) {
Jeff Thompsoncab74c32012-10-21 13:27:28 -07002915 throw new ContentDecodingException(new Error("Decoding error: length " + tv.val()+1 + " longer than expected maximum length!"));
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002916 }
2917
2918 var valval ;
2919 if(typeof tv.val() == 'string'){
2920 valval = (parseInt(tv.val())) + 1;
2921 }
2922 else
2923 valval = (tv.val())+ 1;
2924
2925 // Tag value represents length-1 as tags can never be empty.
2926 //String
Jeff Thompson754652d2012-11-24 16:23:43 -08002927 var strTag = this.decodeUString(valval);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002928
2929 decodedTag = stringToTag(strTag);
2930
2931 //Log.info(Log.FAC_ENCODING, "Unexpected: got text tag in peekStartElement; length: " + valval + " decoded tag = " + decodedTag);
2932
2933 } else if (tv.type() == XML_DTAG) {
2934 decodedTag = tv.val();
2935 }
2936
2937 } // else, not a type and val, probably an end element. rewind and return false.
2938
2939 } catch ( e) {
2940
2941 } finally {
2942 try {
2943 //this.istream.reset();
2944 this.offset = previousOffset;
2945 } catch ( e) {
2946 Log.logStackTrace(Log.FAC_ENCODING, Level.WARNING, e);
2947 throw new Error("Cannot reset stream! " + e.getMessage(), e);
2948 }
2949 }
2950 return decodedTag;
2951 };
2952
2953
2954// returns a byte[]
2955BinaryXMLDecoder.prototype.readBinaryElement = function(
2956 //long
2957 startTag,
2958 //TreeMap<String, String>
2959 attributes){
2960 //byte []
Jeff Thompson754652d2012-11-24 16:23:43 -08002961 var blob = null;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002962
Jeff Thompson754652d2012-11-24 16:23:43 -08002963 this.readStartElement(startTag, attributes);
2964 blob = this.readBlob();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002965
2966 return blob;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002967};
2968
2969
2970BinaryXMLDecoder.prototype.readEndElement = function(){
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002971 if(LOG>4)console.log('this.offset is '+this.offset);
2972
2973 var next = this.istream[this.offset];
2974
2975 this.offset++;
2976 //read();
2977
2978 if(LOG>4)console.log('XML_CLOSE IS '+XML_CLOSE);
2979 if(LOG>4)console.log('next is '+next);
2980
2981 if (next != XML_CLOSE) {
2982 console.log("Expected end element, got: " + next);
Jeff Thompsoncab74c32012-10-21 13:27:28 -07002983 throw new ContentDecodingException(new Error("Expected end element, got: " + next));
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002984 }
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002985 };
2986
2987
2988//String
2989BinaryXMLDecoder.prototype.readUString = function(){
2990 //String
Jeff Thompson754652d2012-11-24 16:23:43 -08002991 var ustring = this.decodeUString();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07002992 this.readEndElement();
2993 return ustring;
2994
2995 };
2996
2997
2998//returns a byte[]
2999BinaryXMLDecoder.prototype.readBlob = function() {
3000 //byte []
3001
Jeff Thompson754652d2012-11-24 16:23:43 -08003002 var blob = this.decodeBlob();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003003 this.readEndElement();
3004 return blob;
3005
3006 };
3007
3008
3009//CCNTime
3010BinaryXMLDecoder.prototype.readDateTime = function(
3011 //long
3012 startTag) {
3013 //byte []
3014
3015 var byteTimestamp = this.readBinaryElement(startTag);
3016
3017 //var lontimestamp = DataUtils.byteArrayToUnsignedLong(byteTimestamp);
3018
Jeff Thompson754652d2012-11-24 16:23:43 -08003019 byteTimestamp = DataUtils.toHex(byteTimestamp);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003020
3021
Jeff Thompson754652d2012-11-24 16:23:43 -08003022 byteTimestamp = parseInt(byteTimestamp, 16);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003023
Jeff Thompson754652d2012-11-24 16:23:43 -08003024 var lontimestamp = (byteTimestamp/ 4096) * 1000;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003025
3026 //if(lontimestamp<0) lontimestamp = - lontimestamp;
3027
3028 if(LOG>3) console.log('DECODED DATE WITH VALUE');
3029 if(LOG>3) console.log(lontimestamp);
3030
3031
3032 //CCNTime
Jeff Thompson754652d2012-11-24 16:23:43 -08003033 var timestamp = new CCNTime(lontimestamp);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003034 //timestamp.setDateBinary(byteTimestamp);
3035
3036 if (null == timestamp) {
Jeff Thompsoncab74c32012-10-21 13:27:28 -07003037 throw new ContentDecodingException(new Error("Cannot parse timestamp: " + DataUtils.printHexBytes(byteTimestamp)));
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003038 }
3039 return timestamp;
3040};
3041
Jeff Thompsondad617b2012-10-14 17:11:41 -07003042BinaryXMLDecoder.prototype.decodeTypeAndVal = function() {
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003043
Jeff Thompson6576bbb2012-10-28 22:20:02 -07003044 /*int*/var type = -1;
3045 /*long*/var val = 0;
3046 /*boolean*/var more = true;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003047
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003048 do {
3049
3050 var next = this.istream[this.offset ];
3051
3052
3053 if (next < 0) {
3054 return null;
3055 }
3056
3057 if ((0 == next) && (0 == val)) {
3058 return null;
3059 }
3060
3061 more = (0 == (next & XML_TT_NO_MORE));
3062
3063 if (more) {
3064 val = val << XML_REG_VAL_BITS;
3065 val |= (next & XML_REG_VAL_MASK);
3066 } else {
3067
3068 type = next & XML_TT_MASK;
3069 val = val << XML_TT_VAL_BITS;
3070 val |= ((next >>> XML_TT_BITS) & XML_TT_VAL_MASK);
3071 }
3072
3073 this.offset++;
3074
3075 } while (more);
3076
3077 if(LOG>3)console.log('TYPE is '+ type + ' VAL is '+ val);
3078
3079 return new TypeAndVal(type, val);
3080};
3081
3082
3083
3084//TypeAndVal
Jeff Thompsondad617b2012-10-14 17:11:41 -07003085BinaryXMLDecoder.peekTypeAndVal = function() {
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003086 //TypeAndVal
Jeff Thompson754652d2012-11-24 16:23:43 -08003087 var tv = null;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003088
Jeff Thompsondad617b2012-10-14 17:11:41 -07003089 //this.istream.mark(LONG_BYTES*2);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003090
3091 var previousOffset = this.offset;
3092
3093 try {
Jeff Thompsondad617b2012-10-14 17:11:41 -07003094 tv = this.decodeTypeAndVal();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003095 } finally {
Jeff Thompsondad617b2012-10-14 17:11:41 -07003096 //this.istream.reset();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003097 this.offset = previousOffset;
3098 }
3099
3100 return tv;
3101};
3102
3103
Jeff Thompson17a9da82012-11-12 01:11:01 -08003104//Uint8Array
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003105BinaryXMLDecoder.prototype.decodeBlob = function(
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003106 //int
3107 blobLength) {
3108
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003109 if(null == blobLength){
3110 //TypeAndVal
Jeff Thompson754652d2012-11-24 16:23:43 -08003111 var tv = this.decodeTypeAndVal();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003112
3113 var valval ;
3114
3115 if(typeof tv.val() == 'string'){
3116 valval = (parseInt(tv.val()));
3117 }
3118 else
3119 valval = (tv.val());
3120
3121 //console.log('valval here is ' + valval);
Jeff Thompsondad617b2012-10-14 17:11:41 -07003122 return this.decodeBlob(valval);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003123 }
3124
3125 //
Jeff Thompson17a9da82012-11-12 01:11:01 -08003126 //Uint8Array
3127 var bytes = this.istream.subarray(this.offset, this.offset+ blobLength);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003128 this.offset += blobLength;
3129
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003130 return bytes;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003131};
3132
3133var count =0;
3134
3135//String
3136BinaryXMLDecoder.prototype.decodeUString = function(
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003137 //int
3138 byteLength) {
3139
3140 /*
3141 console.log('COUNT IS '+count);
3142 console.log('INPUT BYTELENGTH IS '+byteLength);
3143 count++;
3144 if(null == byteLength|| undefined == byteLength){
3145 console.log("!!!!");
Jeff Thompsondad617b2012-10-14 17:11:41 -07003146 tv = this.decodeTypeAndVal();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003147 var valval ;
3148 if(typeof tv.val() == 'string'){
3149 valval = (parseInt(tv.val()));
3150 }
3151 else
3152 valval = (tv.val());
3153
3154 if(LOG>4) console.log('valval is ' + valval);
Jeff Thompsondad617b2012-10-14 17:11:41 -07003155 byteLength= this.decodeUString(valval);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003156
3157 //if(LOG>4) console.log('byte Length found in type val is '+ byteLength.charCodeAt(0));
3158 byteLength = parseInt(byteLength);
3159
3160
3161 //byteLength = byteLength.charCodeAt(0);
3162 //if(LOG>4) console.log('byte Length found in type val is '+ byteLength);
3163 }
3164 if(LOG>4)console.log('byteLength is '+byteLength);
3165 if(LOG>4)console.log('type of byteLength is '+typeof byteLength);
3166
Jeff Thompsondad617b2012-10-14 17:11:41 -07003167 stringBytes = this.decodeBlob(byteLength);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003168
3169 //console.log('String bytes are '+ stringBytes);
3170 //console.log('stringBytes);
3171
3172 if(LOG>4)console.log('byteLength is '+byteLength);
3173 if(LOG>4)console.log('this.offset is '+this.offset);
3174
3175 tempBuffer = this.istream.slice(this.offset, this.offset+byteLength);
3176 if(LOG>4)console.log('TEMPBUFFER IS' + tempBuffer);
3177 if(LOG>4)console.log( tempBuffer);
3178
3179 if(LOG>4)console.log('ADDING to offset value' + byteLength);
3180 this.offset+= byteLength;
3181 //if(LOG>3)console.log('read the String' + tempBuffer.toString('ascii'));
3182 //return tempBuffer.toString('ascii');//
3183
3184
3185 //if(LOG>3)console.log( 'STRING READ IS '+ DataUtils.getUTF8StringFromBytes(stringBytes) ) ;
3186 //if(LOG>3)console.log( 'STRING READ IS '+ DataUtils.getUTF8StringFromBytes(tempBuffer) ) ;
3187 //if(LOG>3)console.log(DataUtils.getUTF8StringFromBytes(tempBuffer) ) ;
3188 //return DataUtils.getUTF8StringFromBytes(tempBuffer);
3189
3190 if(LOG>3)console.log( 'STRING READ IS '+ DataUtils.toString(stringBytes) ) ;
3191 if(LOG>3)console.log( 'TYPE OF STRING READ IS '+ typeof DataUtils.toString(stringBytes) ) ;
3192
3193 return DataUtils.toString(stringBytes);*/
3194
3195 if(null == byteLength ){
3196 var tempStreamPosition = this.offset;
3197
3198 //TypeAndVal
Jeff Thompson754652d2012-11-24 16:23:43 -08003199 var tv = this.decodeTypeAndVal();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003200
3201 if(LOG>3)console.log('TV is '+tv);
3202 if(LOG>3)console.log(tv);
3203
3204 if(LOG>3)console.log('Type of TV is '+typeof tv);
3205
3206 if ((null == tv) || (XML_UDATA != tv.type())) { // if we just have closers left, will get back null
3207 //if (Log.isLoggable(Log.FAC_ENCODING, Level.FINEST))
3208 //Log.finest(Log.FAC_ENCODING, "Expected UDATA, got " + ((null == tv) ? " not a tag " : tv.type()) + ", assuming elided 0-length blob.");
3209
3210 this.offset = tempStreamPosition;
3211
3212 return "";
3213 }
3214
Jeff Thompsondad617b2012-10-14 17:11:41 -07003215 return this.decodeUString(tv.val());
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003216 }
3217 else{
3218 //byte []
Jeff Thompson754652d2012-11-24 16:23:43 -08003219 var stringBytes = this.decodeBlob(byteLength);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003220
3221 //return DataUtils.getUTF8StringFromBytes(stringBytes);
3222 return DataUtils.toString(stringBytes);
3223
3224 }
3225};
3226
3227
3228
3229
3230//OBject containg a pair of type and value
3231var TypeAndVal = function TypeAndVal(_type,_val) {
3232 this.t = _type;
3233 this.v = _val;
3234};
3235
3236TypeAndVal.prototype.type = function(){
3237 return this.t;
3238};
3239
3240TypeAndVal.prototype.val = function(){
3241 return this.v;
3242};
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003243
3244
3245
3246
3247BinaryXMLDecoder.prototype.readIntegerElement =function(
3248 //String
3249 startTag) {
3250
3251 //String
3252 if(LOG>4) console.log('READING INTEGER '+ startTag);
3253 if(LOG>4) console.log('TYPE OF '+ typeof startTag);
3254
Jeff Thompson754652d2012-11-24 16:23:43 -08003255 var strVal = this.readUTF8Element(startTag);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003256
3257 return parseInt(strVal);
3258};
3259
3260
3261BinaryXMLDecoder.prototype.readUTF8Element =function(
3262 //String
3263 startTag,
3264 //TreeMap<String, String>
3265 attributes) {
Jeff Thompsoncab74c32012-10-21 13:27:28 -07003266 //throws Error where name == "ContentDecodingException"
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003267
3268 this.readStartElement(startTag, attributes); // can't use getElementText, can't get attributes
3269 //String
Jeff Thompson754652d2012-11-24 16:23:43 -08003270 var strElementText = this.readUString();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003271 return strElementText;
3272};
3273
Jeff Thompson17a9da82012-11-12 01:11:01 -08003274
Jeff Thompsondad617b2012-10-14 17:11:41 -07003275/*
3276 * Set the offset into the input, used for the next read.
3277 */
3278BinaryXMLDecoder.prototype.seek = function(
3279 //int
3280 offset) {
Jeff Thompson17a9da82012-11-12 01:11:01 -08003281 this.offset = offset;
Jeff Thompsondad617b2012-10-14 17:11:41 -07003282}
3283
3284/*
Jeff Thompsoncab74c32012-10-21 13:27:28 -07003285 * Call with: throw new ContentDecodingException(new Error("message")).
3286 */
3287function ContentDecodingException(error) {
3288 this.message = error.message;
3289 // Copy lineNumber, etc. from where new Error was called.
3290 for (var prop in error)
3291 this[prop] = error[prop];
3292}
3293ContentDecodingException.prototype = new Error();
3294ContentDecodingException.prototype.name = "ContentDecodingException";
3295
3296
Jeff Thompsoncab74c32012-10-21 13:27:28 -07003297/*
Jeff Thompsondad617b2012-10-14 17:11:41 -07003298 * This class uses BinaryXMLDecoder to follow the structure of a ccnb binary element to
3299 * determine its end.
3300 *
Jeff Thompson754652d2012-11-24 16:23:43 -08003301 * @author: Jeff Thompson
Jeff Thompsondad617b2012-10-14 17:11:41 -07003302 * See COPYING for copyright and distribution information.
3303 */
3304
3305var BinaryXMLStructureDecoder = function BinaryXMLDecoder() {
3306 this.gotElementEnd = false;
3307 this.offset = 0;
3308 this.level = 0;
3309 this.state = BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE;
3310 this.headerStartOffset = 0;
3311 this.readBytesEndOffset = 0;
3312};
3313
3314BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE = 0;
3315BinaryXMLStructureDecoder.READ_BYTES = 1;
3316
3317/*
3318 * Continue scanning input starting from this.offset. If found the end of the element
3319 * which started at offset 0 then return true, else false.
3320 * If this returns false, you should read more into input and call again.
3321 * You have to pass in input each time because the array could be reallocated.
3322 * This throws an exception for badly formed ccnb.
3323 */
3324BinaryXMLStructureDecoder.prototype.findElementEnd = function(
3325 // byte array
3326 input)
3327{
3328 if (this.gotElementEnd)
3329 // Someone is calling when we already got the end.
3330 return true;
3331
3332 var decoder = new BinaryXMLDecoder(input);
3333
3334 while (true) {
3335 if (this.offset >= input.length)
3336 // All the cases assume we have some input.
3337 return false;
3338
3339 switch (this.state) {
3340 case BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE:
3341 // First check for XML_CLOSE.
3342 if (this.offset == this.headerStartOffset && input[this.offset] == XML_CLOSE) {
3343 ++this.offset;
3344 // Close the level.
3345 --this.level;
3346 if (this.level == 0)
3347 // Finished.
3348 return true;
3349 if (this.level < 0)
3350 throw new Error("BinaryXMLStructureDecoder: Unexepected close tag at offset " +
3351 (this.offset - 1));
3352
3353 // Get ready for the next header.
3354 this.headerStartOffset = this.offset;
3355 break;
3356 }
3357
3358 while (true) {
3359 if (this.offset >= input.length)
3360 return false;
3361 if (input[this.offset++] & XML_TT_NO_MORE)
3362 // Break and read the header.
3363 break;
3364 }
3365
3366 decoder.seek(this.headerStartOffset);
3367 var typeAndVal = decoder.decodeTypeAndVal();
3368 if (typeAndVal == null)
3369 throw new Error("BinaryXMLStructureDecoder: Can't read header starting at offset " +
3370 this.headerStartOffset);
3371
3372 // Set the next state based on the type.
3373 var type = typeAndVal.t;
3374 if (type == XML_DATTR)
3375 // We already consumed the item. READ_HEADER_OR_CLOSE again.
3376 // ccnb has rules about what must follow an attribute, but we are just scanning.
3377 this.headerStartOffset = this.offset;
3378 else if (type == XML_DTAG || type == XML_EXT) {
3379 // Start a new level and READ_HEADER_OR_CLOSE again.
3380 ++this.level;
3381 this.headerStartOffset = this.offset;
3382 }
3383 else if (type == XML_TAG || type == XML_ATTR) {
3384 if (type == XML_TAG)
3385 // Start a new level and read the tag.
3386 ++this.level;
3387 // Minimum tag or attribute length is 1.
3388 this.readBytesEndOffset = this.offset + typeAndVal.v + 1;
3389 this.state = BinaryXMLStructureDecoder.READ_BYTES;
3390 // ccnb has rules about what must follow an attribute, but we are just scanning.
3391 }
3392 else if (type == XML_BLOB || type == XML_UDATA) {
3393 this.readBytesEndOffset = this.offset + typeAndVal.v;
3394 this.state = BinaryXMLStructureDecoder.READ_BYTES;
3395 }
3396 else
3397 throw new Error("BinaryXMLStructureDecoder: Unrecognized header type " + type);
3398 break;
3399
3400 case BinaryXMLStructureDecoder.READ_BYTES:
3401 if (input.length < this.readBytesEndOffset) {
3402 // Need more.
3403 this.offset = input.length;
3404 return false;
3405 }
3406 // Got the bytes. Read a new header or close.
3407 this.offset = this.readBytesEndOffset;
3408 this.headerStartOffset = this.offset;
3409 this.state = BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE;
3410 break;
3411
3412 default:
3413 // We don't expect this to happen.
3414 throw new Error("BinaryXMLStructureDecoder: Unrecognized state " + this.state);
3415 }
3416 }
3417};
3418
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003419/*
3420 * This class contains utilities to help parse the data
Jeff Thompson754652d2012-11-24 16:23:43 -08003421 * author: Meki Cheraoui, Jeff Thompson
Jeff Thompson745026e2012-10-13 12:49:20 -07003422 * See COPYING for copyright and distribution information.
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003423 */
3424
3425var DataUtils = function DataUtils(){
3426
3427
3428};
3429
3430
3431/*
3432 * NOTE THIS IS CURRENTLY NOT BEHING USED
3433 *
3434 */
3435
3436DataUtils.keyStr = "ABCDEFGHIJKLMNOP" +
3437 "QRSTUVWXYZabcdef" +
3438 "ghijklmnopqrstuv" +
3439 "wxyz0123456789+/" +
3440 "=";
3441
3442
3443/**
3444 * Raw String to Base 64
3445 */
3446DataUtils.stringtoBase64=function stringtoBase64(input) {
3447 input = escape(input);
3448 var output = "";
3449 var chr1, chr2, chr3 = "";
3450 var enc1, enc2, enc3, enc4 = "";
3451 var i = 0;
3452
3453 do {
3454 chr1 = input.charCodeAt(i++);
3455 chr2 = input.charCodeAt(i++);
3456 chr3 = input.charCodeAt(i++);
3457
3458 enc1 = chr1 >> 2;
3459 enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
3460 enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
3461 enc4 = chr3 & 63;
3462
3463 if (isNaN(chr2)) {
3464 enc3 = enc4 = 64;
3465 } else if (isNaN(chr3)) {
3466 enc4 = 64;
3467 }
3468
3469 output = output +
3470 DataUtils.keyStr.charAt(enc1) +
3471 DataUtils.keyStr.charAt(enc2) +
3472 DataUtils.keyStr.charAt(enc3) +
3473 DataUtils.keyStr.charAt(enc4);
3474 chr1 = chr2 = chr3 = "";
3475 enc1 = enc2 = enc3 = enc4 = "";
3476 } while (i < input.length);
3477
3478 return output;
3479 }
3480
3481/**
3482 * Base 64 to Raw String
3483 */
3484DataUtils.base64toString = function base64toString(input) {
3485 var output = "";
3486 var chr1, chr2, chr3 = "";
3487 var enc1, enc2, enc3, enc4 = "";
3488 var i = 0;
3489
3490 // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
3491 var base64test = /[^A-Za-z0-9\+\/\=]/g;
3492 /* Test for invalid characters. */
3493 if (base64test.exec(input)) {
3494 alert("There were invalid base64 characters in the input text.\n" +
3495 "Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\n" +
3496 "Expect errors in decoding.");
3497 }
3498
3499 input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
3500
3501 do {
3502 enc1 = DataUtils.keyStr.indexOf(input.charAt(i++));
3503 enc2 = DataUtils.keyStr.indexOf(input.charAt(i++));
3504 enc3 = DataUtils.keyStr.indexOf(input.charAt(i++));
3505 enc4 = DataUtils.keyStr.indexOf(input.charAt(i++));
3506
3507 chr1 = (enc1 << 2) | (enc2 >> 4);
3508 chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
3509 chr3 = ((enc3 & 3) << 6) | enc4;
3510
3511 output = output + String.fromCharCode(chr1);
3512
3513 if (enc3 != 64) {
3514 output = output + String.fromCharCode(chr2);
3515 }
3516 if (enc4 != 64) {
3517 output = output + String.fromCharCode(chr3);
3518 }
3519
3520 chr1 = chr2 = chr3 = "";
3521 enc1 = enc2 = enc3 = enc4 = "";
3522
3523 } while (i < input.length);
3524
3525 return unescape(output);
3526 };
3527
3528//byte []
3529
3530/**
3531 * NOT WORKING!!!!!
3532 *
3533 * Unsiged Long Number to Byte Array
3534 */
3535
3536 /*
3537DataUtils.unsignedLongToByteArray= function( value) {
3538
3539 if(LOG>4)console.log('INPUT IS '+value);
3540
3541 if( 0 == value )
3542 return [0];
3543
3544 if( 0 <= value && value <= 0x00FF ) {
3545 //byte []
3546 var bb = new Array(1);
3547 bb[0] = (value & 0x00FF);
3548 return bb;
3549 }
3550
3551 if(LOG>4) console.log('type of value is '+typeof value);
3552 if(LOG>4) console.log('value is '+value);
3553 //byte []
3554 var out = null;
3555 //int
3556 var offset = -1;
3557 for(var i = 7; i >=0; --i) {
3558 //byte
3559 console.log(i);
3560 console.log('value is '+value);
3561 console.log('(value >> (i * 8)) '+ (value >> (i * 8)) );
3562 console.log(' ((value >> (i * 8)) & 0xFF) '+ ((value >> (i * 8)) & 0xFF) );
3563
3564 var b = ((value >> (i * 8)) & 0xFF) ;
3565
3566 if(LOG>4) console.log('b is '+b);
3567
3568 if( out == null && b != 0 ) {
3569 //out = new byte[i+1];
3570 out = new Array(i+1);
3571 offset = i;
3572 }
3573
3574 if( out != null )
3575 out[ offset - i ] = b;
3576 }
3577 if(LOG>4)console.log('OUTPUT IS ');
3578 if(LOG>4)console.log(out);
3579 return out;
3580}
3581*/
3582
3583/**
3584 * NOT WORKING!!!!!
3585 *
3586 * Unsiged Long Number to Byte Array
3587 *//*
3588DataUtils.byteArrayToUnsignedLong = function(//final byte []
3589 src) {
3590 if(LOG>4) console.log('INPUT IS ');
3591 if(LOG>4) console.log(src);
3592
3593 var value = 0;
3594 for(var i = 0; i < src.length; i++) {
3595 value = value << 8;
3596 // Java will assume the byte is signed, so extend it and trim it.
3597
3598
3599 var b = ((src[i]) & 0xFF );
3600 value |= b;
3601 }
3602
3603 if(LOG>4) console.log('OUTPUT IS ');
3604
3605 if(LOG>4) console.log(value);
3606
3607 return value;
3608 }*/
3609
3610
3611/**
3612 * Hex String to Byte Array
3613 */
3614 //THIS IS NOT WORKING
3615/*
3616DataUtils.HexStringtoByteArray = function(str) {
3617 var byteArray = [];
3618 for (var i = 0; i < str.length; i++)
3619 if (str.charCodeAt(i) <= 0x7F)
3620 byteArray.push(str.charCodeAt(i));
3621 else {
3622 var h = encodeURIComponent(str.charAt(i)).substr(1).split('%');
3623 for (var j = 0; j < h.length; j++)
3624 byteArray.push(parseInt(h[j], 16));
3625 }
3626 return byteArray;
3627};
3628*/
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003629
3630/**
Jeff Thompson17a9da82012-11-12 01:11:01 -08003631 * Uint8Array to Hex String
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003632 */
3633//http://ejohn.org/blog/numbers-hex-and-colors/
3634DataUtils.toHex = function(arguments){
Jeff Thompson17a9da82012-11-12 01:11:01 -08003635 if (LOG>4) console.log('ABOUT TO CONVERT '+ arguments);
3636 //console.log(arguments);
3637 var ret = "";
3638 for ( var i = 0; i < arguments.length; i++ )
3639 ret += (arguments[i] < 16 ? "0" : "") + arguments[i].toString(16);
3640 if (LOG>4) console.log('Converted to: ' + ret);
3641 return ret; //.toUpperCase();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003642}
3643
3644/**
3645 * Raw string to hex string.
3646 */
3647DataUtils.stringToHex = function(arguments){
3648 var ret = "";
3649 for (var i = 0; i < arguments.length; ++i) {
3650 var value = arguments.charCodeAt(i);
3651 ret += (value < 16 ? "0" : "") + value.toString(16);
3652 }
3653 return ret;
3654}
3655
3656/**
Jeff Thompson17a9da82012-11-12 01:11:01 -08003657 * Uint8Array to raw string.
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003658 */
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003659DataUtils.toString = function(arguments){
3660 //console.log(arguments);
3661 var ret = "";
3662 for ( var i = 0; i < arguments.length; i++ )
3663 ret += String.fromCharCode(arguments[i]);
3664 return ret;
3665}
3666
3667/**
Jeff Thompson17a9da82012-11-12 01:11:01 -08003668 * Hex String to Uint8Array.
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003669 */
Jeff Thompson17a9da82012-11-12 01:11:01 -08003670DataUtils.toNumbers = function(str) {
3671 if (typeof str == 'string') {
3672 var ret = new Uint8Array(Math.floor(str.length / 2));
3673 var i = 0;
3674 str.replace(/(..)/g, function(str) {
3675 ret[i++] = parseInt(str, 16);
3676 });
3677 return ret;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003678 }
3679}
3680
3681/**
3682 * Hex String to raw string.
3683 */
3684DataUtils.hexToRawString = function(str) {
3685 if(typeof str =='string') {
3686 var ret = "";
3687 str.replace(/(..)/g, function(s) {
3688 ret += String.fromCharCode(parseInt(s, 16));
3689 });
3690 return ret;
3691 }
3692}
3693
3694/**
Jeff Thompson17a9da82012-11-12 01:11:01 -08003695 * Raw String to Uint8Array.
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003696 */
3697DataUtils.toNumbersFromString = function( str ){
Jeff Thompson17a9da82012-11-12 01:11:01 -08003698 var bytes = new Uint8Array(str.length);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003699 for(var i=0;i<str.length;i++)
3700 bytes[i] = str.charCodeAt(i);
3701 return bytes;
3702}
3703
Jeff Thompson17a9da82012-11-12 01:11:01 -08003704/*
Jeff Thompson754652d2012-11-24 16:23:43 -08003705 * Encode str as utf8 and return as Uint8Array.
3706 * TODO: Use TextEncoder when available.
3707 */
3708DataUtils.stringToUtf8Array = function(str) {
3709 return DataUtils.toNumbersFromString(str2rstr_utf8(str));
3710}
3711
3712/*
Jeff Thompson17a9da82012-11-12 01:11:01 -08003713 * Return a new Uint8Array which is the Uint8Array concatenated with raw String str.
3714 */
3715DataUtils.concatFromString = function(array, str) {
3716 var bytes = new Uint8Array(array.length + str.length);
3717 bytes.set(array);
3718 for (var i = 0; i < str.length; ++i)
3719 bytes[array.length + i] = str.charCodeAt(i);
3720 return bytes;
3721}
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003722
Jeff Thompson754652d2012-11-24 16:23:43 -08003723// TODO: Take Uint8Array and use TextDecoder when available.
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003724DataUtils.decodeUtf8 = function (utftext) {
3725 var string = "";
3726 var i = 0;
Jeff Thompson10de4592012-10-21 23:54:18 -07003727 var c = 0;
3728 var c1 = 0;
3729 var c2 = 0;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003730
3731 while ( i < utftext.length ) {
3732
3733 c = utftext.charCodeAt(i);
3734
3735 if (c < 128) {
3736 string += String.fromCharCode(c);
3737 i++;
3738 }
3739 else if((c > 191) && (c < 224)) {
3740 c2 = utftext.charCodeAt(i+1);
3741 string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
3742 i += 2;
3743 }
3744 else {
3745 c2 = utftext.charCodeAt(i+1);
Jeff Thompson10de4592012-10-21 23:54:18 -07003746 var c3 = utftext.charCodeAt(i+2);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003747 string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
3748 i += 3;
3749 }
3750
3751 }
3752
3753 return string;
3754 };
3755
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07003756//NOT WORKING
3757/*
3758DataUtils.getUTF8StringFromBytes = function(bytes) {
3759
3760 bytes = toString(bytes);
3761
3762 var ix = 0;
3763
3764 if( bytes.slice(0,3) == "\xEF\xBB\xBF") {
3765 ix = 3;
3766 }
3767
3768 var string = "";
3769 for( ; ix < bytes.length; ix++ ) {
3770 var byte1 = bytes[ix].charCodeAt(0);
3771 if( byte1 < 0x80 ) {
3772 string += String.fromCharCode(byte1);
3773 } else if( byte1 >= 0xC2 && byte1 < 0xE0 ) {
3774 var byte2 = bytes[++ix].charCodeAt(0);
3775 string += String.fromCharCode(((byte1&0x1F)<<6) + (byte2&0x3F));
3776 } else if( byte1 >= 0xE0 && byte1 < 0xF0 ) {
3777 var byte2 = bytes[++ix].charCodeAt(0);
3778 var byte3 = bytes[++ix].charCodeAt(0);
3779 string += String.fromCharCode(((byte1&0xFF)<<12) + ((byte2&0x3F)<<6) + (byte3&0x3F));
3780 } else if( byte1 >= 0xF0 && byte1 < 0xF5) {
3781 var byte2 = bytes[++ix].charCodeAt(0);
3782 var byte3 = bytes[++ix].charCodeAt(0);
3783 var byte4 = bytes[++ix].charCodeAt(0);
3784 var codepoint = ((byte1&0x07)<<18) + ((byte2&0x3F)<<12)+ ((byte3&0x3F)<<6) + (byte4&0x3F);
3785 codepoint -= 0x10000;
3786 string += String.fromCharCode(
3787 (codepoint>>10) + 0xD800,
3788 (codepoint&0x3FF) + 0xDC00
3789 );
3790 }
3791 }
3792
3793 return string;
3794}*/
3795
3796/**
3797 * Return true if a1 and a2 are the same length with equal elements.
3798 */
3799DataUtils.arraysEqual = function(a1, a2){
3800 if (a1.length != a2.length)
3801 return false;
3802
3803 for (var i = 0; i < a1.length; ++i) {
3804 if (a1[i] != a2[i])
3805 return false;
3806 }
3807
3808 return true;
Jeff Thompson10de4592012-10-21 23:54:18 -07003809};
3810
3811/*
Jeff Thompson17a9da82012-11-12 01:11:01 -08003812 * Convert the big endian Uint8Array to an unsigned int.
Jeff Thompson10de4592012-10-21 23:54:18 -07003813 * Don't check for overflow.
3814 */
3815DataUtils.bigEndianToUnsignedInt = function(bytes) {
3816 var result = 0;
3817 for (var i = 0; i < bytes.length; ++i) {
3818 result <<= 8;
3819 result += bytes[i];
3820 }
3821 return result;
3822};
3823
3824/*
Jeff Thompson17a9da82012-11-12 01:11:01 -08003825 * Convert the int value to a new big endian Uint8Array and return.
3826 * If value is 0 or negative, return Uint8Array(0).
Jeff Thompson10de4592012-10-21 23:54:18 -07003827 */
3828DataUtils.nonNegativeIntToBigEndian = function(value) {
Jeff Thompson754652d2012-11-24 16:23:43 -08003829 value = Math.round(value);
Jeff Thompson10de4592012-10-21 23:54:18 -07003830 if (value <= 0)
Jeff Thompson17a9da82012-11-12 01:11:01 -08003831 return new Uint8Array(0);
Jeff Thompson10de4592012-10-21 23:54:18 -07003832
Jeff Thompson17a9da82012-11-12 01:11:01 -08003833 // Assume value is not over 64 bits.
Jeff Thompson754652d2012-11-24 16:23:43 -08003834 var size = 8;
3835 var result = new Uint8Array(size);
Jeff Thompson17a9da82012-11-12 01:11:01 -08003836 var i = 0;
Jeff Thompson10de4592012-10-21 23:54:18 -07003837 while (value != 0) {
Jeff Thompson754652d2012-11-24 16:23:43 -08003838 ++i;
3839 result[size - i] = value & 0xff;
Jeff Thompson10de4592012-10-21 23:54:18 -07003840 value >>= 8;
3841 }
Jeff Thompson754652d2012-11-24 16:23:43 -08003842 return result.subarray(size - i, size);
Jeff Thompson10de4592012-10-21 23:54:18 -07003843};
3844
Jeff Thompson754652d2012-11-24 16:23:43 -08003845/*
3846 * This class defines MOME types based on the filename extension.
3847 * author: Jeff Thompson
3848 * See COPYING for copyright and distribution information.
3849 */
3850
Jeff Thompsone769c512012-11-04 17:25:07 -08003851var MimeTypes = {
3852 /*
3853 * Based on filename, return an object with properties contentType and charset.
3854 */
3855 getContentTypeAndCharset: function(filename) {
3856 var iDot = filename.lastIndexOf('.');
3857 if (iDot >= 0) {
3858 var extension = filename.substr(iDot + 1, filename.length - iDot - 1);
3859 var contentType = MimeTypes[extension];
3860 if (contentType != null) {
3861 var charset = "ISO-8859-1";
3862 if (contentType.split('/')[0] == "text")
3863 charset = "utf-8";
3864 return { contentType: contentType, charset: charset };
3865 }
3866 }
3867
3868 // Use a default.
3869 return { contentType: "text/html", charset: "utf-8" };
3870 },
3871
3872 /* For each file extension, define the MIME type.
3873 */
3874 "323": "text/h323",
3875 "%": "application/x-trash",
3876 "~": "application/x-trash",
3877 "3gp": "video/3gpp",
3878 "7z": "application/x-7z-compressed",
3879 "abw": "application/x-abiword",
3880 "ai": "application/postscript",
3881 "aif": "audio/x-aiff",
3882 "aifc": "audio/x-aiff",
3883 "aiff": "audio/x-aiff",
3884 "alc": "chemical/x-alchemy",
3885 "amr": "audio/amr",
3886 "anx": "application/annodex",
3887 "apk": "application/vnd.android.package-archive",
3888 "art": "image/x-jg",
3889 "asc": "text/plain",
3890 "asf": "video/x-ms-asf",
3891 "asx": "video/x-ms-asf",
3892 "asn": "chemical/x-ncbi-asn1",
3893 "atom": "application/atom+xml",
3894 "atomcat": "application/atomcat+xml",
3895 "atomsrv": "application/atomserv+xml",
3896 "au": "audio/basic",
3897 "snd": "audio/basic",
3898 "avi": "video/x-msvideo",
3899 "awb": "audio/amr-wb",
3900 "axa": "audio/annodex",
3901 "axv": "video/annodex",
3902 "b": "chemical/x-molconn-Z",
3903 "bak": "application/x-trash",
3904 "bat": "application/x-msdos-program",
3905 "bcpio": "application/x-bcpio",
3906 "bib": "text/x-bibtex",
3907 "bin": "application/octet-stream",
3908 "bmp": "image/x-ms-bmp",
3909 "boo": "text/x-boo",
3910 "book": "application/x-maker",
3911 "brf": "text/plain",
3912 "bsd": "chemical/x-crossfire",
3913 "c": "text/x-csrc",
3914 "c++": "text/x-c++src",
3915 "c3d": "chemical/x-chem3d",
3916 "cab": "application/x-cab",
3917 "cac": "chemical/x-cache",
3918 "cache": "chemical/x-cache",
3919 "cap": "application/cap",
3920 "cascii": "chemical/x-cactvs-binary",
3921 "cat": "application/vnd.ms-pki.seccat",
3922 "cbin": "chemical/x-cactvs-binary",
3923 "cbr": "application/x-cbr",
3924 "cbz": "application/x-cbz",
3925 "cc": "text/x-c++src",
3926 "cda": "application/x-cdf",
3927 "cdf": "application/x-cdf",
3928 "cdr": "image/x-coreldraw",
3929 "cdt": "image/x-coreldrawtemplate",
3930 "cdx": "chemical/x-cdx",
3931 "cdy": "application/vnd.cinderella",
3932 "cer": "chemical/x-cerius",
3933 "chm": "chemical/x-chemdraw",
3934 "chrt": "application/x-kchart",
3935 "cif": "chemical/x-cif",
3936 "class": "application/java-vm",
3937 "cls": "text/x-tex",
3938 "cmdf": "chemical/x-cmdf",
3939 "cml": "chemical/x-cml",
3940 "cod": "application/vnd.rim.cod",
3941 "com": "application/x-msdos-program",
3942 "cpa": "chemical/x-compass",
3943 "cpio": "application/x-cpio",
3944 "cpp": "text/x-c++src",
3945 "cpt": "image/x-corelphotopaint",
3946 "cr2": "image/x-canon-cr2",
3947 "crl": "application/x-pkcs7-crl",
3948 "crt": "application/x-x509-ca-cert",
3949 "crw": "image/x-canon-crw",
3950 "csd": "audio/csound",
3951 "csf": "chemical/x-cache-csf",
3952 "csh": "application/x-csh",
3953 "csml": "chemical/x-csml",
3954 "csm": "chemical/x-csml",
3955 "css": "text/css",
3956 "csv": "text/csv",
3957 "ctab": "chemical/x-cactvs-binary",
3958 "ctx": "chemical/x-ctx",
3959 "cu": "application/cu-seeme",
3960 "cub": "chemical/x-gaussian-cube",
3961 "cxf": "chemical/x-cxf",
3962 "cef": "chemical/x-cxf",
3963 "cxx": "text/x-c++src",
3964 "d": "text/x-dsrc",
3965 "dat": "application/x-ns-proxy-autoconfig",
3966 "davmount": "application/davmount+xml",
3967 "dcr": "application/x-director",
3968 "deb": "application/x-debian-package",
3969 "dif": "video/dv",
3970 "dv": "video/dv",
3971 "diff": "text/x-diff",
3972 "patch": "text/x-diff",
3973 "dir": "application/x-director",
3974 "djvu": "image/vnd.djvu",
3975 "djv": "image/vnd.djvu",
3976 "dl": "video/dl",
3977 "dll": "application/x-msdos-program",
3978 "dmg": "application/x-apple-diskimage",
3979 "dms": "application/x-dms",
3980 "doc": "application/msword",
3981 "docm": "application/vnd.ms-word.document.macroEnabled.12",
3982 "docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
3983 "dot": "application/msword",
3984 "dotm": "application/vnd.ms-word.template.macroEnabled.12",
3985 "dotx": "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
3986 "dvi": "application/x-dvi",
3987 "dxr": "application/x-director",
3988 "emb": "chemical/x-embl-dl-nucleotide",
3989 "embl": "chemical/x-embl-dl-nucleotide",
3990 "eml": "message/rfc822",
3991 "eps": "application/postscript",
3992 "eps2": "application/postscript",
3993 "eps3": "application/postscript",
3994 "epsf": "application/postscript",
3995 "epsi": "application/postscript",
3996 "erf": "image/x-epson-erf",
3997 "es": "application/ecmascript",
3998 "etx": "text/x-setext",
3999 "exe": "application/x-msdos-program",
4000 "ez": "application/andrew-inset",
4001 "fb": "application/x-maker",
4002 "fbdoc": "application/x-maker",
4003 "fch": "chemical/x-gaussian-checkpoint",
4004 "fchk": "chemical/x-gaussian-checkpoint",
4005 "fig": "application/x-xfig",
4006 "flac": "audio/flac",
4007 "fli": "video/fli",
4008 "flv": "video/x-flv",
4009 "fm": "application/x-maker",
4010 "frame": "application/x-maker",
4011 "frm": "application/x-maker",
4012 "gal": "chemical/x-gaussian-log",
4013 "gam": "chemical/x-gamess-input",
4014 "gamin": "chemical/x-gamess-input",
4015 "gan": "application/x-ganttproject",
4016 "gau": "chemical/x-gaussian-input",
4017 "gcd": "text/x-pcs-gcd",
4018 "gcf": "application/x-graphing-calculator",
4019 "gcg": "chemical/x-gcg8-sequence",
4020 "gen": "chemical/x-genbank",
4021 "gf": "application/x-tex-gf",
4022 "gif": "image/gif",
4023 "gjc": "chemical/x-gaussian-input",
4024 "gjf": "chemical/x-gaussian-input",
4025 "gl": "video/gl",
4026 "gnumeric": "application/x-gnumeric",
4027 "gpt": "chemical/x-mopac-graph",
4028 "gsf": "application/x-font",
4029 "gsm": "audio/x-gsm",
4030 "gtar": "application/x-gtar",
4031 "h": "text/x-chdr",
4032 "h++": "text/x-c++hdr",
4033 "hdf": "application/x-hdf",
4034 "hh": "text/x-c++hdr",
4035 "hin": "chemical/x-hin",
4036 "hpp": "text/x-c++hdr",
4037 "hqx": "application/mac-binhex40",
4038 "hs": "text/x-haskell",
4039 "hta": "application/hta",
4040 "htc": "text/x-component",
4041 "htm": "text/html",
4042 "html": "text/html",
4043 "hxx": "text/x-c++hdr",
4044 "ica": "application/x-ica",
4045 "ice": "x-conference/x-cooltalk",
4046 "ico": "image/x-icon",
4047 "ics": "text/calendar",
4048 "icz": "text/calendar",
4049 "ief": "image/ief",
4050 "igs": "model/iges",
4051 "iges": "model/iges",
4052 "iii": "application/x-iphone",
4053 "info": "application/x-info",
4054 "inp": "chemical/x-gamess-input",
4055 "ins": "application/x-internet-signup",
4056 "iso": "application/x-iso9660-image",
4057 "isp": "application/x-internet-signup",
4058 "istr": "chemical/x-isostar",
4059 "ist": "chemical/x-isostar",
4060 "jad": "text/vnd.sun.j2me.app-descriptor",
4061 "jam": "application/x-jam",
4062 "jar": "application/java-archive",
4063 "java": "text/x-java",
4064 "jdx": "chemical/x-jcamp-dx",
4065 "dx": "chemical/x-jcamp-dx",
4066 "jmz": "application/x-jmol",
4067 "jng": "image/x-jng",
4068 "jnlp": "application/x-java-jnlp-file",
4069 "jpe": "image/jpeg",
4070 "jpeg": "image/jpeg",
4071 "jpg": "image/jpeg",
4072 "js": "application/javascript",
4073 "json": "application/json",
4074 "kar": "audio/midi",
4075 "key": "application/pgp-keys",
4076 "kil": "application/x-killustrator",
4077 "kin": "chemical/x-kinemage",
4078 "kml": "application/vnd.google-earth.kml+xml",
4079 "kmz": "application/vnd.google-earth.kmz",
4080 "kpr": "application/x-kpresenter",
4081 "kpt": "application/x-kpresenter",
4082 "ksp": "application/x-kspread",
4083 "kwd": "application/x-kword",
4084 "kwt": "application/x-kword",
4085 "latex": "application/x-latex",
4086 "lha": "application/x-lha",
4087 "lhs": "text/x-literate-haskell",
4088 "lin": "application/bbolin",
4089 "lsf": "video/x-la-asf",
4090 "lsx": "video/x-la-asf",
4091 "ltx": "text/x-tex",
4092 "lyx": "application/x-lyx",
4093 "lzh": "application/x-lzh",
4094 "lzx": "application/x-lzx",
4095 "m3g": "application/m3g",
4096 "m3u": "audio/mpegurl",
4097 "m3u8": "application/x-mpegURL",
4098 "m4a": "audio/mpeg",
4099 "maker": "application/x-maker",
4100 "man": "application/x-troff-man",
4101 "manifest": "text/cache-manifest",
4102 "mcif": "chemical/x-mmcif",
4103 "mcm": "chemical/x-macmolecule",
4104 "mdb": "application/msaccess",
4105 "me": "application/x-troff-me",
4106 "mesh": "model/mesh",
4107 "mid": "audio/midi",
4108 "midi": "audio/midi",
4109 "mif": "application/x-mif",
4110 "mm": "application/x-freemind",
4111 "mmd": "chemical/x-macromodel-input",
4112 "mmod": "chemical/x-macromodel-input",
4113 "mmf": "application/vnd.smaf",
4114 "mml": "text/mathml",
4115 "mng": "video/x-mng",
4116 "moc": "text/x-moc",
4117 "mol": "chemical/x-mdl-molfile",
4118 "mol2": "chemical/x-mol2",
4119 "moo": "chemical/x-mopac-out",
4120 "mop": "chemical/x-mopac-input",
4121 "mopcrt": "chemical/x-mopac-input",
4122 "movie": "video/x-sgi-movie",
4123 "mp2": "audio/mpeg",
4124 "mp3": "audio/mpeg",
4125 "mp4": "video/mp4",
4126 "mpc": "chemical/x-mopac-input",
4127 "mpe": "video/mpeg",
4128 "mpeg": "video/mpeg",
4129 "mpega": "audio/mpeg",
4130 "mpg": "video/mpeg",
4131 "mpga": "audio/mpeg",
4132 "mph": "application/x-comsol",
4133 "mpv": "video/x-matroska",
4134 "mkv": "video/x-matroska",
4135 "ms": "application/x-troff-ms",
4136 "msh": "model/mesh",
4137 "msi": "application/x-msi",
4138 "mvb": "chemical/x-mopac-vib",
4139 "mxf": "application/mxf",
4140 "mxu": "video/vnd.mpegurl",
4141 "nb": "application/mathematica",
4142 "nbp": "application/mathematica",
4143 "nc": "application/x-netcdf",
4144 "nef": "image/x-nikon-nef",
4145 "nwc": "application/x-nwc",
4146 "o": "application/x-object",
4147 "oda": "application/oda",
4148 "odb": "application/vnd.oasis.opendocument.database",
4149 "odc": "application/vnd.oasis.opendocument.chart",
4150 "odf": "application/vnd.oasis.opendocument.formula",
4151 "odg": "application/vnd.oasis.opendocument.graphics",
4152 "odi": "application/vnd.oasis.opendocument.image",
4153 "odm": "application/vnd.oasis.opendocument.text-master",
4154 "odp": "application/vnd.oasis.opendocument.presentation",
4155 "ods": "application/vnd.oasis.opendocument.spreadsheet",
4156 "odt": "application/vnd.oasis.opendocument.text",
4157 "oga": "audio/ogg",
4158 "ogg": "audio/ogg",
4159 "ogv": "video/ogg",
4160 "ogx": "application/ogg",
4161 "old": "application/x-trash",
4162 "one": "application/onenote",
4163 "onepkg": "application/onenote",
4164 "onetmp": "application/onenote",
4165 "onetoc2": "application/onenote",
4166 "orc": "audio/csound",
4167 "orf": "image/x-olympus-orf",
4168 "otg": "application/vnd.oasis.opendocument.graphics-template",
4169 "oth": "application/vnd.oasis.opendocument.text-web",
4170 "otp": "application/vnd.oasis.opendocument.presentation-template",
4171 "ots": "application/vnd.oasis.opendocument.spreadsheet-template",
4172 "ott": "application/vnd.oasis.opendocument.text-template",
4173 "oza": "application/x-oz-application",
4174 "p": "text/x-pascal",
4175 "pas": "text/x-pascal",
4176 "p7r": "application/x-pkcs7-certreqresp",
4177 "pac": "application/x-ns-proxy-autoconfig",
4178 "pat": "image/x-coreldrawpattern",
4179 "pbm": "image/x-portable-bitmap",
4180 "pcap": "application/cap",
4181 "pcf": "application/x-font",
4182 "pcx": "image/pcx",
4183 "pdb": "chemical/x-pdb",
4184 "ent": "chemical/x-pdb",
4185 "pdf": "application/pdf",
4186 "pfa": "application/x-font",
4187 "pfb": "application/x-font",
4188 "pgm": "image/x-portable-graymap",
4189 "pgn": "application/x-chess-pgn",
4190 "pgp": "application/pgp-signature",
4191 "php": "application/x-httpd-php",
4192 "php3": "application/x-httpd-php3",
4193 "php3p": "application/x-httpd-php3-preprocessed",
4194 "php4": "application/x-httpd-php4",
4195 "php5": "application/x-httpd-php5",
4196 "phps": "application/x-httpd-php-source",
4197 "pht": "application/x-httpd-php",
4198 "phtml": "application/x-httpd-php",
4199 "pk": "application/x-tex-pk",
4200 "pl": "text/x-perl",
4201 "pm": "text/x-perl",
4202 "pls": "audio/x-scpls",
4203 "png": "image/png",
4204 "pnm": "image/x-portable-anymap",
4205 "pot": "text/plain",
4206 "potm": "application/vnd.ms-powerpoint.template.macroEnabled.12",
4207 "potx": "application/vnd.openxmlformats-officedocument.presentationml.template",
4208 "ppam": "application/vnd.ms-powerpoint.addin.macroEnabled.12",
4209 "ppm": "image/x-portable-pixmap",
4210 "pps": "application/vnd.ms-powerpoint",
4211 "ppsm": "application/vnd.ms-powerpoint.slideshow.macroEnabled.12",
4212 "ppsx": "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
4213 "ppt": "application/vnd.ms-powerpoint",
4214 "pptm": "application/vnd.ms-powerpoint.presentation.macroEnabled.12",
4215 "pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
4216 "prf": "application/pics-rules",
4217 "prt": "chemical/x-ncbi-asn1-ascii",
4218 "ps": "application/postscript",
4219 "psd": "image/x-photoshop",
4220 "py": "text/x-python",
4221 "pyc": "application/x-python-code",
4222 "pyo": "application/x-python-code",
4223 "qgs": "application/x-qgis",
4224 "qt": "video/quicktime",
4225 "mov": "video/quicktime",
4226 "qtl": "application/x-quicktimeplayer",
4227 "ra": "audio/x-realaudio",
4228 "ram": "audio/x-pn-realaudio",
4229 "rar": "application/rar",
4230 "ras": "image/x-cmu-raster",
4231 "rb": "application/x-ruby",
4232 "rd": "chemical/x-mdl-rdfile",
4233 "rdf": "application/rdf+xml",
4234 "rdp": "application/x-rdp",
4235 "rgb": "image/x-rgb",
4236 "rhtml": "application/x-httpd-eruby",
4237 "rm": "audio/x-pn-realaudio",
4238 "roff": "application/x-troff",
4239 "ros": "chemical/x-rosdal",
4240 "rpm": "application/x-redhat-package-manager",
4241 "rss": "application/rss+xml",
4242 "rtf": "application/rtf",
4243 "rtx": "text/richtext",
4244 "rxn": "chemical/x-mdl-rxnfile",
4245 "scala": "text/x-scala",
4246 "sci": "application/x-scilab",
4247 "sce": "application/x-scilab",
4248 "sco": "audio/csound",
4249 "scr": "application/x-silverlight",
4250 "sct": "text/scriptlet",
4251 "wsc": "text/scriptlet",
4252 "sd": "chemical/x-mdl-sdfile",
4253 "sdf": "chemical/x-mdl-sdfile",
4254 "sd2": "audio/x-sd2",
4255 "sda": "application/vnd.stardivision.draw",
4256 "sdc": "application/vnd.stardivision.calc",
4257 "sdd": "application/vnd.stardivision.impress",
4258 "sds": "application/vnd.stardivision.chart",
4259 "sdw": "application/vnd.stardivision.writer",
4260 "ser": "application/java-serialized-object",
4261 "sfv": "text/x-sfv",
4262 "sgf": "application/x-go-sgf",
4263 "sgl": "application/vnd.stardivision.writer-global",
4264 "sh": "application/x-sh",
4265 "shar": "application/x-shar",
4266 "shp": "application/x-qgis",
4267 "shtml": "text/html",
4268 "shx": "application/x-qgis",
4269 "sid": "audio/prs.sid",
4270 "sik": "application/x-trash",
4271 "silo": "model/mesh",
4272 "sis": "application/vnd.symbian.install",
4273 "sisx": "x-epoc/x-sisx-app",
4274 "sit": "application/x-stuffit",
4275 "sitx": "application/x-stuffit",
4276 "skd": "application/x-koan",
4277 "skm": "application/x-koan",
4278 "skp": "application/x-koan",
4279 "skt": "application/x-koan",
4280 "sldm": "application/vnd.ms-powerpoint.slide.macroEnabled.12",
4281 "sldx": "application/vnd.openxmlformats-officedocument.presentationml.slide",
4282 "smi": "application/smil",
4283 "smil": "application/smil",
4284 "spc": "chemical/x-galactic-spc",
4285 "spl": "application/futuresplash",
4286 "spx": "audio/ogg",
4287 "sql": "application/x-sql",
4288 "src": "application/x-wais-source",
4289 "stc": "application/vnd.sun.xml.calc.template",
4290 "std": "application/vnd.sun.xml.draw.template",
4291 "sti": "application/vnd.sun.xml.impress.template",
4292 "stl": "application/sla",
4293 "stw": "application/vnd.sun.xml.writer.template",
4294 "sty": "text/x-tex",
4295 "sv4cpio": "application/x-sv4cpio",
4296 "sv4crc": "application/x-sv4crc",
4297 "svg": "image/svg+xml",
4298 "svgz": "image/svg+xml",
4299 "sw": "chemical/x-swissprot",
4300 "swf": "application/x-shockwave-flash",
4301 "swfl": "application/x-shockwave-flash",
4302 "sxc": "application/vnd.sun.xml.calc",
4303 "sxd": "application/vnd.sun.xml.draw",
4304 "sxg": "application/vnd.sun.xml.writer.global",
4305 "sxi": "application/vnd.sun.xml.impress",
4306 "sxm": "application/vnd.sun.xml.math",
4307 "sxw": "application/vnd.sun.xml.writer",
4308 "t": "application/x-troff",
4309 "tar": "application/x-tar",
4310 "taz": "application/x-gtar-compressed",
4311 "tcl": "application/x-tcl",
4312 "tk": "text/x-tcl",
4313 "tex": "text/x-tex",
4314 "texinfo": "application/x-texinfo",
4315 "texi": "application/x-texinfo",
4316 "text": "text/plain",
4317 "tgf": "chemical/x-mdl-tgf",
4318 "tgz": "application/x-gtar-compressed",
4319 "thmx": "application/vnd.ms-officetheme",
4320 "tiff": "image/tiff",
4321 "tif": "image/tiff",
4322 "tm": "text/texmacs",
4323 "torrent": "application/x-bittorrent",
4324 "tr": "application/x-troff",
4325 "ts": "video/MP2T",
4326 "tsp": "application/dsptype",
4327 "tsv": "text/tab-separated-values",
4328 "txt": "text/plain",
4329 "udeb": "application/x-debian-package",
4330 "uls": "text/iuls",
4331 "ustar": "application/x-ustar",
4332 "val": "chemical/x-ncbi-asn1-binary",
4333 "aso": "chemical/x-ncbi-asn1-binary",
4334 "vcd": "application/x-cdlink",
4335 "vcf": "text/x-vcard",
4336 "vcs": "text/x-vcalendar",
4337 "vmd": "chemical/x-vmd",
4338 "vms": "chemical/x-vamas-iso14976",
4339 "vrm": "x-world/x-vrml",
4340 "vsd": "application/vnd.visio",
4341 "wad": "application/x-doom",
4342 "wav": "audio/x-wav",
4343 "wax": "audio/x-ms-wax",
4344 "wbmp": "image/vnd.wap.wbmp",
4345 "wbxml": "application/vnd.wap.wbxml",
4346 "webm": "video/webm",
4347 "wk": "application/x-123",
4348 "wm": "video/x-ms-wm",
4349 "wma": "audio/x-ms-wma",
4350 "wmd": "application/x-ms-wmd",
4351 "wml": "text/vnd.wap.wml",
4352 "wmlc": "application/vnd.wap.wmlc",
4353 "wmls": "text/vnd.wap.wmlscript",
4354 "wmlsc": "application/vnd.wap.wmlscriptc",
4355 "wmv": "video/x-ms-wmv",
4356 "wmx": "video/x-ms-wmx",
4357 "wmz": "application/x-ms-wmz",
4358 "wp5": "application/vnd.wordperfect5.1",
4359 "wpd": "application/vnd.wordperfect",
4360 "wrl": "model/vrml",
4361 "vrml": "model/vrml",
4362 "wvx": "video/x-ms-wvx",
4363 "wz": "application/x-wingz",
4364 "x3d": "model/x3d+xml",
4365 "x3db": "model/x3d+binary",
4366 "x3dv": "model/x3d+vrml",
4367 "xbm": "image/x-xbitmap",
4368 "xcf": "application/x-xcf",
4369 "xht": "application/xhtml+xml",
4370 "xhtml": "application/xhtml+xml",
4371 "xlam": "application/vnd.ms-excel.addin.macroEnabled.12",
4372 "xlb": "application/vnd.ms-excel",
4373 "xls": "application/vnd.ms-excel",
4374 "xlsb": "application/vnd.ms-excel.sheet.binary.macroEnabled.12",
4375 "xlsm": "application/vnd.ms-excel.sheet.macroEnabled.12",
4376 "xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
4377 "xlt": "application/vnd.ms-excel",
4378 "xltm": "application/vnd.ms-excel.template.macroEnabled.12",
4379 "xltx": "application/vnd.openxmlformats-officedocument.spreadsheetml.template",
4380 "xml": "application/xml",
4381 "xpi": "application/x-xpinstall",
4382 "xpm": "image/x-xpixmap",
4383 "xsd": "application/xml",
4384 "xsl": "application/xml",
4385 "xspf": "application/xspf+xml",
4386 "xtel": "chemical/x-xtel",
4387 "xul": "application/vnd.mozilla.xul+xml",
4388 "xwd": "image/x-xwindowdump",
4389 "xyz": "chemical/x-xyz",
4390 "zip": "application/zip",
4391 "zmt": "chemical/x-mopac-input"
4392};
4393
Jeff Thompson745026e2012-10-13 12:49:20 -07004394/*
4395 * This file contains utilities to help encode and decode NDN objects.
Jeff Thompson754652d2012-11-24 16:23:43 -08004396 * author: Meki Cheraoui
Jeff Thompson745026e2012-10-13 12:49:20 -07004397 * See COPYING for copyright and distribution information.
4398 */
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07004399
4400function encodeToHexInterest(interest){
Jeff Thompson754652d2012-11-24 16:23:43 -08004401 return DataUtils.toHex(encodeToBinaryInterest(interest));
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07004402}
4403
4404
Jeff Thompson754652d2012-11-24 16:23:43 -08004405function encodeToBinaryInterest(interest) {
Jeff Thompson17a9da82012-11-12 01:11:01 -08004406 var enc = new BinaryXMLEncoder();
Jeff Thompson17a9da82012-11-12 01:11:01 -08004407 interest.to_ccnb(enc);
4408
Jeff Thompson754652d2012-11-24 16:23:43 -08004409 return enc.getReducedOstream();
Jeff Thompson17a9da82012-11-12 01:11:01 -08004410}
4411
4412
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07004413function encodeToHexContentObject(co){
Jeff Thompson754652d2012-11-24 16:23:43 -08004414 return DataUtils.toHex(encodeToBinaryContentObject(co));
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07004415}
4416
4417function encodeToBinaryContentObject(co){
4418 var enc = new BinaryXMLEncoder();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07004419 co.to_ccnb(enc);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07004420
Jeff Thompson754652d2012-11-24 16:23:43 -08004421 return enc.getReducedOstream();
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07004422}
4423
4424function encodeForwardingEntry(co){
4425 var enc = new BinaryXMLEncoder();
4426
4427 co.to_ccnb(enc);
4428
4429 var bytes = enc.getReducedOstream();
4430
4431 return bytes;
4432
4433
4434}
4435
4436
4437
4438function decodeHexFaceInstance(result){
4439
4440 var numbers = DataUtils.toNumbers(result);
4441
4442
4443 decoder = new BinaryXMLDecoder(numbers);
4444
4445 if(LOG>3)console.log('DECODING HEX FACE INSTANCE \n'+numbers);
4446
4447 var faceInstance = new FaceInstance();
4448
4449 faceInstance.from_ccnb(decoder);
4450
4451 return faceInstance;
4452
4453}
4454
Jeff Thompson17a9da82012-11-12 01:11:01 -08004455
4456
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07004457function decodeHexInterest(result){
Jeff Thompson17a9da82012-11-12 01:11:01 -08004458 var numbers = DataUtils.toNumbers(result);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07004459
4460 decoder = new BinaryXMLDecoder(numbers);
Jeff Thompson17a9da82012-11-12 01:11:01 -08004461
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07004462 if(LOG>3)console.log('DECODING HEX INTERST \n'+numbers);
4463
4464 var interest = new Interest();
4465
4466 interest.from_ccnb(decoder);
4467
4468 return interest;
4469
4470}
4471
4472
4473
4474function decodeHexContentObject(result){
4475 var numbers = DataUtils.toNumbers(result);
Jeff Thompson17a9da82012-11-12 01:11:01 -08004476
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07004477 decoder = new BinaryXMLDecoder(numbers);
Jeff Thompson17a9da82012-11-12 01:11:01 -08004478
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07004479 if(LOG>3)console.log('DECODED HEX CONTENT OBJECT \n'+numbers);
4480
4481 co = new ContentObject();
4482
4483 co.from_ccnb(decoder);
4484
4485 return co;
4486
4487}
4488
4489
4490
4491function decodeHexForwardingEntry(result){
4492 var numbers = DataUtils.toNumbers(result);
4493
4494 decoder = new BinaryXMLDecoder(numbers);
4495
4496 if(LOG>3)console.log('DECODED HEX FORWARDING ENTRY \n'+numbers);
4497
4498 forwardingEntry = new ForwardingEntry();
4499
4500 forwardingEntry.from_ccnb(decoder);
4501
4502 return forwardingEntry;
4503
4504}
4505
4506/* Return a user friendly HTML string with the contents of co.
4507 This also outputs to console.log.
4508 */
4509function contentObjectToHtml(/* ContentObject */ co) {
4510 var output ="";
4511
4512 if(co==-1)
4513 output+= "NO CONTENT FOUND"
4514 else if (co==-2)
4515 output+= "CONTENT NAME IS EMPTY"
4516 else{
4517 if(co.name!=null && co.name.components!=null){
Jeff Thompson754652d2012-11-24 16:23:43 -08004518 output+= "NAME: " + co.name.to_uri();
4519
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07004520 output+= "<br />";
4521 output+= "<br />";
4522 }
4523
4524 if(co.content !=null){
4525 output += "CONTENT(ASCII): "+ DataUtils.toString(co.content);
4526
4527 output+= "<br />";
4528 output+= "<br />";
4529 }
4530 if(co.content !=null){
4531 output += "CONTENT(hex): "+ DataUtils.toHex(co.content);
4532
4533 output+= "<br />";
4534 output+= "<br />";
4535 }
4536 if(co.signature !=null && co.signature.signature!=null){
4537 output += "SIGNATURE(hex): "+ DataUtils.toHex(co.signature.signature);
4538
4539 output+= "<br />";
4540 output+= "<br />";
4541 }
4542 if(co.signedInfo !=null && co.signedInfo.publisher!=null && co.signedInfo.publisher.publisherPublicKeyDigest!=null){
4543 output += "Publisher Public Key Digest(hex): "+ DataUtils.toHex(co.signedInfo.publisher.publisherPublicKeyDigest);
4544
4545 output+= "<br />";
4546 output+= "<br />";
4547 }
4548 if(co.signedInfo !=null && co.signedInfo.timestamp!=null){
4549 var d = new Date();
4550 d.setTime( co.signedInfo.timestamp.msec );
4551
4552 var bytes = [217, 185, 12, 225, 217, 185, 12, 225];
4553
4554 output += "TimeStamp: "+d;
4555 output+= "<br />";
4556 output += "TimeStamp(number): "+ co.signedInfo.timestamp.msec;
4557
4558 output+= "<br />";
4559 }
Jeff Thompson34419762012-10-15 22:24:12 -07004560 if(co.signedInfo !=null && co.signedInfo.finalBlockID!=null){
4561 output += "FinalBlockID: "+ DataUtils.toHex(co.signedInfo.finalBlockID);
4562 output+= "<br />";
4563 }
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07004564 if(co.signedInfo!=null && co.signedInfo.locator!=null && co.signedInfo.locator.certificate!=null){
4565 var tmp = DataUtils.toString(co.signedInfo.locator.certificate);
4566 var publickey = rstr2b64(tmp);
4567 var publickeyHex = DataUtils.toHex(co.signedInfo.locator.certificate).toLowerCase();
4568 var publickeyString = DataUtils.toString(co.signedInfo.locator.certificate);
4569 var signature = DataUtils.toHex(co.signature.signature).toLowerCase();
4570 var input = DataUtils.toString(co.rawSignatureData);
4571
4572 output += "DER Certificate: "+publickey ;
4573
4574 output+= "<br />";
4575 output+= "<br />";
4576
4577 if(LOG>2) console.log(" ContentName + SignedInfo + Content = "+input);
4578
4579 if(LOG>2) console.log("HEX OF ContentName + SignedInfo + Content = ");
4580 if(LOG>2) console.log(DataUtils.stringtoBase64(input));
4581
4582 if(LOG>2) console.log(" PublicKey = "+publickey );
4583 if(LOG>2) console.log(" PublicKeyHex = "+publickeyHex );
4584 if(LOG>2) console.log(" PublicKeyString = "+publickeyString );
4585
4586 if(LOG>2) console.log(" Signature is");
4587 if(LOG>2) console.log( signature );
4588 //if(LOG>2) console.log(" Signature NOW IS" );
4589 //if(LOG>2) console.log(co.signature.signature);
4590
4591 var x509 = new X509();
4592 x509.readCertPEM(publickey);
4593
4594 //x509.readCertPEMWithoutRSAInit(publickey);
4595
4596 var result = x509.subjectPublicKeyRSA.verifyByteArray(co.rawSignatureData, signature);
4597 if(LOG>2) console.log('result is '+result);
4598
4599 var n = x509.subjectPublicKeyRSA.n;
4600 var e = x509.subjectPublicKeyRSA.e;
4601
4602 if(LOG>2) console.log('PUBLIC KEY n after is ');
4603 if(LOG>2) console.log(n);
4604
4605 if(LOG>2) console.log('EXPONENT e after is ');
4606 if(LOG>2) console.log(e);
4607
4608 /*var rsakey = new RSAKey();
4609
4610 var kp = publickeyHex.slice(56,314);
4611
4612 output += "PUBLISHER KEY(hex): "+kp ;
4613
4614 output+= "<br />";
4615 output+= "<br />";
4616
4617 console.log('kp is '+kp);
4618
4619 var exp = publickeyHex.slice(318,324);
4620
4621 console.log('kp size is '+kp.length );
4622 output += "exponent: "+exp ;
4623
4624 output+= "<br />";
4625 output+= "<br />";
4626
4627 console.log('exp is '+exp);
4628
4629 rsakey.setPublic(kp,exp);
4630
4631 var result = rsakey.verifyString(input, signature);*/
4632
4633 if(result)
4634 output += 'SIGNATURE VALID';
4635 else
4636 output += 'SIGNATURE INVALID';
4637
4638 //output += "VALID: "+ toHex(co.signedInfo.locator.publicKey);
4639
4640 output+= "<br />";
4641 output+= "<br />";
4642
4643 //if(LOG>4) console.log('str'[1]);
4644 }
4645 if(co.signedInfo!=null && co.signedInfo.locator!=null && co.signedInfo.locator.publicKey!=null){
4646 var publickey = rstr2b64(DataUtils.toString(co.signedInfo.locator.publicKey));
4647 var publickeyHex = DataUtils.toHex(co.signedInfo.locator.publicKey).toLowerCase();
4648 var publickeyString = DataUtils.toString(co.signedInfo.locator.publicKey);
4649 var signature = DataUtils.toHex(co.signature.signature).toLowerCase();
4650 var input = DataUtils.toString(co.rawSignatureData);
4651
4652 output += "DER Certificate: "+publickey ;
4653
4654 output+= "<br />";
4655 output+= "<br />";
4656
4657 if(LOG>2) console.log(" ContentName + SignedInfo + Content = "+input);
4658 if(LOG>2) console.log(" PublicKey = "+publickey );
4659 if(LOG>2) console.log(" PublicKeyHex = "+publickeyHex );
4660 if(LOG>2) console.log(" PublicKeyString = "+publickeyString );
4661
4662 if(LOG>2) console.log(" Signature "+signature );
4663
4664 if(LOG>2) console.log(" Signature NOW IS" );
4665
4666 if(LOG>2) console.log(co.signature.signature);
4667
4668 /*var x509 = new X509();
4669
4670 x509.readCertPEM(publickey);
4671
4672
4673 //x509.readCertPEMWithoutRSAInit(publickey);
4674
4675 var result = x509.subjectPublicKeyRSA.verifyString(input, signature);*/
4676 //console.log('result is '+result);
4677
4678 var kp = publickeyHex.slice(56,314);
4679
4680 output += "PUBLISHER KEY(hex): "+kp ;
4681
4682 output+= "<br />";
4683 output+= "<br />";
4684
4685 console.log('PUBLIC KEY IN HEX is ');
4686 console.log(kp);
4687
4688 var exp = publickeyHex.slice(318,324);
4689
4690 console.log('kp size is '+kp.length );
4691 output += "exponent: "+exp ;
4692
4693 output+= "<br />";
4694 output+= "<br />";
4695
4696 console.log('EXPONENT is ');
4697 console.log(exp);
4698
4699 /*var c1 = hex_sha256(input);
4700 var c2 = signature;
4701
4702 if(LOG>4)console.log('input is ');
4703 if(LOG>4)console.log(input);
4704 if(LOG>4)console.log('C1 is ');
4705 if(LOG>4)console.log(c1);
4706 if(LOG>4)console.log('C2 is ');
4707 if(LOG>4)console.log(c2);
4708 var result = c1 == c2;*/
4709
4710 var rsakey = new RSAKey();
4711
4712 rsakey.setPublic(kp,exp);
4713
4714 var result = rsakey.verifyByteArray(co.rawSignatureData,signature);
4715 // var result = rsakey.verifyString(input, signature);
4716
4717 console.log('PUBLIC KEY n after is ');
4718 console.log(rsakey.n);
4719
4720 console.log('EXPONENT e after is ');
4721 console.log(rsakey.e);
4722
4723 if(result)
4724 output += 'SIGNATURE VALID';
4725 else
4726 output += 'SIGNATURE INVALID';
4727
4728 //output += "VALID: "+ toHex(co.signedInfo.locator.publicKey);
4729
4730 output+= "<br />";
4731 output+= "<br />";
4732
4733 //if(LOG>4) console.log('str'[1]);
4734 }
4735 }
4736
4737 return output;
4738}
4739
Jeff Thompson745026e2012-10-13 12:49:20 -07004740/*
Jeff Thompson754652d2012-11-24 16:23:43 -08004741 * @author: Meki Cheraoui
Jeff Thompson745026e2012-10-13 12:49:20 -07004742 * See COPYING for copyright and distribution information.
4743 */
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07004744
4745var KeyManager = function KeyManager(){
4746
4747
4748//Certificate from CCNx
4749
4750this.certificate = 'MIIBmzCCAQQCCQC32FyQa61S7jANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwd'+
4751
4752'heGVsY2R2MB4XDTEyMDQyODIzNDQzN1oXDTEyMDUyODIzNDQzN1owEjEQMA4GA1'+
4753
4754'UEAxMHYXhlbGNkdjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4X0wp9goq'+
4755
4756'xuECxdULcr2IHr9Ih4Iaypg0Wy39URIup8/CLzQmdsh3RYqd55hqonu5VTTpH3i'+
4757
4758'MLx6xZDVJAZ8OJi7pvXcQ2C4Re2kjL2c8SanI0RfDhlS1zJadfr1VhRPmpivcYa'+
4759
4760'wJ4aFuOLAi+qHFxtN7lhcGCgpW1OV60oXd58CAwEAATANBgkqhkiG9w0BAQUFAA'+
4761
4762'OBgQDLOrA1fXzSrpftUB5Ro6DigX1Bjkf7F5Bkd69hSVp+jYeJFBBlsILQAfSxU'+
4763
4764'ZPQtD+2Yc3iCmSYNyxqu9PcufDRJlnvB7PG29+L3y9lR37tetzUV9eTscJ7rdp8'+
4765
4766'Wt6AzpW32IJ/54yKNfP7S6ZIoIG+LP6EIxq6s8K1MXRt8uBJKw==';
4767
4768
4769//this.publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhfTCn2CirG4QLF1QtyvYgev0iHghrKmDRbLf1REi6nz8IvNCZ2yHdFip3nmGqie7lVNOkfeIwvHrFkNUkBnw4mLum9dxDYLhF7aSMvZzxJqcjRF8OGVLXMlp1+vVWFE+amK9xhrAnhoW44sCL6ocXG03uWFwYKClbU5XrShd3nwIDAQAB';
4770this.publicKey ='30819F300D06092A864886F70D010101050003818D0030818902818100E17D30A7D828AB1B840B17542DCAF6207AFD221E086B2A60D16CB7F54448BA9F3F08BCD099DB21DD162A779E61AA89EEE554D3A47DE230BC7AC590D524067C3898BBA6F5DC4360B845EDA48CBD9CF126A723445F0E1952D7325A75FAF556144F9A98AF7186B0278685B8E2C08BEA87171B4DEE585C1828295B5395EB4A17779F0203010001';
4771//Private Key from CCNx
4772
4773this.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';
4774
4775
4776/*
4777 this.certificate =
4778 'MIIBvTCCASYCCQD55fNzc0WF7TANBgkqhkiG9w0BAQUFADAjMQswCQYDVQQGEwJK'+
4779 'UDEUMBIGA1UEChMLMDAtVEVTVC1SU0EwHhcNMTAwNTI4MDIwODUxWhcNMjAwNTI1'+
4780 'MDIwODUxWjAjMQswCQYDVQQGEwJKUDEUMBIGA1UEChMLMDAtVEVTVC1SU0EwgZ8w'+
4781 'DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANGEYXtfgDRlWUSDn3haY4NVVQiKI9Cz'+
4782 'Thoua9+DxJuiseyzmBBe7Roh1RPqdvmtOHmEPbJ+kXZYhbozzPRbFGHCJyBfCLzQ'+
4783 'fVos9/qUQ88u83b0SFA2MGmQWQAlRtLy66EkR4rDRwTj2DzR4EEXgEKpIvo8VBs/'+
4784 '3+sHLF3ESgAhAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAEZ6mXFFq3AzfaqWHmCy1'+
4785 'ARjlauYAa8ZmUFnLm0emg9dkVBJ63aEqARhtok6bDQDzSJxiLpCEF6G4b/Nv/M/M'+
4786 'LyhP+OoOTmETMegAVQMq71choVJyOFE5BtQa6M/lCHEOya5QUfoRF2HF9EjRF44K'+
4787 '3OK+u3ivTSj3zwjtpudY5Xo=';
4788
4789 this.privateKey =
4790 'MIICWwIBAAKBgQDRhGF7X4A0ZVlEg594WmODVVUIiiPQs04aLmvfg8SborHss5gQ'+
4791 'Xu0aIdUT6nb5rTh5hD2yfpF2WIW6M8z0WxRhwicgXwi80H1aLPf6lEPPLvN29EhQ'+
4792 'NjBpkFkAJUbS8uuhJEeKw0cE49g80eBBF4BCqSL6PFQbP9/rByxdxEoAIQIDAQAB'+
4793 'AoGAA9/q3Zk6ib2GFRpKDLO/O2KMnAfR+b4XJ6zMGeoZ7Lbpi3MW0Nawk9ckVaX0'+
4794 'ZVGqxbSIX5Cvp/yjHHpww+QbUFrw/gCjLiiYjM9E8C3uAF5AKJ0r4GBPl4u8K4bp'+
4795 'bXeSxSB60/wPQFiQAJVcA5xhZVzqNuF3EjuKdHsw+dk+dPECQQDubX/lVGFgD/xY'+
4796 'uchz56Yc7VHX+58BUkNSewSzwJRbcueqknXRWwj97SXqpnYfKqZq78dnEF10SWsr'+
4797 '/NMKi+7XAkEA4PVqDv/OZAbWr4syXZNv/Mpl4r5suzYMMUD9U8B2JIRnrhmGZPzL'+
4798 'x23N9J4hEJ+Xh8tSKVc80jOkrvGlSv+BxwJAaTOtjA3YTV+gU7Hdza53sCnSw/8F'+
4799 'YLrgc6NOJtYhX9xqdevbyn1lkU0zPr8mPYg/F84m6MXixm2iuSz8HZoyzwJARi2p'+
4800 'aYZ5/5B2lwroqnKdZBJMGKFpUDn7Mb5hiSgocxnvMkv6NjT66Xsi3iYakJII9q8C'+
4801 'Ma1qZvT/cigmdbAh7wJAQNXyoizuGEltiSaBXx4H29EdXNYWDJ9SS5f070BRbAIl'+
4802 'dqRh3rcNvpY6BKJqFapda1DjdcncZECMizT/GMrc1w==';
4803
4804 */
4805};
4806
4807
4808KeyManager.prototype.verify = function verify(message,signature){
4809
4810 var input = message;
4811
4812 var _PEM_X509CERT_STRING_ = this.certificate;
4813
4814 var x509 = new X509();
4815
4816 x509.readCertPEM(_PEM_X509CERT_STRING_);
4817
4818 var result = x509.subjectPublicKeyRSA.verifyString(input, signature);
4819
4820 return result;
4821};
4822
4823KeyManager.prototype.sign= function sign(message){
4824
4825 var input = message;
4826
4827 var _PEM_PRIVATE_KEY_STRING_ = this.privateKey;
4828
4829 var rsa = new RSAKey();
4830
4831 rsa.readPrivateKeyFromPEMString(_PEM_PRIVATE_KEY_STRING_);
4832
4833 var hSig = rsa.signString(input, "sha256");
4834
4835 return hSig;
4836
4837};
4838
4839
4840
4841var globalKeyManager = new KeyManager();
4842//var KeyPair = { "public" : "PUBLIC KEY" , "private" : "PRIVATE KEY" };
4843
4844
4845
4846/*
4847 * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
4848 * in FIPS 180-1
4849 * Version 2.2 Copyright Paul Johnston 2000 - 2009.
4850 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
4851 * Distributed under the BSD License
4852 * See http://pajhome.org.uk/crypt/md5 for details.
4853 */
4854
4855/*
4856 * Configurable variables. You may need to tweak these to be compatible with
4857 * the server-side, but the defaults work in most cases.
4858 */
4859var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
4860var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
4861
4862/**
4863 * These are the functions you'll usually want to call
4864 * They take string arguments and return either hex or base-64 encoded strings
4865 */
4866function hex_sha1(s) { return rstr2hex(rstr_sha1(str2rstr_utf8(s))); }
4867function b64_sha1(s) { return rstr2b64(rstr_sha1(str2rstr_utf8(s))); }
4868function any_sha1(s, e) { return rstr2any(rstr_sha1(str2rstr_utf8(s)), e); }
4869function hex_hmac_sha1(k, d)
4870 { return rstr2hex(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d))); }
4871function b64_hmac_sha1(k, d)
4872 { return rstr2b64(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d))); }
4873function any_hmac_sha1(k, d, e)
4874 { return rstr2any(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
4875
4876/**
4877 * Perform a simple self-test to see if the VM is working
4878 */
4879function sha1_vm_test()
4880{
4881 return hex_sha1("abc").toLowerCase() == "a9993e364706816aba3e25717850c26c9cd0d89d";
4882}
4883
4884/**
4885 * Calculate the SHA1 of a raw string
4886 */
4887function rstr_sha1(s)
4888{
4889 return binb2rstr(binb_sha1(rstr2binb(s), s.length * 8));
4890}
4891
4892/**
4893 * Calculate the HMAC-SHA1 of a key and some data (raw strings)
4894 */
4895function rstr_hmac_sha1(key, data)
4896{
4897 var bkey = rstr2binb(key);
4898 if(bkey.length > 16) bkey = binb_sha1(bkey, key.length * 8);
4899
4900 var ipad = Array(16), opad = Array(16);
4901 for(var i = 0; i < 16; i++)
4902 {
4903 ipad[i] = bkey[i] ^ 0x36363636;
4904 opad[i] = bkey[i] ^ 0x5C5C5C5C;
4905 }
4906
4907 var hash = binb_sha1(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
4908 return binb2rstr(binb_sha1(opad.concat(hash), 512 + 160));
4909}
4910
4911/**
4912 * Convert a raw string to a hex string
4913 */
4914function rstr2hex(input)
4915{
4916 try { hexcase } catch(e) { hexcase=0; }
4917 var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
4918 var output = "";
4919 var x;
4920 for(var i = 0; i < input.length; i++)
4921 {
4922 x = input.charCodeAt(i);
4923 output += hex_tab.charAt((x >>> 4) & 0x0F)
4924 + hex_tab.charAt( x & 0x0F);
4925 }
4926 return output;
4927}
4928
4929/**
4930 * Convert a raw string to a base-64 string
4931 */
4932function rstr2b64(input)
4933{
4934 try { b64pad } catch(e) { b64pad=''; }
4935 var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4936 var output = "";
4937 var len = input.length;
4938 for(var i = 0; i < len; i += 3)
4939 {
4940 var triplet = (input.charCodeAt(i) << 16)
4941 | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
4942 | (i + 2 < len ? input.charCodeAt(i+2) : 0);
4943 for(var j = 0; j < 4; j++)
4944 {
4945 if(i * 8 + j * 6 > input.length * 8) output += b64pad;
4946 else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
4947 }
4948 }
4949 return output;
4950}
4951
4952/**
4953 * Convert a raw string to an arbitrary string encoding
4954 */
4955function rstr2any(input, encoding)
4956{
4957 var divisor = encoding.length;
4958 var remainders = Array();
4959 var i, q, x, quotient;
4960
4961 /* Convert to an array of 16-bit big-endian values, forming the dividend */
4962 var dividend = Array(Math.ceil(input.length / 2));
4963 for(i = 0; i < dividend.length; i++)
4964 {
4965 dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
4966 }
4967
4968 /*
4969 * Repeatedly perform a long division. The binary array forms the dividend,
4970 * the length of the encoding is the divisor. Once computed, the quotient
4971 * forms the dividend for the next step. We stop when the dividend is zero.
4972 * All remainders are stored for later use.
4973 */
4974 while(dividend.length > 0)
4975 {
4976 quotient = Array();
4977 x = 0;
4978 for(i = 0; i < dividend.length; i++)
4979 {
4980 x = (x << 16) + dividend[i];
4981 q = Math.floor(x / divisor);
4982 x -= q * divisor;
4983 if(quotient.length > 0 || q > 0)
4984 quotient[quotient.length] = q;
4985 }
4986 remainders[remainders.length] = x;
4987 dividend = quotient;
4988 }
4989
4990 /* Convert the remainders to the output string */
4991 var output = "";
4992 for(i = remainders.length - 1; i >= 0; i--)
4993 output += encoding.charAt(remainders[i]);
4994
4995 /* Append leading zero equivalents */
4996 var full_length = Math.ceil(input.length * 8 /
4997 (Math.log(encoding.length) / Math.log(2)));
4998 for(i = output.length; i < full_length; i++)
4999 output = encoding[0] + output;
5000
5001 return output;
5002}
5003
5004/**
5005 * Encode a string as utf-8.
5006 * For efficiency, this assumes the input is valid utf-16.
5007 */
5008function str2rstr_utf8(input)
5009{
5010 var output = "";
5011 var i = -1;
5012 var x, y;
5013
5014 while(++i < input.length)
5015 {
5016 /* Decode utf-16 surrogate pairs */
5017 x = input.charCodeAt(i);
5018 y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
5019 if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
5020 {
5021 x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
5022 i++;
5023 }
5024
5025 /* Encode output as utf-8 */
5026 if(x <= 0x7F)
5027 output += String.fromCharCode(x);
5028 else if(x <= 0x7FF)
5029 output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
5030 0x80 | ( x & 0x3F));
5031 else if(x <= 0xFFFF)
5032 output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
5033 0x80 | ((x >>> 6 ) & 0x3F),
5034 0x80 | ( x & 0x3F));
5035 else if(x <= 0x1FFFFF)
5036 output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
5037 0x80 | ((x >>> 12) & 0x3F),
5038 0x80 | ((x >>> 6 ) & 0x3F),
5039 0x80 | ( x & 0x3F));
5040 }
5041 return output;
5042}
5043
5044/**
5045 * Encode a string as utf-16
5046 */
5047function str2rstr_utf16le(input)
5048{
5049 var output = "";
5050 for(var i = 0; i < input.length; i++)
5051 output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
5052 (input.charCodeAt(i) >>> 8) & 0xFF);
5053 return output;
5054}
5055
5056function str2rstr_utf16be(input)
5057{
5058 var output = "";
5059 for(var i = 0; i < input.length; i++)
5060 output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
5061 input.charCodeAt(i) & 0xFF);
5062 return output;
5063}
5064
5065/**
5066 * Convert a raw string to an array of big-endian words
5067 * Characters >255 have their high-byte silently ignored.
5068 */
5069function rstr2binb(input)
5070{
5071 var output = Array(input.length >> 2);
5072 for(var i = 0; i < output.length; i++)
5073 output[i] = 0;
5074 for(var i = 0; i < input.length * 8; i += 8)
5075 output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
5076 return output;
5077}
5078
5079/**
5080 * Convert an array of big-endian words to a string
5081 */
5082function binb2rstr(input)
5083{
5084 var output = "";
5085 for(var i = 0; i < input.length * 32; i += 8)
5086 output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
5087 return output;
5088}
5089
5090/**
5091 * Calculate the SHA-1 of an array of big-endian words, and a bit length
5092 */
5093function binb_sha1(x, len)
5094{
5095 /* append padding */
5096 x[len >> 5] |= 0x80 << (24 - len % 32);
5097 x[((len + 64 >> 9) << 4) + 15] = len;
5098
5099 var w = Array(80);
5100 var a = 1732584193;
5101 var b = -271733879;
5102 var c = -1732584194;
5103 var d = 271733878;
5104 var e = -1009589776;
5105
5106 for(var i = 0; i < x.length; i += 16)
5107 {
5108 var olda = a;
5109 var oldb = b;
5110 var oldc = c;
5111 var oldd = d;
5112 var olde = e;
5113
5114 for(var j = 0; j < 80; j++)
5115 {
5116 if(j < 16) w[j] = x[i + j];
5117 else w[j] = bit_rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
5118 var t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)),
5119 safe_add(safe_add(e, w[j]), sha1_kt(j)));
5120 e = d;
5121 d = c;
5122 c = bit_rol(b, 30);
5123 b = a;
5124 a = t;
5125 }
5126
5127 a = safe_add(a, olda);
5128 b = safe_add(b, oldb);
5129 c = safe_add(c, oldc);
5130 d = safe_add(d, oldd);
5131 e = safe_add(e, olde);
5132 }
5133 return Array(a, b, c, d, e);
5134
5135}
5136
5137/**
5138 * Perform the appropriate triplet combination function for the current
5139 * iteration
5140 */
5141function sha1_ft(t, b, c, d)
5142{
5143 if(t < 20) return (b & c) | ((~b) & d);
5144 if(t < 40) return b ^ c ^ d;
5145 if(t < 60) return (b & c) | (b & d) | (c & d);
5146 return b ^ c ^ d;
5147}
5148
5149/**
5150 * Determine the appropriate additive constant for the current iteration
5151 */
5152function sha1_kt(t)
5153{
5154 return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
5155 (t < 60) ? -1894007588 : -899497514;
5156}
5157
5158/**
5159 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
5160 * to work around bugs in some JS interpreters.
5161 */
5162function safe_add(x, y)
5163{
5164 var lsw = (x & 0xFFFF) + (y & 0xFFFF);
5165 var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
5166 return (msw << 16) | (lsw & 0xFFFF);
5167}
5168
5169/**
5170 * Bitwise rotate a 32-bit number to the left.
5171 */
5172function bit_rol(num, cnt)
5173{
5174 return (num << cnt) | (num >>> (32 - cnt));
5175}
5176
5177/*
5178 * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined
5179 * in FIPS 180-2
5180 * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
5181 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
5182 * Distributed under the BSD License
5183 * See http://pajhome.org.uk/crypt/md5 for details.
5184 * Also http://anmar.eu.org/projects/jssha2/
5185 */
5186
5187/*
5188 * Configurable variables. You may need to tweak these to be compatible with
5189 * the server-side, but the defaults work in most cases.
5190 */
5191var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
5192var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
5193
5194/*
5195 * These are the functions you'll usually want to call
5196 * They take string arguments and return either hex or base-64 encoded strings
5197 */
5198
5199//@author axelcdv
5200/**
5201 * Computes the Sha-256 hash of the given byte array
5202 * @param {byte[]}
5203 * @return the hex string corresponding to the Sha-256 hash of the byte array
5204 */
5205function hex_sha256_from_bytes(byteArray){
5206 return rstr2hex(binb2rstr(binb_sha256( byteArray2binb(byteArray), byteArray.length * 8)));
5207}
5208
5209function hex_sha256(s) { return rstr2hex(rstr_sha256(str2rstr_utf8(s))); }
5210function b64_sha256(s) { return rstr2b64(rstr_sha256(str2rstr_utf8(s))); }
5211function any_sha256(s, e) { return rstr2any(rstr_sha256(str2rstr_utf8(s)), e); }
5212function hex_hmac_sha256(k, d)
5213 { return rstr2hex(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d))); }
5214function b64_hmac_sha256(k, d)
5215 { return rstr2b64(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d))); }
5216function any_hmac_sha256(k, d, e)
5217 { return rstr2any(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
5218
5219
5220/*
5221 function hex_sha256(s) { return rstr2hex(rstr_sha256(s)); }
5222function b64_sha256(s) { return rstr2b64(rstr_sha256(s)); }
5223function any_sha256(s, e) { return rstr2any(rstr_sha256(s), e); }
5224function hex_hmac_sha256(k, d)
5225 { return rstr2hex(rstr_hmac_sha256(str2rstr_utf8(k), d)); }
5226function b64_hmac_sha256(k, d)
5227 { return rstr2b64(rstr_hmac_sha256(str2rstr_utf8(k), d)); }
5228function any_hmac_sha256(k, d, e)
5229 { return rstr2any(rstr_hmac_sha256(str2rstr_utf8(k), d), e); }
5230*/
5231
5232/*
5233 * Perform a simple self-test to see if the VM is working
5234 */
5235function sha256_vm_test()
5236{
5237 return hex_sha256("abc").toLowerCase() ==
5238 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad";
5239}
5240
5241/**
5242 * Calculate the sha256 of a raw string
5243 * @param s: the raw string
5244 */
5245function rstr_sha256(s)
5246{
5247 return binb2rstr(binb_sha256(rstr2binb(s), s.length * 8));
5248}
5249
5250/**
5251 * Calculate the HMAC-sha256 of a key and some data (raw strings)
5252 */
5253function rstr_hmac_sha256(key, data)
5254{
5255 var bkey = rstr2binb(key);
5256 if(bkey.length > 16) bkey = binb_sha256(bkey, key.length * 8);
5257
5258 var ipad = Array(16), opad = Array(16);
5259 for(var i = 0; i < 16; i++)
5260 {
5261 ipad[i] = bkey[i] ^ 0x36363636;
5262 opad[i] = bkey[i] ^ 0x5C5C5C5C;
5263 }
5264
5265 var hash = binb_sha256(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
5266 return binb2rstr(binb_sha256(opad.concat(hash), 512 + 256));
5267}
5268
5269/**
5270 * Convert a raw string to a hex string
5271 */
5272function rstr2hex(input)
5273{
5274 try { hexcase } catch(e) { hexcase=0; }
5275 var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
5276 var output = "";
5277 var x;
5278 for(var i = 0; i < input.length; i++)
5279 {
5280 x = input.charCodeAt(i);
5281 output += hex_tab.charAt((x >>> 4) & 0x0F)
5282 + hex_tab.charAt( x & 0x0F);
5283 }
5284 return output;
5285}
5286
5287/*
5288 * Convert a raw string to a base-64 string
5289 */
5290function rstr2b64(input)
5291{
5292 try { b64pad } catch(e) { b64pad=''; }
5293 var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
5294 var output = "";
5295 var len = input.length;
5296 for(var i = 0; i < len; i += 3)
5297 {
5298 var triplet = (input.charCodeAt(i) << 16)
5299 | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
5300 | (i + 2 < len ? input.charCodeAt(i+2) : 0);
5301 for(var j = 0; j < 4; j++)
5302 {
5303 if(i * 8 + j * 6 > input.length * 8) output += b64pad;
5304 else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
5305 }
5306 }
5307 return output;
5308}
5309
5310/*
5311 * Convert a raw string to an arbitrary string encoding
5312 */
5313function rstr2any(input, encoding)
5314{
5315 var divisor = encoding.length;
5316 var remainders = Array();
5317 var i, q, x, quotient;
5318
5319 /* Convert to an array of 16-bit big-endian values, forming the dividend */
5320 var dividend = Array(Math.ceil(input.length / 2));
5321 for(i = 0; i < dividend.length; i++)
5322 {
5323 dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
5324 }
5325
5326 /*
5327 * Repeatedly perform a long division. The binary array forms the dividend,
5328 * the length of the encoding is the divisor. Once computed, the quotient
5329 * forms the dividend for the next step. We stop when the dividend is zero.
5330 * All remainders are stored for later use.
5331 */
5332 while(dividend.length > 0)
5333 {
5334 quotient = Array();
5335 x = 0;
5336 for(i = 0; i < dividend.length; i++)
5337 {
5338 x = (x << 16) + dividend[i];
5339 q = Math.floor(x / divisor);
5340 x -= q * divisor;
5341 if(quotient.length > 0 || q > 0)
5342 quotient[quotient.length] = q;
5343 }
5344 remainders[remainders.length] = x;
5345 dividend = quotient;
5346 }
5347
5348 /* Convert the remainders to the output string */
5349 var output = "";
5350 for(i = remainders.length - 1; i >= 0; i--)
5351 output += encoding.charAt(remainders[i]);
5352
5353 /* Append leading zero equivalents */
5354 var full_length = Math.ceil(input.length * 8 /
5355 (Math.log(encoding.length) / Math.log(2)))
5356 for(i = output.length; i < full_length; i++)
5357 output = encoding[0] + output;
5358
5359 return output;
5360}
5361
5362/*
5363 * Encode a string as utf-8.
5364 * For efficiency, this assumes the input is valid utf-16.
5365 */
5366function str2rstr_utf8(input)
5367{
5368 var output = "";
5369 var i = -1;
5370 var x, y;
5371
5372 while(++i < input.length)
5373 {
5374 /* Decode utf-16 surrogate pairs */
5375 x = input.charCodeAt(i);
5376 y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
5377 if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
5378 {
5379 x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
5380 i++;
5381 }
5382
5383 /* Encode output as utf-8 */
5384 if(x <= 0x7F)
5385 output += String.fromCharCode(x);
5386 else if(x <= 0x7FF)
5387 output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
5388 0x80 | ( x & 0x3F));
5389 else if(x <= 0xFFFF)
5390 output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
5391 0x80 | ((x >>> 6 ) & 0x3F),
5392 0x80 | ( x & 0x3F));
5393 else if(x <= 0x1FFFFF)
5394 output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
5395 0x80 | ((x >>> 12) & 0x3F),
5396 0x80 | ((x >>> 6 ) & 0x3F),
5397 0x80 | ( x & 0x3F));
5398 }
5399 return output;
5400}
5401
5402/*
5403 * Encode a string as utf-16
5404 */
5405function str2rstr_utf16le(input)
5406{
5407 var output = "";
5408 for(var i = 0; i < input.length; i++)
5409 output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
5410 (input.charCodeAt(i) >>> 8) & 0xFF);
5411 return output;
5412}
5413
5414function str2rstr_utf16be(input)
5415{
5416 var output = "";
5417 for(var i = 0; i < input.length; i++)
5418 output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
5419 input.charCodeAt(i) & 0xFF);
5420 return output;
5421}
5422
5423/**
5424 * Convert a raw string to an array of big-endian words
5425 * Characters >255 have their high-byte silently ignored.
5426 */
5427function rstr2binb(input)
5428{
Jeff Thompson17a9da82012-11-12 01:11:01 -08005429 //console.log('Raw string comming is '+input);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07005430 var output = Array(input.length >> 2);
5431 for(var i = 0; i < output.length; i++)
5432 output[i] = 0;
5433 for(var i = 0; i < input.length * 8; i += 8)
5434 output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
5435 return output;
5436}
5437
5438/**
5439 * @author axelcdv
5440 * Convert a byte array to an array of big-endian words
5441 * @param {byte[]} input
5442 * @return the array of big-endian words
5443 */
5444function byteArray2binb(input){
Jeff Thompson17a9da82012-11-12 01:11:01 -08005445 //console.log("Byte array coming is " + input);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07005446 var output = Array(input.length >> 2);
5447 for(var i = 0; i < output.length; i++)
5448 output[i] = 0;
5449 for(var i = 0; i < input.length * 8; i += 8)
5450 output[i>>5] |= (input[i / 8] & 0xFF) << (24 - i % 32);
5451 return output;
5452}
5453
5454/*
5455 * Convert an array of big-endian words to a string
5456 */
5457function binb2rstr(input)
5458{
5459 var output = "";
5460 for(var i = 0; i < input.length * 32; i += 8)
5461 output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
5462 return output;
5463}
5464
5465/*
5466 * Main sha256 function, with its support functions
5467 */
5468function sha256_S (X, n) {return ( X >>> n ) | (X << (32 - n));}
5469function sha256_R (X, n) {return ( X >>> n );}
5470function sha256_Ch(x, y, z) {return ((x & y) ^ ((~x) & z));}
5471function sha256_Maj(x, y, z) {return ((x & y) ^ (x & z) ^ (y & z));}
5472function sha256_Sigma0256(x) {return (sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22));}
5473function sha256_Sigma1256(x) {return (sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25));}
5474function sha256_Gamma0256(x) {return (sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3));}
5475function sha256_Gamma1256(x) {return (sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10));}
5476function sha256_Sigma0512(x) {return (sha256_S(x, 28) ^ sha256_S(x, 34) ^ sha256_S(x, 39));}
5477function sha256_Sigma1512(x) {return (sha256_S(x, 14) ^ sha256_S(x, 18) ^ sha256_S(x, 41));}
5478function sha256_Gamma0512(x) {return (sha256_S(x, 1) ^ sha256_S(x, 8) ^ sha256_R(x, 7));}
5479function sha256_Gamma1512(x) {return (sha256_S(x, 19) ^ sha256_S(x, 61) ^ sha256_R(x, 6));}
5480
5481var sha256_K = new Array
5482(
5483 1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993,
5484 -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987,
5485 1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522,
5486 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986,
5487 -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585,
5488 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291,
5489 1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885,
5490 -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344,
5491 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218,
5492 1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872,
5493 -1866530822, -1538233109, -1090935817, -965641998
5494);
5495
5496function binb_sha256(m, l)
5497{
5498 var HASH = new Array(1779033703, -1150833019, 1013904242, -1521486534,
5499 1359893119, -1694144372, 528734635, 1541459225);
5500 var W = new Array(64);
5501 var a, b, c, d, e, f, g, h;
5502 var i, j, T1, T2;
5503
5504 /* append padding */
5505 m[l >> 5] |= 0x80 << (24 - l % 32);
5506 m[((l + 64 >> 9) << 4) + 15] = l;
5507
5508 for(i = 0; i < m.length; i += 16)
5509 {
5510 a = HASH[0];
5511 b = HASH[1];
5512 c = HASH[2];
5513 d = HASH[3];
5514 e = HASH[4];
5515 f = HASH[5];
5516 g = HASH[6];
5517 h = HASH[7];
5518
5519 for(j = 0; j < 64; j++)
5520 {
5521 if (j < 16) W[j] = m[j + i];
5522 else W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]),
5523 sha256_Gamma0256(W[j - 15])), W[j - 16]);
5524
5525 T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)),
5526 sha256_K[j]), W[j]);
5527 T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
5528 h = g;
5529 g = f;
5530 f = e;
5531 e = safe_add(d, T1);
5532 d = c;
5533 c = b;
5534 b = a;
5535 a = safe_add(T1, T2);
5536 }
5537
5538 HASH[0] = safe_add(a, HASH[0]);
5539 HASH[1] = safe_add(b, HASH[1]);
5540 HASH[2] = safe_add(c, HASH[2]);
5541 HASH[3] = safe_add(d, HASH[3]);
5542 HASH[4] = safe_add(e, HASH[4]);
5543 HASH[5] = safe_add(f, HASH[5]);
5544 HASH[6] = safe_add(g, HASH[6]);
5545 HASH[7] = safe_add(h, HASH[7]);
5546 }
5547 return HASH;
5548}
5549
5550function safe_add (x, y)
5551{
5552 var lsw = (x & 0xFFFF) + (y & 0xFFFF);
5553 var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
5554 return (msw << 16) | (lsw & 0xFFFF);
5555}
5556
5557/*
5558 * A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined
5559 * in FIPS 180-2
5560 * Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009.
5561 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
5562 * Distributed under the BSD License
5563 * See http://pajhome.org.uk/crypt/md5 for details.
5564 */
5565
5566/*
5567 * Configurable variables. You may need to tweak these to be compatible with
5568 * the server-side, but the defaults work in most cases.
5569 */
5570var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
5571var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
5572
5573/*
5574 * These are the functions you'll usually want to call
5575 * They take string arguments and return either hex or base-64 encoded strings
5576 */
5577function hex_sha512(s) { return rstr2hex(rstr_sha512(str2rstr_utf8(s))); }
5578function b64_sha512(s) { return rstr2b64(rstr_sha512(str2rstr_utf8(s))); }
5579function any_sha512(s, e) { return rstr2any(rstr_sha512(str2rstr_utf8(s)), e);}
5580function hex_hmac_sha512(k, d)
5581 { return rstr2hex(rstr_hmac_sha512(str2rstr_utf8(k), str2rstr_utf8(d))); }
5582function b64_hmac_sha512(k, d)
5583 { return rstr2b64(rstr_hmac_sha512(str2rstr_utf8(k), str2rstr_utf8(d))); }
5584function any_hmac_sha512(k, d, e)
5585 { return rstr2any(rstr_hmac_sha512(str2rstr_utf8(k), str2rstr_utf8(d)), e);}
5586
5587/*
5588 * Perform a simple self-test to see if the VM is working
5589 */
5590function sha512_vm_test()
5591{
5592 return hex_sha512("abc").toLowerCase() ==
5593 "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" +
5594 "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f";
5595}
5596
5597/*
5598 * Calculate the SHA-512 of a raw string
5599 */
5600function rstr_sha512(s)
5601{
5602 return binb2rstr(binb_sha512(rstr2binb(s), s.length * 8));
5603}
5604
5605/*
5606 * Calculate the HMAC-SHA-512 of a key and some data (raw strings)
5607 */
5608function rstr_hmac_sha512(key, data)
5609{
5610 var bkey = rstr2binb(key);
5611 if(bkey.length > 32) bkey = binb_sha512(bkey, key.length * 8);
5612
5613 var ipad = Array(32), opad = Array(32);
5614 for(var i = 0; i < 32; i++)
5615 {
5616 ipad[i] = bkey[i] ^ 0x36363636;
5617 opad[i] = bkey[i] ^ 0x5C5C5C5C;
5618 }
5619
5620 var hash = binb_sha512(ipad.concat(rstr2binb(data)), 1024 + data.length * 8);
5621 return binb2rstr(binb_sha512(opad.concat(hash), 1024 + 512));
5622}
5623
5624/*
5625 * Convert a raw string to a hex string
5626 */
5627function rstr2hex(input)
5628{
5629 try { hexcase } catch(e) { hexcase=0; }
5630 var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
5631 var output = "";
5632 var x;
5633 for(var i = 0; i < input.length; i++)
5634 {
5635 x = input.charCodeAt(i);
5636 output += hex_tab.charAt((x >>> 4) & 0x0F)
5637 + hex_tab.charAt( x & 0x0F);
5638 }
5639 return output;
5640}
5641
5642/*
5643 * Convert a raw string to a base-64 string
5644 */
5645function rstr2b64(input)
5646{
5647 try { b64pad } catch(e) { b64pad=''; }
5648 var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
5649 var output = "";
5650 var len = input.length;
5651 for(var i = 0; i < len; i += 3)
5652 {
5653 var triplet = (input.charCodeAt(i) << 16)
5654 | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
5655 | (i + 2 < len ? input.charCodeAt(i+2) : 0);
5656 for(var j = 0; j < 4; j++)
5657 {
5658 if(i * 8 + j * 6 > input.length * 8) output += b64pad;
5659 else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
5660 }
5661 }
5662 return output;
5663}
5664
5665/*
5666 * Convert a raw string to an arbitrary string encoding
5667 */
5668function rstr2any(input, encoding)
5669{
5670 var divisor = encoding.length;
5671 var i, j, q, x, quotient;
5672
5673 /* Convert to an array of 16-bit big-endian values, forming the dividend */
5674 var dividend = Array(Math.ceil(input.length / 2));
5675 for(i = 0; i < dividend.length; i++)
5676 {
5677 dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
5678 }
5679
5680 /*
5681 * Repeatedly perform a long division. The binary array forms the dividend,
5682 * the length of the encoding is the divisor. Once computed, the quotient
5683 * forms the dividend for the next step. All remainders are stored for later
5684 * use.
5685 */
5686 var full_length = Math.ceil(input.length * 8 /
5687 (Math.log(encoding.length) / Math.log(2)));
5688 var remainders = Array(full_length);
5689 for(j = 0; j < full_length; j++)
5690 {
5691 quotient = Array();
5692 x = 0;
5693 for(i = 0; i < dividend.length; i++)
5694 {
5695 x = (x << 16) + dividend[i];
5696 q = Math.floor(x / divisor);
5697 x -= q * divisor;
5698 if(quotient.length > 0 || q > 0)
5699 quotient[quotient.length] = q;
5700 }
5701 remainders[j] = x;
5702 dividend = quotient;
5703 }
5704
5705 /* Convert the remainders to the output string */
5706 var output = "";
5707 for(i = remainders.length - 1; i >= 0; i--)
5708 output += encoding.charAt(remainders[i]);
5709
5710 return output;
5711}
5712
5713/*
5714 * Encode a string as utf-8.
5715 * For efficiency, this assumes the input is valid utf-16.
5716 */
5717function str2rstr_utf8(input)
5718{
5719 var output = "";
5720 var i = -1;
5721 var x, y;
5722
5723 while(++i < input.length)
5724 {
5725 /* Decode utf-16 surrogate pairs */
5726 x = input.charCodeAt(i);
5727 y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
5728 if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
5729 {
5730 x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
5731 i++;
5732 }
5733
5734 /* Encode output as utf-8 */
5735 if(x <= 0x7F)
5736 output += String.fromCharCode(x);
5737 else if(x <= 0x7FF)
5738 output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
5739 0x80 | ( x & 0x3F));
5740 else if(x <= 0xFFFF)
5741 output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
5742 0x80 | ((x >>> 6 ) & 0x3F),
5743 0x80 | ( x & 0x3F));
5744 else if(x <= 0x1FFFFF)
5745 output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
5746 0x80 | ((x >>> 12) & 0x3F),
5747 0x80 | ((x >>> 6 ) & 0x3F),
5748 0x80 | ( x & 0x3F));
5749 }
5750 return output;
5751}
5752
5753/*
5754 * Encode a string as utf-16
5755 */
5756function str2rstr_utf16le(input)
5757{
5758 var output = "";
5759 for(var i = 0; i < input.length; i++)
5760 output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
5761 (input.charCodeAt(i) >>> 8) & 0xFF);
5762 return output;
5763}
5764
5765function str2rstr_utf16be(input)
5766{
5767 var output = "";
5768 for(var i = 0; i < input.length; i++)
5769 output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
5770 input.charCodeAt(i) & 0xFF);
5771 return output;
5772}
5773
5774/*
5775 * Convert a raw string to an array of big-endian words
5776 * Characters >255 have their high-byte silently ignored.
5777 */
5778function rstr2binb(input)
5779{
5780 var output = Array(input.length >> 2);
5781 for(var i = 0; i < output.length; i++)
5782 output[i] = 0;
5783 for(var i = 0; i < input.length * 8; i += 8)
5784 output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
5785 return output;
5786}
5787
5788/*
5789 * Convert an array of big-endian words to a string
5790 */
5791function binb2rstr(input)
5792{
5793 var output = "";
5794 for(var i = 0; i < input.length * 32; i += 8)
5795 output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
5796 return output;
5797}
5798
5799/*
5800 * Calculate the SHA-512 of an array of big-endian dwords, and a bit length
5801 */
5802var sha512_k;
5803function binb_sha512(x, len)
5804{
5805 if(sha512_k == undefined)
5806 {
5807 //SHA512 constants
5808 sha512_k = new Array(
5809new int64(0x428a2f98, -685199838), new int64(0x71374491, 0x23ef65cd),
5810new int64(-1245643825, -330482897), new int64(-373957723, -2121671748),
5811new int64(0x3956c25b, -213338824), new int64(0x59f111f1, -1241133031),
5812new int64(-1841331548, -1357295717), new int64(-1424204075, -630357736),
5813new int64(-670586216, -1560083902), new int64(0x12835b01, 0x45706fbe),
5814new int64(0x243185be, 0x4ee4b28c), new int64(0x550c7dc3, -704662302),
5815new int64(0x72be5d74, -226784913), new int64(-2132889090, 0x3b1696b1),
5816new int64(-1680079193, 0x25c71235), new int64(-1046744716, -815192428),
5817new int64(-459576895, -1628353838), new int64(-272742522, 0x384f25e3),
5818new int64(0xfc19dc6, -1953704523), new int64(0x240ca1cc, 0x77ac9c65),
5819new int64(0x2de92c6f, 0x592b0275), new int64(0x4a7484aa, 0x6ea6e483),
5820new int64(0x5cb0a9dc, -1119749164), new int64(0x76f988da, -2096016459),
5821new int64(-1740746414, -295247957), new int64(-1473132947, 0x2db43210),
5822new int64(-1341970488, -1728372417), new int64(-1084653625, -1091629340),
5823new int64(-958395405, 0x3da88fc2), new int64(-710438585, -1828018395),
5824new int64(0x6ca6351, -536640913), new int64(0x14292967, 0xa0e6e70),
5825new int64(0x27b70a85, 0x46d22ffc), new int64(0x2e1b2138, 0x5c26c926),
5826new int64(0x4d2c6dfc, 0x5ac42aed), new int64(0x53380d13, -1651133473),
5827new int64(0x650a7354, -1951439906), new int64(0x766a0abb, 0x3c77b2a8),
5828new int64(-2117940946, 0x47edaee6), new int64(-1838011259, 0x1482353b),
5829new int64(-1564481375, 0x4cf10364), new int64(-1474664885, -1136513023),
5830new int64(-1035236496, -789014639), new int64(-949202525, 0x654be30),
5831new int64(-778901479, -688958952), new int64(-694614492, 0x5565a910),
5832new int64(-200395387, 0x5771202a), new int64(0x106aa070, 0x32bbd1b8),
5833new int64(0x19a4c116, -1194143544), new int64(0x1e376c08, 0x5141ab53),
5834new int64(0x2748774c, -544281703), new int64(0x34b0bcb5, -509917016),
5835new int64(0x391c0cb3, -976659869), new int64(0x4ed8aa4a, -482243893),
5836new int64(0x5b9cca4f, 0x7763e373), new int64(0x682e6ff3, -692930397),
5837new int64(0x748f82ee, 0x5defb2fc), new int64(0x78a5636f, 0x43172f60),
5838new int64(-2067236844, -1578062990), new int64(-1933114872, 0x1a6439ec),
5839new int64(-1866530822, 0x23631e28), new int64(-1538233109, -561857047),
5840new int64(-1090935817, -1295615723), new int64(-965641998, -479046869),
5841new int64(-903397682, -366583396), new int64(-779700025, 0x21c0c207),
5842new int64(-354779690, -840897762), new int64(-176337025, -294727304),
5843new int64(0x6f067aa, 0x72176fba), new int64(0xa637dc5, -1563912026),
5844new int64(0x113f9804, -1090974290), new int64(0x1b710b35, 0x131c471b),
5845new int64(0x28db77f5, 0x23047d84), new int64(0x32caab7b, 0x40c72493),
5846new int64(0x3c9ebe0a, 0x15c9bebc), new int64(0x431d67c4, -1676669620),
5847new int64(0x4cc5d4be, -885112138), new int64(0x597f299c, -60457430),
5848new int64(0x5fcb6fab, 0x3ad6faec), new int64(0x6c44198c, 0x4a475817));
5849 }
5850
5851 //Initial hash values
5852 var H = new Array(
5853new int64(0x6a09e667, -205731576),
5854new int64(-1150833019, -2067093701),
5855new int64(0x3c6ef372, -23791573),
5856new int64(-1521486534, 0x5f1d36f1),
5857new int64(0x510e527f, -1377402159),
5858new int64(-1694144372, 0x2b3e6c1f),
5859new int64(0x1f83d9ab, -79577749),
5860new int64(0x5be0cd19, 0x137e2179));
5861
5862 var T1 = new int64(0, 0),
5863 T2 = new int64(0, 0),
5864 a = new int64(0,0),
5865 b = new int64(0,0),
5866 c = new int64(0,0),
5867 d = new int64(0,0),
5868 e = new int64(0,0),
5869 f = new int64(0,0),
5870 g = new int64(0,0),
5871 h = new int64(0,0),
5872 //Temporary variables not specified by the document
5873 s0 = new int64(0, 0),
5874 s1 = new int64(0, 0),
5875 Ch = new int64(0, 0),
5876 Maj = new int64(0, 0),
5877 r1 = new int64(0, 0),
5878 r2 = new int64(0, 0),
5879 r3 = new int64(0, 0);
5880 var j, i;
5881 var W = new Array(80);
5882 for(i=0; i<80; i++)
5883 W[i] = new int64(0, 0);
5884
5885 // append padding to the source string. The format is described in the FIPS.
5886 x[len >> 5] |= 0x80 << (24 - (len & 0x1f));
5887 x[((len + 128 >> 10)<< 5) + 31] = len;
5888
5889 for(i = 0; i<x.length; i+=32) //32 dwords is the block size
5890 {
5891 int64copy(a, H[0]);
5892 int64copy(b, H[1]);
5893 int64copy(c, H[2]);
5894 int64copy(d, H[3]);
5895 int64copy(e, H[4]);
5896 int64copy(f, H[5]);
5897 int64copy(g, H[6]);
5898 int64copy(h, H[7]);
5899
5900 for(j=0; j<16; j++)
5901 {
5902 W[j].h = x[i + 2*j];
5903 W[j].l = x[i + 2*j + 1];
5904 }
5905
5906 for(j=16; j<80; j++)
5907 {
5908 //sigma1
5909 int64rrot(r1, W[j-2], 19);
5910 int64revrrot(r2, W[j-2], 29);
5911 int64shr(r3, W[j-2], 6);
5912 s1.l = r1.l ^ r2.l ^ r3.l;
5913 s1.h = r1.h ^ r2.h ^ r3.h;
5914 //sigma0
5915 int64rrot(r1, W[j-15], 1);
5916 int64rrot(r2, W[j-15], 8);
5917 int64shr(r3, W[j-15], 7);
5918 s0.l = r1.l ^ r2.l ^ r3.l;
5919 s0.h = r1.h ^ r2.h ^ r3.h;
5920
5921 int64add4(W[j], s1, W[j-7], s0, W[j-16]);
5922 }
5923
5924 for(j = 0; j < 80; j++)
5925 {
5926 //Ch
5927 Ch.l = (e.l & f.l) ^ (~e.l & g.l);
5928 Ch.h = (e.h & f.h) ^ (~e.h & g.h);
5929
5930 //Sigma1
5931 int64rrot(r1, e, 14);
5932 int64rrot(r2, e, 18);
5933 int64revrrot(r3, e, 9);
5934 s1.l = r1.l ^ r2.l ^ r3.l;
5935 s1.h = r1.h ^ r2.h ^ r3.h;
5936
5937 //Sigma0
5938 int64rrot(r1, a, 28);
5939 int64revrrot(r2, a, 2);
5940 int64revrrot(r3, a, 7);
5941 s0.l = r1.l ^ r2.l ^ r3.l;
5942 s0.h = r1.h ^ r2.h ^ r3.h;
5943
5944 //Maj
5945 Maj.l = (a.l & b.l) ^ (a.l & c.l) ^ (b.l & c.l);
5946 Maj.h = (a.h & b.h) ^ (a.h & c.h) ^ (b.h & c.h);
5947
5948 int64add5(T1, h, s1, Ch, sha512_k[j], W[j]);
5949 int64add(T2, s0, Maj);
5950
5951 int64copy(h, g);
5952 int64copy(g, f);
5953 int64copy(f, e);
5954 int64add(e, d, T1);
5955 int64copy(d, c);
5956 int64copy(c, b);
5957 int64copy(b, a);
5958 int64add(a, T1, T2);
5959 }
5960 int64add(H[0], H[0], a);
5961 int64add(H[1], H[1], b);
5962 int64add(H[2], H[2], c);
5963 int64add(H[3], H[3], d);
5964 int64add(H[4], H[4], e);
5965 int64add(H[5], H[5], f);
5966 int64add(H[6], H[6], g);
5967 int64add(H[7], H[7], h);
5968 }
5969
5970 //represent the hash as an array of 32-bit dwords
5971 var hash = new Array(16);
5972 for(i=0; i<8; i++)
5973 {
5974 hash[2*i] = H[i].h;
5975 hash[2*i + 1] = H[i].l;
5976 }
5977 return hash;
5978}
5979
5980//A constructor for 64-bit numbers
5981function int64(h, l)
5982{
5983 this.h = h;
5984 this.l = l;
5985 //this.toString = int64toString;
5986}
5987
5988//Copies src into dst, assuming both are 64-bit numbers
5989function int64copy(dst, src)
5990{
5991 dst.h = src.h;
5992 dst.l = src.l;
5993}
5994
5995//Right-rotates a 64-bit number by shift
5996//Won't handle cases of shift>=32
5997//The function revrrot() is for that
5998function int64rrot(dst, x, shift)
5999{
6000 dst.l = (x.l >>> shift) | (x.h << (32-shift));
6001 dst.h = (x.h >>> shift) | (x.l << (32-shift));
6002}
6003
6004//Reverses the dwords of the source and then rotates right by shift.
6005//This is equivalent to rotation by 32+shift
6006function int64revrrot(dst, x, shift)
6007{
6008 dst.l = (x.h >>> shift) | (x.l << (32-shift));
6009 dst.h = (x.l >>> shift) | (x.h << (32-shift));
6010}
6011
6012//Bitwise-shifts right a 64-bit number by shift
6013//Won't handle shift>=32, but it's never needed in SHA512
6014function int64shr(dst, x, shift)
6015{
6016 dst.l = (x.l >>> shift) | (x.h << (32-shift));
6017 dst.h = (x.h >>> shift);
6018}
6019
6020//Adds two 64-bit numbers
6021//Like the original implementation, does not rely on 32-bit operations
6022function int64add(dst, x, y)
6023{
6024 var w0 = (x.l & 0xffff) + (y.l & 0xffff);
6025 var w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16);
6026 var w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16);
6027 var w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16);
6028 dst.l = (w0 & 0xffff) | (w1 << 16);
6029 dst.h = (w2 & 0xffff) | (w3 << 16);
6030}
6031
6032//Same, except with 4 addends. Works faster than adding them one by one.
6033function int64add4(dst, a, b, c, d)
6034{
6035 var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff);
6036 var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16);
6037 var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16);
6038 var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16);
6039 dst.l = (w0 & 0xffff) | (w1 << 16);
6040 dst.h = (w2 & 0xffff) | (w3 << 16);
6041}
6042
6043//Same, except with 5 addends
6044function int64add5(dst, a, b, c, d, e)
6045{
6046 var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff);
6047 var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16);
6048 var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16);
6049 var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16);
6050 dst.l = (w0 & 0xffff) | (w1 << 16);
6051 dst.h = (w2 & 0xffff) | (w3 << 16);
6052}
6053
6054/*
6055 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
6056 * Digest Algorithm, as defined in RFC 1321.
6057 * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
6058 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
6059 * Distributed under the BSD License
6060 * See http://pajhome.org.uk/crypt/md5 for more info.
6061 */
6062
6063/*
6064 * Configurable variables. You may need to tweak these to be compatible with
6065 * the server-side, but the defaults work in most cases.
6066 */
6067var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
6068var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
6069
6070/*
6071 * These are the functions you'll usually want to call
6072 * They take string arguments and return either hex or base-64 encoded strings
6073 */
6074function hex_md5(s) { return rstr2hex(rstr_md5(str2rstr_utf8(s))); }
6075function b64_md5(s) { return rstr2b64(rstr_md5(str2rstr_utf8(s))); }
6076function any_md5(s, e) { return rstr2any(rstr_md5(str2rstr_utf8(s)), e); }
6077function hex_hmac_md5(k, d)
6078 { return rstr2hex(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
6079function b64_hmac_md5(k, d)
6080 { return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
6081function any_hmac_md5(k, d, e)
6082 { return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
6083
6084/*
6085 * Perform a simple self-test to see if the VM is working
6086 */
6087function md5_vm_test()
6088{
6089 return hex_md5("abc").toLowerCase() == "900150983cd24fb0d6963f7d28e17f72";
6090}
6091
6092/*
6093 * Calculate the MD5 of a raw string
6094 */
6095function rstr_md5(s)
6096{
6097 return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
6098}
6099
6100/*
6101 * Calculate the HMAC-MD5, of a key and some data (raw strings)
6102 */
6103function rstr_hmac_md5(key, data)
6104{
6105 var bkey = rstr2binl(key);
6106 if(bkey.length > 16) bkey = binl_md5(bkey, key.length * 8);
6107
6108 var ipad = Array(16), opad = Array(16);
6109 for(var i = 0; i < 16; i++)
6110 {
6111 ipad[i] = bkey[i] ^ 0x36363636;
6112 opad[i] = bkey[i] ^ 0x5C5C5C5C;
6113 }
6114
6115 var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
6116 return binl2rstr(binl_md5(opad.concat(hash), 512 + 128));
6117}
6118
6119/*
6120 * Convert a raw string to a hex string
6121 */
6122function rstr2hex(input)
6123{
6124 try { hexcase } catch(e) { hexcase=0; }
6125 var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
6126 var output = "";
6127 var x;
6128 for(var i = 0; i < input.length; i++)
6129 {
6130 x = input.charCodeAt(i);
6131 output += hex_tab.charAt((x >>> 4) & 0x0F)
6132 + hex_tab.charAt( x & 0x0F);
6133 }
6134 return output;
6135}
6136
6137/*
6138 * Convert a raw string to a base-64 string
6139 */
6140function rstr2b64(input)
6141{
6142 try { b64pad } catch(e) { b64pad=''; }
6143 var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
6144 var output = "";
6145 var len = input.length;
6146 for(var i = 0; i < len; i += 3)
6147 {
6148 var triplet = (input.charCodeAt(i) << 16)
6149 | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
6150 | (i + 2 < len ? input.charCodeAt(i+2) : 0);
6151 for(var j = 0; j < 4; j++)
6152 {
6153 if(i * 8 + j * 6 > input.length * 8) output += b64pad;
6154 else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
6155 }
6156 }
6157 return output;
6158}
6159
6160/*
6161 * Convert a raw string to an arbitrary string encoding
6162 */
6163function rstr2any(input, encoding)
6164{
6165 var divisor = encoding.length;
6166 var i, j, q, x, quotient;
6167
6168 /* Convert to an array of 16-bit big-endian values, forming the dividend */
6169 var dividend = Array(Math.ceil(input.length / 2));
6170 for(i = 0; i < dividend.length; i++)
6171 {
6172 dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
6173 }
6174
6175 /*
6176 * Repeatedly perform a long division. The binary array forms the dividend,
6177 * the length of the encoding is the divisor. Once computed, the quotient
6178 * forms the dividend for the next step. All remainders are stored for later
6179 * use.
6180 */
6181 var full_length = Math.ceil(input.length * 8 /
6182 (Math.log(encoding.length) / Math.log(2)));
6183 var remainders = Array(full_length);
6184 for(j = 0; j < full_length; j++)
6185 {
6186 quotient = Array();
6187 x = 0;
6188 for(i = 0; i < dividend.length; i++)
6189 {
6190 x = (x << 16) + dividend[i];
6191 q = Math.floor(x / divisor);
6192 x -= q * divisor;
6193 if(quotient.length > 0 || q > 0)
6194 quotient[quotient.length] = q;
6195 }
6196 remainders[j] = x;
6197 dividend = quotient;
6198 }
6199
6200 /* Convert the remainders to the output string */
6201 var output = "";
6202 for(i = remainders.length - 1; i >= 0; i--)
6203 output += encoding.charAt(remainders[i]);
6204
6205 return output;
6206}
6207
6208/*
6209 * Encode a string as utf-8.
6210 * For efficiency, this assumes the input is valid utf-16.
6211 */
6212function str2rstr_utf8(input)
6213{
6214 var output = "";
6215 var i = -1;
6216 var x, y;
6217
6218 while(++i < input.length)
6219 {
6220 /* Decode utf-16 surrogate pairs */
6221 x = input.charCodeAt(i);
6222 y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
6223 if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
6224 {
6225 x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
6226 i++;
6227 }
6228
6229 /* Encode output as utf-8 */
6230 if(x <= 0x7F)
6231 output += String.fromCharCode(x);
6232 else if(x <= 0x7FF)
6233 output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
6234 0x80 | ( x & 0x3F));
6235 else if(x <= 0xFFFF)
6236 output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
6237 0x80 | ((x >>> 6 ) & 0x3F),
6238 0x80 | ( x & 0x3F));
6239 else if(x <= 0x1FFFFF)
6240 output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
6241 0x80 | ((x >>> 12) & 0x3F),
6242 0x80 | ((x >>> 6 ) & 0x3F),
6243 0x80 | ( x & 0x3F));
6244 }
6245 return output;
6246}
6247
6248/*
6249 * Encode a string as utf-16
6250 */
6251function str2rstr_utf16le(input)
6252{
6253 var output = "";
6254 for(var i = 0; i < input.length; i++)
6255 output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
6256 (input.charCodeAt(i) >>> 8) & 0xFF);
6257 return output;
6258}
6259
6260function str2rstr_utf16be(input)
6261{
6262 var output = "";
6263 for(var i = 0; i < input.length; i++)
6264 output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
6265 input.charCodeAt(i) & 0xFF);
6266 return output;
6267}
6268
6269/*
6270 * Convert a raw string to an array of little-endian words
6271 * Characters >255 have their high-byte silently ignored.
6272 */
6273function rstr2binl(input)
6274{
6275 var output = Array(input.length >> 2);
6276 for(var i = 0; i < output.length; i++)
6277 output[i] = 0;
6278 for(var i = 0; i < input.length * 8; i += 8)
6279 output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);
6280 return output;
6281}
6282
6283/*
6284 * Convert an array of little-endian words to a string
6285 */
6286function binl2rstr(input)
6287{
6288 var output = "";
6289 for(var i = 0; i < input.length * 32; i += 8)
6290 output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
6291 return output;
6292}
6293
6294/*
6295 * Calculate the MD5 of an array of little-endian words, and a bit length.
6296 */
6297function binl_md5(x, len)
6298{
6299 /* append padding */
6300 x[len >> 5] |= 0x80 << ((len) % 32);
6301 x[(((len + 64) >>> 9) << 4) + 14] = len;
6302
6303 var a = 1732584193;
6304 var b = -271733879;
6305 var c = -1732584194;
6306 var d = 271733878;
6307
6308 for(var i = 0; i < x.length; i += 16)
6309 {
6310 var olda = a;
6311 var oldb = b;
6312 var oldc = c;
6313 var oldd = d;
6314
6315 a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
6316 d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
6317 c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
6318 b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
6319 a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
6320 d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
6321 c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
6322 b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
6323 a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
6324 d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
6325 c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
6326 b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
6327 a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
6328 d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
6329 c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
6330 b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
6331
6332 a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
6333 d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
6334 c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
6335 b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
6336 a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
6337 d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
6338 c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
6339 b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
6340 a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
6341 d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
6342 c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
6343 b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
6344 a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
6345 d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
6346 c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
6347 b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
6348
6349 a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
6350 d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
6351 c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
6352 b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
6353 a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
6354 d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
6355 c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
6356 b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
6357 a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
6358 d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
6359 c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
6360 b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
6361 a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
6362 d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
6363 c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
6364 b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
6365
6366 a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
6367 d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
6368 c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
6369 b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
6370 a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
6371 d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
6372 c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
6373 b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
6374 a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
6375 d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
6376 c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
6377 b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
6378 a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
6379 d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
6380 c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
6381 b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
6382
6383 a = safe_add(a, olda);
6384 b = safe_add(b, oldb);
6385 c = safe_add(c, oldc);
6386 d = safe_add(d, oldd);
6387 }
6388 return Array(a, b, c, d);
6389}
6390
6391/*
6392 * These functions implement the four basic operations the algorithm uses.
6393 */
6394function md5_cmn(q, a, b, x, s, t)
6395{
6396 return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
6397}
6398function md5_ff(a, b, c, d, x, s, t)
6399{
6400 return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
6401}
6402function md5_gg(a, b, c, d, x, s, t)
6403{
6404 return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
6405}
6406function md5_hh(a, b, c, d, x, s, t)
6407{
6408 return md5_cmn(b ^ c ^ d, a, b, x, s, t);
6409}
6410function md5_ii(a, b, c, d, x, s, t)
6411{
6412 return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
6413}
6414
6415/*
6416 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
6417 * to work around bugs in some JS interpreters.
6418 */
6419function safe_add(x, y)
6420{
6421 var lsw = (x & 0xFFFF) + (y & 0xFFFF);
6422 var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
6423 return (msw << 16) | (lsw & 0xFFFF);
6424}
6425
6426/*
6427 * Bitwise rotate a 32-bit number to the left.
6428 */
6429function bit_rol(num, cnt)
6430{
6431 return (num << cnt) | (num >>> (32 - cnt));
6432}
6433
6434/*
6435 * A JavaScript implementation of the RIPEMD-160 Algorithm
6436 * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
6437 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
6438 * Distributed under the BSD License
6439 * See http://pajhome.org.uk/crypt/md5 for details.
6440 * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
6441 */
6442
6443/*
6444 * Configurable variables. You may need to tweak these to be compatible with
6445 * the server-side, but the defaults work in most cases.
6446 */
6447var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
6448var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
6449
6450/*
6451 * These are the functions you'll usually want to call
6452 * They take string arguments and return either hex or base-64 encoded strings
6453 */
6454function hex_rmd160(s) { return rstr2hex(rstr_rmd160(str2rstr_utf8(s))); }
6455function b64_rmd160(s) { return rstr2b64(rstr_rmd160(str2rstr_utf8(s))); }
6456function any_rmd160(s, e) { return rstr2any(rstr_rmd160(str2rstr_utf8(s)), e); }
6457function hex_hmac_rmd160(k, d)
6458 { return rstr2hex(rstr_hmac_rmd160(str2rstr_utf8(k), str2rstr_utf8(d))); }
6459function b64_hmac_rmd160(k, d)
6460 { return rstr2b64(rstr_hmac_rmd160(str2rstr_utf8(k), str2rstr_utf8(d))); }
6461function any_hmac_rmd160(k, d, e)
6462 { return rstr2any(rstr_hmac_rmd160(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
6463
6464/*
6465 * Perform a simple self-test to see if the VM is working
6466 */
6467function rmd160_vm_test()
6468{
6469 return hex_rmd160("abc").toLowerCase() == "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc";
6470}
6471
6472/*
6473 * Calculate the rmd160 of a raw string
6474 */
6475function rstr_rmd160(s)
6476{
6477 return binl2rstr(binl_rmd160(rstr2binl(s), s.length * 8));
6478}
6479
6480/*
6481 * Calculate the HMAC-rmd160 of a key and some data (raw strings)
6482 */
6483function rstr_hmac_rmd160(key, data)
6484{
6485 var bkey = rstr2binl(key);
6486 if(bkey.length > 16) bkey = binl_rmd160(bkey, key.length * 8);
6487
6488 var ipad = Array(16), opad = Array(16);
6489 for(var i = 0; i < 16; i++)
6490 {
6491 ipad[i] = bkey[i] ^ 0x36363636;
6492 opad[i] = bkey[i] ^ 0x5C5C5C5C;
6493 }
6494
6495 var hash = binl_rmd160(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
6496 return binl2rstr(binl_rmd160(opad.concat(hash), 512 + 160));
6497}
6498
6499/*
6500 * Convert a raw string to a hex string
6501 */
6502function rstr2hex(input)
6503{
6504 try { hexcase } catch(e) { hexcase=0; }
6505 var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
6506 var output = "";
6507 var x;
6508 for(var i = 0; i < input.length; i++)
6509 {
6510 x = input.charCodeAt(i);
6511 output += hex_tab.charAt((x >>> 4) & 0x0F)
6512 + hex_tab.charAt( x & 0x0F);
6513 }
6514 return output;
6515}
6516
6517/*
6518 * Convert a raw string to a base-64 string
6519 */
6520function rstr2b64(input)
6521{
6522 try { b64pad } catch(e) { b64pad=''; }
6523 var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
6524 var output = "";
6525 var len = input.length;
6526 for(var i = 0; i < len; i += 3)
6527 {
6528 var triplet = (input.charCodeAt(i) << 16)
6529 | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
6530 | (i + 2 < len ? input.charCodeAt(i+2) : 0);
6531 for(var j = 0; j < 4; j++)
6532 {
6533 if(i * 8 + j * 6 > input.length * 8) output += b64pad;
6534 else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
6535 }
6536 }
6537 return output;
6538}
6539
6540/*
6541 * Convert a raw string to an arbitrary string encoding
6542 */
6543function rstr2any(input, encoding)
6544{
6545 var divisor = encoding.length;
6546 var remainders = Array();
6547 var i, q, x, quotient;
6548
6549 /* Convert to an array of 16-bit big-endian values, forming the dividend */
6550 var dividend = Array(Math.ceil(input.length / 2));
6551 for(i = 0; i < dividend.length; i++)
6552 {
6553 dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
6554 }
6555
6556 /*
6557 * Repeatedly perform a long division. The binary array forms the dividend,
6558 * the length of the encoding is the divisor. Once computed, the quotient
6559 * forms the dividend for the next step. We stop when the dividend is zero.
6560 * All remainders are stored for later use.
6561 */
6562 while(dividend.length > 0)
6563 {
6564 quotient = Array();
6565 x = 0;
6566 for(i = 0; i < dividend.length; i++)
6567 {
6568 x = (x << 16) + dividend[i];
6569 q = Math.floor(x / divisor);
6570 x -= q * divisor;
6571 if(quotient.length > 0 || q > 0)
6572 quotient[quotient.length] = q;
6573 }
6574 remainders[remainders.length] = x;
6575 dividend = quotient;
6576 }
6577
6578 /* Convert the remainders to the output string */
6579 var output = "";
6580 for(i = remainders.length - 1; i >= 0; i--)
6581 output += encoding.charAt(remainders[i]);
6582
6583 /* Append leading zero equivalents */
6584 var full_length = Math.ceil(input.length * 8 /
6585 (Math.log(encoding.length) / Math.log(2)))
6586 for(i = output.length; i < full_length; i++)
6587 output = encoding[0] + output;
6588
6589 return output;
6590}
6591
6592/*
6593 * Encode a string as utf-8.
6594 * For efficiency, this assumes the input is valid utf-16.
6595 */
6596function str2rstr_utf8(input)
6597{
6598 var output = "";
6599 var i = -1;
6600 var x, y;
6601
6602 while(++i < input.length)
6603 {
6604 /* Decode utf-16 surrogate pairs */
6605 x = input.charCodeAt(i);
6606 y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
6607 if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
6608 {
6609 x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
6610 i++;
6611 }
6612
6613 /* Encode output as utf-8 */
6614 if(x <= 0x7F)
6615 output += String.fromCharCode(x);
6616 else if(x <= 0x7FF)
6617 output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
6618 0x80 | ( x & 0x3F));
6619 else if(x <= 0xFFFF)
6620 output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
6621 0x80 | ((x >>> 6 ) & 0x3F),
6622 0x80 | ( x & 0x3F));
6623 else if(x <= 0x1FFFFF)
6624 output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
6625 0x80 | ((x >>> 12) & 0x3F),
6626 0x80 | ((x >>> 6 ) & 0x3F),
6627 0x80 | ( x & 0x3F));
6628 }
6629 return output;
6630}
6631
6632/*
6633 * Encode a string as utf-16
6634 */
6635function str2rstr_utf16le(input)
6636{
6637 var output = "";
6638 for(var i = 0; i < input.length; i++)
6639 output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
6640 (input.charCodeAt(i) >>> 8) & 0xFF);
6641 return output;
6642}
6643
6644function str2rstr_utf16be(input)
6645{
6646 var output = "";
6647 for(var i = 0; i < input.length; i++)
6648 output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
6649 input.charCodeAt(i) & 0xFF);
6650 return output;
6651}
6652
6653/*
6654 * Convert a raw string to an array of little-endian words
6655 * Characters >255 have their high-byte silently ignored.
6656 */
6657function rstr2binl(input)
6658{
6659 var output = Array(input.length >> 2);
6660 for(var i = 0; i < output.length; i++)
6661 output[i] = 0;
6662 for(var i = 0; i < input.length * 8; i += 8)
6663 output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);
6664 return output;
6665}
6666
6667/*
6668 * Convert an array of little-endian words to a string
6669 */
6670function binl2rstr(input)
6671{
6672 var output = "";
6673 for(var i = 0; i < input.length * 32; i += 8)
6674 output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
6675 return output;
6676}
6677
6678/*
6679 * Calculate the RIPE-MD160 of an array of little-endian words, and a bit length.
6680 */
6681function binl_rmd160(x, len)
6682{
6683 /* append padding */
6684 x[len >> 5] |= 0x80 << (len % 32);
6685 x[(((len + 64) >>> 9) << 4) + 14] = len;
6686
6687 var h0 = 0x67452301;
6688 var h1 = 0xefcdab89;
6689 var h2 = 0x98badcfe;
6690 var h3 = 0x10325476;
6691 var h4 = 0xc3d2e1f0;
6692
6693 for (var i = 0; i < x.length; i += 16) {
6694 var T;
6695 var A1 = h0, B1 = h1, C1 = h2, D1 = h3, E1 = h4;
6696 var A2 = h0, B2 = h1, C2 = h2, D2 = h3, E2 = h4;
6697 for (var j = 0; j <= 79; ++j) {
6698 T = safe_add(A1, rmd160_f(j, B1, C1, D1));
6699 T = safe_add(T, x[i + rmd160_r1[j]]);
6700 T = safe_add(T, rmd160_K1(j));
6701 T = safe_add(bit_rol(T, rmd160_s1[j]), E1);
6702 A1 = E1; E1 = D1; D1 = bit_rol(C1, 10); C1 = B1; B1 = T;
6703 T = safe_add(A2, rmd160_f(79-j, B2, C2, D2));
6704 T = safe_add(T, x[i + rmd160_r2[j]]);
6705 T = safe_add(T, rmd160_K2(j));
6706 T = safe_add(bit_rol(T, rmd160_s2[j]), E2);
6707 A2 = E2; E2 = D2; D2 = bit_rol(C2, 10); C2 = B2; B2 = T;
6708 }
6709 T = safe_add(h1, safe_add(C1, D2));
6710 h1 = safe_add(h2, safe_add(D1, E2));
6711 h2 = safe_add(h3, safe_add(E1, A2));
6712 h3 = safe_add(h4, safe_add(A1, B2));
6713 h4 = safe_add(h0, safe_add(B1, C2));
6714 h0 = T;
6715 }
6716 return [h0, h1, h2, h3, h4];
6717}
6718
6719function rmd160_f(j, x, y, z)
6720{
6721 return ( 0 <= j && j <= 15) ? (x ^ y ^ z) :
6722 (16 <= j && j <= 31) ? (x & y) | (~x & z) :
6723 (32 <= j && j <= 47) ? (x | ~y) ^ z :
6724 (48 <= j && j <= 63) ? (x & z) | (y & ~z) :
6725 (64 <= j && j <= 79) ? x ^ (y | ~z) :
6726 "rmd160_f: j out of range";
6727}
6728function rmd160_K1(j)
6729{
6730 return ( 0 <= j && j <= 15) ? 0x00000000 :
6731 (16 <= j && j <= 31) ? 0x5a827999 :
6732 (32 <= j && j <= 47) ? 0x6ed9eba1 :
6733 (48 <= j && j <= 63) ? 0x8f1bbcdc :
6734 (64 <= j && j <= 79) ? 0xa953fd4e :
6735 "rmd160_K1: j out of range";
6736}
6737function rmd160_K2(j)
6738{
6739 return ( 0 <= j && j <= 15) ? 0x50a28be6 :
6740 (16 <= j && j <= 31) ? 0x5c4dd124 :
6741 (32 <= j && j <= 47) ? 0x6d703ef3 :
6742 (48 <= j && j <= 63) ? 0x7a6d76e9 :
6743 (64 <= j && j <= 79) ? 0x00000000 :
6744 "rmd160_K2: j out of range";
6745}
6746var rmd160_r1 = [
6747 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
6748 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
6749 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
6750 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
6751 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
6752];
6753var rmd160_r2 = [
6754 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
6755 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
6756 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
6757 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
6758 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
6759];
6760var rmd160_s1 = [
6761 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
6762 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
6763 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
6764 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
6765 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
6766];
6767var rmd160_s2 = [
6768 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
6769 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
6770 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
6771 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
6772 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
6773];
6774
6775/*
6776 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
6777 * to work around bugs in some JS interpreters.
6778 */
6779function safe_add(x, y)
6780{
6781 var lsw = (x & 0xFFFF) + (y & 0xFFFF);
6782 var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
6783 return (msw << 16) | (lsw & 0xFFFF);
6784}
6785
6786/*
6787 * Bitwise rotate a 32-bit number to the left.
6788 */
6789function bit_rol(num, cnt)
6790{
6791 return (num << cnt) | (num >>> (32 - cnt));
6792}
6793
6794var b64map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
6795var b64pad="=";
6796
6797function hex2b64(h) {
6798 var i;
6799 var c;
6800 var ret = "";
6801 for(i = 0; i+3 <= h.length; i+=3) {
6802 c = parseInt(h.substring(i,i+3),16);
6803 ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63);
6804 }
6805 if(i+1 == h.length) {
6806 c = parseInt(h.substring(i,i+1),16);
6807 ret += b64map.charAt(c << 2);
6808 }
6809 else if(i+2 == h.length) {
6810 c = parseInt(h.substring(i,i+2),16);
6811 ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4);
6812 }
6813 while((ret.length & 3) > 0) ret += b64pad;
6814 return ret;
6815}
6816
6817// convert a base64 string to hex
6818function b64tohex(s) {
6819 var ret = ""
6820 var i;
6821 var k = 0; // b64 state, 0-3
6822 var slop;
6823 for(i = 0; i < s.length; ++i) {
6824 if(s.charAt(i) == b64pad) break;
6825 v = b64map.indexOf(s.charAt(i));
6826 if(v < 0) continue;
6827 if(k == 0) {
6828 ret += int2char(v >> 2);
6829 slop = v & 3;
6830 k = 1;
6831 }
6832 else if(k == 1) {
6833 ret += int2char((slop << 2) | (v >> 4));
6834 slop = v & 0xf;
6835 k = 2;
6836 }
6837 else if(k == 2) {
6838 ret += int2char(slop);
6839 ret += int2char(v >> 2);
6840 slop = v & 3;
6841 k = 3;
6842 }
6843 else {
6844 ret += int2char((slop << 2) | (v >> 4));
6845 ret += int2char(v & 0xf);
6846 k = 0;
6847 }
6848 }
6849 if(k == 1)
6850 ret += int2char(slop << 2);
6851 return ret;
6852}
6853
6854// convert a base64 string to a byte/number array
6855function b64toBA(s) {
6856 //piggyback on b64tohex for now, optimize later
6857 var h = b64tohex(s);
6858 var i;
6859 var a = new Array();
6860 for(i = 0; 2*i < h.length; ++i) {
6861 a[i] = parseInt(h.substring(2*i,2*i+2),16);
6862 }
6863 return a;
6864}
6865
6866// Depends on jsbn.js and rng.js
6867
6868// Version 1.1: support utf-8 encoding in pkcs1pad2
6869
6870// convert a (hex) string to a bignum object
6871function parseBigInt(str,r) {
6872 return new BigInteger(str,r);
6873}
6874
6875function linebrk(s,n) {
6876 var ret = "";
6877 var i = 0;
6878 while(i + n < s.length) {
6879 ret += s.substring(i,i+n) + "\n";
6880 i += n;
6881 }
6882 return ret + s.substring(i,s.length);
6883}
6884
6885function byte2Hex(b) {
6886 if(b < 0x10)
6887 return "0" + b.toString(16);
6888 else
6889 return b.toString(16);
6890}
6891
6892/**
6893 * PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint
6894 * @param s: the string to encode
6895 * @param n: the size in byte
6896 */
6897function pkcs1pad2(s,n) {
6898 if(n < s.length + 11) { // TODO: fix for utf-8
6899 alert("Message too long for RSA");
6900 return null;
6901 }
6902 var ba = new Array();
6903 var i = s.length - 1;
6904 while(i >= 0 && n > 0) {
6905 var c = s.charCodeAt(i--);
6906 if(c < 128) { // encode using utf-8
6907 ba[--n] = c;
6908 }
6909 else if((c > 127) && (c < 2048)) {
6910 ba[--n] = (c & 63) | 128;
6911 ba[--n] = (c >> 6) | 192;
6912 }
6913 else {
6914 ba[--n] = (c & 63) | 128;
6915 ba[--n] = ((c >> 6) & 63) | 128;
6916 ba[--n] = (c >> 12) | 224;
6917 }
6918 }
6919 ba[--n] = 0;
6920 var rng = new SecureRandom();
6921 var x = new Array();
6922 while(n > 2) { // random non-zero pad
6923 x[0] = 0;
6924 while(x[0] == 0) rng.nextBytes(x);
6925 ba[--n] = x[0];
6926 }
6927 ba[--n] = 2;
6928 ba[--n] = 0;
6929 return new BigInteger(ba);
6930}
6931
6932/**
6933 * "empty" RSA key constructor
6934 * @returns {RSAKey}
6935 */
6936function RSAKey() {
6937 this.n = null;
6938 this.e = 0;
6939 this.d = null;
6940 this.p = null;
6941 this.q = null;
6942 this.dmp1 = null;
6943 this.dmq1 = null;
6944 this.coeff = null;
6945}
6946
6947/**
6948 * Set the public key fields N and e from hex strings
6949 * @param N
6950 * @param E
6951 * @returns {RSASetPublic}
6952 */
6953function RSASetPublic(N,E) {
6954 if(N != null && E != null && N.length > 0 && E.length > 0) {
6955 this.n = parseBigInt(N,16);
6956 this.e = parseInt(E,16);
6957 }
6958 else
6959 alert("Invalid RSA public key");
6960}
6961
6962/**
6963 * Perform raw public operation on "x": return x^e (mod n)
6964 * @param x
6965 * @returns x^e (mod n)
6966 */
6967function RSADoPublic(x) {
6968 return x.modPowInt(this.e, this.n);
6969}
6970
6971/**
6972 * Return the PKCS#1 RSA encryption of "text" as an even-length hex string
6973 */
6974function RSAEncrypt(text) {
6975 var m = pkcs1pad2(text,(this.n.bitLength()+7)>>3);
6976 if(m == null) return null;
6977 var c = this.doPublic(m);
6978 if(c == null) return null;
6979 var h = c.toString(16);
6980 if((h.length & 1) == 0) return h; else return "0" + h;
6981}
6982
6983// Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string
6984//function RSAEncryptB64(text) {
6985// var h = this.encrypt(text);
6986// if(h) return hex2b64(h); else return null;
6987//}
6988
6989// protected
6990RSAKey.prototype.doPublic = RSADoPublic;
6991
6992// public
6993RSAKey.prototype.setPublic = RSASetPublic;
6994RSAKey.prototype.encrypt = RSAEncrypt;
6995//RSAKey.prototype.encrypt_b64 = RSAEncryptB64;
6996
6997// Depends on rsa.js and jsbn2.js
6998
6999// Version 1.1: support utf-8 decoding in pkcs1unpad2
7000
7001// Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext
7002function pkcs1unpad2(d,n) {
7003 var b = d.toByteArray();
7004 var i = 0;
7005 while(i < b.length && b[i] == 0) ++i;
7006 if(b.length-i != n-1 || b[i] != 2)
7007 return null;
7008 ++i;
7009 while(b[i] != 0)
7010 if(++i >= b.length) return null;
7011 var ret = "";
7012 while(++i < b.length) {
7013 var c = b[i] & 255;
7014 if(c < 128) { // utf-8 decode
7015 ret += String.fromCharCode(c);
7016 }
7017 else if((c > 191) && (c < 224)) {
7018 ret += String.fromCharCode(((c & 31) << 6) | (b[i+1] & 63));
7019 ++i;
7020 }
7021 else {
7022 ret += String.fromCharCode(((c & 15) << 12) | ((b[i+1] & 63) << 6) | (b[i+2] & 63));
7023 i += 2;
7024 }
7025 }
7026 return ret;
7027}
7028
7029// Set the private key fields N, e, and d from hex strings
7030function RSASetPrivate(N,E,D) {
7031 if(N != null && E != null && N.length > 0 && E.length > 0) {
7032 this.n = parseBigInt(N,16);
7033 this.e = parseInt(E,16);
7034 this.d = parseBigInt(D,16);
7035 }
7036 else
7037 alert("Invalid RSA private key");
7038}
7039
7040// Set the private key fields N, e, d and CRT params from hex strings
7041function RSASetPrivateEx(N,E,D,P,Q,DP,DQ,C) {
7042 if(N != null && E != null && N.length > 0 && E.length > 0) {
7043 this.n = parseBigInt(N,16);
7044 this.e = parseInt(E,16);
7045 this.d = parseBigInt(D,16);
7046 this.p = parseBigInt(P,16);
7047 this.q = parseBigInt(Q,16);
7048 this.dmp1 = parseBigInt(DP,16);
7049 this.dmq1 = parseBigInt(DQ,16);
7050 this.coeff = parseBigInt(C,16);
7051 }
7052 else
7053 alert("Invalid RSA private key");
7054}
7055
7056/**
7057 * Generate a new random private key B bits long, using public expt E
7058 */
7059function RSAGenerate(B,E) {
7060 var rng = new SecureRandom();
7061 var qs = B>>1;
7062 this.e = parseInt(E,16);
7063 var ee = new BigInteger(E,16);
7064 for(;;) {
7065 for(;;) {
7066 this.p = new BigInteger(B-qs,1,rng);
7067 if(this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.p.isProbablePrime(10)) break;
7068 }
7069 for(;;) {
7070 this.q = new BigInteger(qs,1,rng);
7071 if(this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.q.isProbablePrime(10)) break;
7072 }
7073 if(this.p.compareTo(this.q) <= 0) {
7074 var t = this.p;
7075 this.p = this.q;
7076 this.q = t;
7077 }
7078 var p1 = this.p.subtract(BigInteger.ONE); // p1 = p - 1
7079 var q1 = this.q.subtract(BigInteger.ONE); // q1 = q - 1
7080 var phi = p1.multiply(q1);
7081 if(phi.gcd(ee).compareTo(BigInteger.ONE) == 0) {
7082 this.n = this.p.multiply(this.q); // this.n = p * q
7083 this.d = ee.modInverse(phi); // this.d =
7084 this.dmp1 = this.d.mod(p1); // this.dmp1 = d mod (p - 1)
7085 this.dmq1 = this.d.mod(q1); // this.dmq1 = d mod (q - 1)
7086 this.coeff = this.q.modInverse(this.p); // this.coeff = (q ^ -1) mod p
7087 break;
7088 }
7089 }
7090}
7091
7092/**
7093 * Perform raw private operation on "x": return x^d (mod n)
7094 * @return x^d (mod n)
7095 */
7096function RSADoPrivate(x) {
7097 if(this.p == null || this.q == null)
7098 return x.modPow(this.d, this.n);
7099
7100 // TODO: re-calculate any missing CRT params
7101 var xp = x.mod(this.p).modPow(this.dmp1, this.p); // xp=cp?
7102 var xq = x.mod(this.q).modPow(this.dmq1, this.q); // xq=cq?
7103
7104 while(xp.compareTo(xq) < 0)
7105 xp = xp.add(this.p);
7106 // NOTE:
7107 // xp.subtract(xq) => cp -cq
7108 // xp.subtract(xq).multiply(this.coeff).mod(this.p) => (cp - cq) * u mod p = h
7109 // xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq) => cq + (h * q) = M
7110 return xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq);
7111}
7112
7113// Return the PKCS#1 RSA decryption of "ctext".
7114// "ctext" is an even-length hex string and the output is a plain string.
7115function RSADecrypt(ctext) {
7116 var c = parseBigInt(ctext, 16);
7117 var m = this.doPrivate(c);
7118 if(m == null) return null;
7119 return pkcs1unpad2(m, (this.n.bitLength()+7)>>3);
7120}
7121
7122// Return the PKCS#1 RSA decryption of "ctext".
7123// "ctext" is a Base64-encoded string and the output is a plain string.
7124//function RSAB64Decrypt(ctext) {
7125// var h = b64tohex(ctext);
7126// if(h) return this.decrypt(h); else return null;
7127//}
7128
7129// protected
7130RSAKey.prototype.doPrivate = RSADoPrivate;
7131
7132// public
7133RSAKey.prototype.setPrivate = RSASetPrivate;
7134RSAKey.prototype.setPrivateEx = RSASetPrivateEx;
7135RSAKey.prototype.generate = RSAGenerate;
7136RSAKey.prototype.decrypt = RSADecrypt;
7137//RSAKey.prototype.b64_decrypt = RSAB64Decrypt;
7138
7139/*! rsapem-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
7140 */
7141//
7142// rsa-pem.js - adding function for reading/writing PKCS#1 PEM private key
7143// to RSAKey class.
7144//
7145// version: 1.1 (2012-May-10)
7146//
7147// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
7148//
7149// This software is licensed under the terms of the MIT License.
7150// http://kjur.github.com/jsrsasign/license/
7151//
7152// The above copyright and license notice shall be
7153// included in all copies or substantial portions of the Software.
7154//
7155//
7156// Depends on:
7157//
7158//
7159//
7160// _RSApem_pemToBase64(sPEM)
7161//
7162// removing PEM header, PEM footer and space characters including
7163// new lines from PEM formatted RSA private key string.
7164//
7165
7166function _rsapem_pemToBase64(sPEMPrivateKey) {
7167 var s = sPEMPrivateKey;
7168 s = s.replace("-----BEGIN RSA PRIVATE KEY-----", "");
7169 s = s.replace("-----END RSA PRIVATE KEY-----", "");
7170 s = s.replace(/[ \n]+/g, "");
7171 return s;
7172}
7173
7174function _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey) {
7175 var a = new Array();
7176 var v1 = ASN1HEX.getStartPosOfV_AtObj(hPrivateKey, 0);
7177 var n1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, v1);
7178 var e1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, n1);
7179 var d1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, e1);
7180 var p1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, d1);
7181 var q1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, p1);
7182 var dp1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, q1);
7183 var dq1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dp1);
7184 var co1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dq1);
7185 a.push(v1, n1, e1, d1, p1, q1, dp1, dq1, co1);
7186 return a;
7187}
7188
7189function _rsapem_getHexValueArrayOfChildrenFromHex(hPrivateKey) {
7190 var posArray = _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey);
7191 var v = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[0]);
7192 var n = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[1]);
7193 var e = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[2]);
7194 var d = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[3]);
7195 var p = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[4]);
7196 var q = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[5]);
7197 var dp = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[6]);
7198 var dq = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[7]);
7199 var co = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[8]);
7200 var a = new Array();
7201 a.push(v, n, e, d, p, q, dp, dq, co);
7202 return a;
7203}
7204
7205/**
7206 * read PKCS#1 private key from a string
7207 * @name readPrivateKeyFromPEMString
7208 * @memberOf RSAKey#
7209 * @function
7210 * @param {String} keyPEM string of PKCS#1 private key.
7211 */
7212function _rsapem_readPrivateKeyFromPEMString(keyPEM) {
7213 var keyB64 = _rsapem_pemToBase64(keyPEM);
7214 var keyHex = b64tohex(keyB64) // depends base64.js
7215 var a = _rsapem_getHexValueArrayOfChildrenFromHex(keyHex);
7216 this.setPrivateEx(a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]);
7217}
7218
7219RSAKey.prototype.readPrivateKeyFromPEMString = _rsapem_readPrivateKeyFromPEMString;
7220
7221/*! rsasign-1.2.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
7222 */
7223//
7224// rsa-sign.js - adding signing functions to RSAKey class.
7225//
7226//
7227// version: 1.2.1 (08 May 2012)
7228//
7229// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
7230//
7231// This software is licensed under the terms of the MIT License.
7232// http://kjur.github.com/jsrsasign/license/
7233//
7234// The above copyright and license notice shall be
7235// included in all copies or substantial portions of the Software.
7236
7237//
7238// Depends on:
7239// function sha1.hex(s) of sha1.js
7240// jsbn.js
7241// jsbn2.js
7242// rsa.js
7243// rsa2.js
7244//
7245
7246// keysize / pmstrlen
7247// 512 / 128
7248// 1024 / 256
7249// 2048 / 512
7250// 4096 / 1024
7251
7252/**
7253 * @property {Dictionary} _RSASIGN_DIHEAD
7254 * @description Array of head part of hexadecimal DigestInfo value for hash algorithms.
7255 * You can add any DigestInfo hash algorith for signing.
7256 * See PKCS#1 v2.1 spec (p38).
7257 */
7258var _RSASIGN_DIHEAD = [];
7259_RSASIGN_DIHEAD['sha1'] = "3021300906052b0e03021a05000414";
7260_RSASIGN_DIHEAD['sha256'] = "3031300d060960864801650304020105000420";
7261_RSASIGN_DIHEAD['sha384'] = "3041300d060960864801650304020205000430";
7262_RSASIGN_DIHEAD['sha512'] = "3051300d060960864801650304020305000440";
7263_RSASIGN_DIHEAD['md2'] = "3020300c06082a864886f70d020205000410";
7264_RSASIGN_DIHEAD['md5'] = "3020300c06082a864886f70d020505000410";
7265_RSASIGN_DIHEAD['ripemd160'] = "3021300906052b2403020105000414";
7266
7267/**
7268 * @property {Dictionary} _RSASIGN_HASHHEXFUNC
7269 * @description Array of functions which calculate hash and returns it as hexadecimal.
7270 * You can add any hash algorithm implementations.
7271 */
7272var _RSASIGN_HASHHEXFUNC = [];
7273_RSASIGN_HASHHEXFUNC['sha1'] = function(s){return hex_sha1(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
7274_RSASIGN_HASHHEXFUNC['sha256'] = function(s){return hex_sha256(s);} // http://pajhome.org.uk/crypt/md5/md5.html
7275_RSASIGN_HASHHEXFUNC['sha512'] = function(s){return hex_sha512(s);} // http://pajhome.org.uk/crypt/md5/md5.html
7276_RSASIGN_HASHHEXFUNC['md5'] = function(s){return hex_md5(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
7277_RSASIGN_HASHHEXFUNC['ripemd160'] = function(s){return hex_rmd160(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
7278
7279//@author axelcdv
7280var _RSASIGN_HASHBYTEFUNC = [];
7281_RSASIGN_HASHBYTEFUNC['sha256'] = function(byteArray){return hex_sha256_from_bytes(byteArray);};
7282
7283//_RSASIGN_HASHHEXFUNC['sha1'] = function(s){return sha1.hex(s);} // http://user1.matsumoto.ne.jp/~goma/js/hash.html
7284//_RSASIGN_HASHHEXFUNC['sha256'] = function(s){return sha256.hex;} // http://user1.matsumoto.ne.jp/~goma/js/hash.html
7285
7286var _RE_HEXDECONLY = new RegExp("");
7287_RE_HEXDECONLY.compile("[^0-9a-f]", "gi");
7288
7289// ========================================================================
7290// Signature Generation
7291// ========================================================================
7292
7293function _rsasign_getHexPaddedDigestInfoForString(s, keySize, hashAlg) {
7294 var pmStrLen = keySize / 4;
7295 var hashFunc = _RSASIGN_HASHHEXFUNC[hashAlg];
7296 var sHashHex = hashFunc(s);
7297
7298 var sHead = "0001";
7299 var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex;
7300 var sMid = "";
7301 var fLen = pmStrLen - sHead.length - sTail.length;
7302 for (var i = 0; i < fLen; i += 2) {
7303 sMid += "ff";
7304 }
7305 sPaddedMessageHex = sHead + sMid + sTail;
7306 return sPaddedMessageHex;
7307}
7308
7309
Jeff Thompson754652d2012-11-24 16:23:43 -08007310//@author: Meki Cheraoui
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07007311function _rsasign_getHexPaddedDigestInfoForStringHEX(s, keySize, hashAlg) {
7312 var pmStrLen = keySize / 4;
7313 var hashFunc = _RSASIGN_HASHHEXFUNC[hashAlg];
7314 var sHashHex = hashFunc(s);
7315
7316 var sHead = "0001";
7317 var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex;
7318 var sMid = "";
7319 var fLen = pmStrLen - sHead.length - sTail.length;
7320 for (var i = 0; i < fLen; i += 2) {
7321 sMid += "ff";
7322 }
7323 sPaddedMessageHex = sHead + sMid + sTail;
7324 return sPaddedMessageHex;
7325}
7326
7327/**
7328 * Apply padding, then computes the hash of the given byte array, according to the key size and with the hash algorithm
7329 * @param byteArray (byte[])
7330 * @param keySize (int)
7331 * @param hashAlg the hash algorithm to apply (string)
7332 * @return the hash of byteArray
7333 */
7334function _rsasign_getHexPaddedDigestInfoForByteArray(byteArray, keySize, hashAlg){
7335 var pmStrLen = keySize / 4;
7336 var hashFunc = _RSASIGN_HASHBYTEFUNC[hashAlg];
7337 var sHashHex = hashFunc(byteArray); //returns hex hash
7338
7339 var sHead = "0001";
7340 var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex;
7341 var sMid = "";
7342 var fLen = pmStrLen - sHead.length - sTail.length;
7343 for (var i = 0; i < fLen; i += 2) {
7344 sMid += "ff";
7345 }
7346 sPaddedMessageHex = sHead + sMid + sTail;
7347 return sPaddedMessageHex;
7348}
7349
7350function _zeroPaddingOfSignature(hex, bitLength) {
7351 var s = "";
7352 var nZero = bitLength / 4 - hex.length;
7353 for (var i = 0; i < nZero; i++) {
7354 s = s + "0";
7355 }
7356 return s + hex;
7357}
7358
7359/**
7360 * sign for a message string with RSA private key.<br/>
7361 * @name signString
7362 * @memberOf RSAKey#
7363 * @function
7364 * @param {String} s message string to be signed.
7365 * @param {String} hashAlg hash algorithm name for signing.<br/>
7366 * @return returns hexadecimal string of signature value.
7367 */
7368function _rsasign_signString(s, hashAlg) {
7369 //alert("this.n.bitLength() = " + this.n.bitLength());
7370 var hPM = _rsasign_getHexPaddedDigestInfoForString(s, this.n.bitLength(), hashAlg);
7371 var biPaddedMessage = parseBigInt(hPM, 16);
7372 var biSign = this.doPrivate(biPaddedMessage);
7373 var hexSign = biSign.toString(16);
7374 return _zeroPaddingOfSignature(hexSign, this.n.bitLength());
7375}
7376
7377//@author: ucla-cs
7378function _rsasign_signStringHEX(s, hashAlg) {
7379 //alert("this.n.bitLength() = " + this.n.bitLength());
7380 var hPM = _rsasign_getHexPaddedDigestInfoForString(s, this.n.bitLength(), hashAlg);
7381 var biPaddedMessage = parseBigInt(hPM, 16);
7382 var biSign = this.doPrivate(biPaddedMessage);
7383 var hexSign = biSign.toString(16);
7384 return _zeroPaddingOfSignature(hexSign, this.n.bitLength());
7385}
7386
7387
7388/**
7389 * Sign a message byteArray with an RSA private key
7390 * @name signByteArray
7391 * @memberOf RSAKey#
7392 * @function
7393 * @param {byte[]} byteArray
7394 * @param {Sring} hashAlg the hash algorithm to apply
7395 * @param {RSAKey} rsa key to sign with: hack because the context is lost here
7396 * @return hexadecimal string of signature value
7397 */
7398function _rsasign_signByteArray(byteArray, hashAlg, rsaKey) {
7399 var hPM = _rsasign_getHexPaddedDigestInfoForByteArray(byteArray, rsaKey.n.bitLength(), hashAlg); ///hack because the context is lost here
7400 var biPaddedMessage = parseBigInt(hPM, 16);
7401 var biSign = rsaKey.doPrivate(biPaddedMessage); //hack because the context is lost here
7402 var hexSign = biSign.toString(16);
7403 return _zeroPaddingOfSignature(hexSign, rsaKey.n.bitLength()); //hack because the context is lost here
7404}
7405
7406/**
7407 * Sign a byte array with the Sha-256 algorithm
7408 * @param {byte[]} byteArray
7409 * @return hexadecimal string of signature value
7410 */
7411function _rsasign_signByteArrayWithSHA256(byteArray){
7412 return _rsasign_signByteArray(byteArray, 'sha256', this); //Hack because the context is lost in the next function
7413}
7414
7415
7416function _rsasign_signStringWithSHA1(s) {
7417 return _rsasign_signString(s, 'sha1');
7418}
7419
7420function _rsasign_signStringWithSHA256(s) {
7421 return _rsasign_signString(s, 'sha256');
7422}
7423
7424// ========================================================================
7425// Signature Verification
7426// ========================================================================
7427
7428function _rsasign_getDecryptSignatureBI(biSig, hN, hE) {
7429 var rsa = new RSAKey();
7430 rsa.setPublic(hN, hE);
7431 var biDecryptedSig = rsa.doPublic(biSig);
7432 return biDecryptedSig;
7433}
7434
7435function _rsasign_getHexDigestInfoFromSig(biSig, hN, hE) {
7436 var biDecryptedSig = _rsasign_getDecryptSignatureBI(biSig, hN, hE);
7437 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
7438 return hDigestInfo;
7439}
7440
7441function _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo) {
7442 for (var algName in _RSASIGN_DIHEAD) {
7443 var head = _RSASIGN_DIHEAD[algName];
7444 var len = head.length;
7445 if (hDigestInfo.substring(0, len) == head) {
7446 var a = [algName, hDigestInfo.substring(len)];
7447 return a;
7448 }
7449 }
7450 return [];
7451}
7452
7453function _rsasign_verifySignatureWithArgs(sMsg, biSig, hN, hE) {
7454 var hDigestInfo = _rsasign_getHexDigestInfoFromSig(biSig, hN, hE);
7455 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
7456 if (digestInfoAry.length == 0) return false;
7457 var algName = digestInfoAry[0];
7458 var diHashValue = digestInfoAry[1];
7459 var ff = _RSASIGN_HASHHEXFUNC[algName];
7460 var msgHashValue = ff(sMsg);
7461 return (diHashValue == msgHashValue);
7462}
7463
7464function _rsasign_verifyHexSignatureForMessage(hSig, sMsg) {
7465 var biSig = parseBigInt(hSig, 16);
7466 var result = _rsasign_verifySignatureWithArgs(sMsg, biSig,
7467 this.n.toString(16),
7468 this.e.toString(16));
7469 return result;
7470}
7471
7472/**
7473 * verifies a sigature for a message string with RSA public key.<br/>
7474 * @name verifyString
7475 * @memberOf RSAKey#
7476 * @function
7477 * @param {String} sMsg message string to be verified.
7478 * @param {String} hSig hexadecimal string of siganture.<br/>
7479 * non-hexadecimal charactors including new lines will be ignored.
7480 * @return returns 1 if valid, otherwise 0
7481 */
7482function _rsasign_verifyString(sMsg, hSig) {
7483 hSig = hSig.replace(_RE_HEXDECONLY, '');
7484
7485 if(LOG>3)console.log('n is '+this.n);
7486 if(LOG>3)console.log('e is '+this.e);
7487
7488 if (hSig.length != this.n.bitLength() / 4) return 0;
7489 hSig = hSig.replace(/[ \n]+/g, "");
7490 var biSig = parseBigInt(hSig, 16);
7491 var biDecryptedSig = this.doPublic(biSig);
7492 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
7493 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
7494
7495 if (digestInfoAry.length == 0) return false;
7496 var algName = digestInfoAry[0];
7497 var diHashValue = digestInfoAry[1];
7498 var ff = _RSASIGN_HASHHEXFUNC[algName];
7499 var msgHashValue = ff(sMsg);
7500 return (diHashValue == msgHashValue);
7501}
7502
7503/**
7504 * verifies a sigature for a message byte array with RSA public key.<br/>
7505 * @name verifyByteArray
7506 * @memberOf RSAKey#
7507 * @function
7508 * @param {byte[]} byteArray message byte array to be verified.
7509 * @param {String} hSig hexadecimal string of signature.<br/>
7510 * non-hexadecimal charactors including new lines will be ignored.
7511 * @return returns 1 if valid, otherwise 0
7512 */
7513function _rsasign_verifyByteArray(byteArray, hSig) {
7514 hSig = hSig.replace(_RE_HEXDECONLY, '');
7515
7516 if(LOG>3)console.log('n is '+this.n);
7517 if(LOG>3)console.log('e is '+this.e);
7518
7519 if (hSig.length != this.n.bitLength() / 4) return 0;
7520 hSig = hSig.replace(/[ \n]+/g, "");
7521 var biSig = parseBigInt(hSig, 16);
7522 var biDecryptedSig = this.doPublic(biSig);
7523 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
7524 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
7525
7526 if (digestInfoAry.length == 0) return false;
7527 var algName = digestInfoAry[0];
7528 var diHashValue = digestInfoAry[1];
7529 var ff = _RSASIGN_HASHBYTEFUNC[algName];
7530 var msgHashValue = ff(byteArray);
7531 return (diHashValue == msgHashValue);
7532}
7533
7534RSAKey.prototype.signString = _rsasign_signString;
7535
7536RSAKey.prototype.signByteArray = _rsasign_signByteArray; //@author axelcdv
7537RSAKey.prototype.signByteArrayWithSHA256 = _rsasign_signByteArrayWithSHA256; //@author axelcdv
7538
7539RSAKey.prototype.signStringWithSHA1 = _rsasign_signStringWithSHA1;
7540RSAKey.prototype.signStringWithSHA256 = _rsasign_signStringWithSHA256;
7541RSAKey.prototype.sign = _rsasign_signString;
7542RSAKey.prototype.signWithSHA1 = _rsasign_signStringWithSHA1;
7543RSAKey.prototype.signWithSHA256 = _rsasign_signStringWithSHA256;
7544
7545
7546/*RSAKey.prototype.signStringHEX = _rsasign_signStringHEX;
7547RSAKey.prototype.signStringWithSHA1HEX = _rsasign_signStringWithSHA1HEX;
7548RSAKey.prototype.signStringWithSHA256HEX = _rsasign_signStringWithSHA256HEX;
7549RSAKey.prototype.signHEX = _rsasign_signStringHEX;
7550RSAKey.prototype.signWithSHA1HEX = _rsasign_signStringWithSHA1HEX;
7551RSAKey.prototype.signWithSHA256HEX = _rsasign_signStringWithSHA256HEX;
7552*/
7553
7554RSAKey.prototype.verifyByteArray = _rsasign_verifyByteArray;
7555RSAKey.prototype.verifyString = _rsasign_verifyString;
7556RSAKey.prototype.verifyHexSignatureForMessage = _rsasign_verifyHexSignatureForMessage;
7557RSAKey.prototype.verify = _rsasign_verifyString;
7558RSAKey.prototype.verifyHexSignatureForByteArrayMessage = _rsasign_verifyHexSignatureForMessage;
7559
7560/*
7561RSAKey.prototype.verifyStringHEX = _rsasign_verifyStringHEX;
7562RSAKey.prototype.verifyHexSignatureForMessageHEX = _rsasign_verifyHexSignatureForMessageHEX;
7563RSAKey.prototype.verifyHEX = _rsasign_verifyStringHEX;
7564RSAKey.prototype.verifyHexSignatureForByteArrayMessageHEX = _rsasign_verifyHexSignatureForMessageHEX;
7565*/
7566
7567
7568/**
7569 * @name RSAKey
7570 * @class
7571 * @description Tom Wu's RSA Key class and extension
7572 */
7573
7574/*! asn1hex-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
7575 */
7576//
7577// asn1hex.js - Hexadecimal represented ASN.1 string library
7578//
7579// version: 1.1 (09-May-2012)
7580//
7581// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
7582//
7583// This software is licensed under the terms of the MIT License.
7584// http://kjur.github.com/jsrsasign/license/
7585//
7586// The above copyright and license notice shall be
7587// included in all copies or substantial portions of the Software.
7588//
7589// Depends on:
7590//
7591
7592// MEMO:
7593// f('3082025b02...', 2) ... 82025b ... 3bytes
7594// f('020100', 2) ... 01 ... 1byte
7595// f('0203001...', 2) ... 03 ... 1byte
7596// f('02818003...', 2) ... 8180 ... 2bytes
7597// f('3080....0000', 2) ... 80 ... -1
7598//
7599// Requirements:
7600// - ASN.1 type octet length MUST be 1.
7601// (i.e. ASN.1 primitives like SET, SEQUENCE, INTEGER, OCTETSTRING ...)
7602// -
7603/**
7604 * get byte length for ASN.1 L(length) bytes
7605 * @name getByteLengthOfL_AtObj
7606 * @memberOf ASN1HEX
7607 * @function
7608 * @param {String} s hexadecimal string of ASN.1 DER encoded data
7609 * @param {Number} pos string index
7610 * @return byte length for ASN.1 L(length) bytes
7611 */
7612function _asnhex_getByteLengthOfL_AtObj(s, pos) {
7613 if (s.substring(pos + 2, pos + 3) != '8') return 1;
7614 var i = parseInt(s.substring(pos + 3, pos + 4));
7615 if (i == 0) return -1; // length octet '80' indefinite length
7616 if (0 < i && i < 10) return i + 1; // including '8?' octet;
7617 return -2; // malformed format
7618}
7619
7620
7621/**
7622 * get hexadecimal string for ASN.1 L(length) bytes
7623 * @name getHexOfL_AtObj
7624 * @memberOf ASN1HEX
7625 * @function
7626 * @param {String} s hexadecimal string of ASN.1 DER encoded data
7627 * @param {Number} pos string index
7628 * @return {String} hexadecimal string for ASN.1 L(length) bytes
7629 */
7630function _asnhex_getHexOfL_AtObj(s, pos) {
7631 var len = _asnhex_getByteLengthOfL_AtObj(s, pos);
7632 if (len < 1) return '';
7633 return s.substring(pos + 2, pos + 2 + len * 2);
7634}
7635
7636//
7637// getting ASN.1 length value at the position 'idx' of
7638// hexa decimal string 's'.
7639//
7640// f('3082025b02...', 0) ... 82025b ... ???
7641// f('020100', 0) ... 01 ... 1
7642// f('0203001...', 0) ... 03 ... 3
7643// f('02818003...', 0) ... 8180 ... 128
7644/**
7645 * get integer value of ASN.1 length for ASN.1 data
7646 * @name getIntOfL_AtObj
7647 * @memberOf ASN1HEX
7648 * @function
7649 * @param {String} s hexadecimal string of ASN.1 DER encoded data
7650 * @param {Number} pos string index
7651 * @return ASN.1 L(length) integer value
7652 */
7653function _asnhex_getIntOfL_AtObj(s, pos) {
7654 var hLength = _asnhex_getHexOfL_AtObj(s, pos);
7655 if (hLength == '') return -1;
7656 var bi;
7657 if (parseInt(hLength.substring(0, 1)) < 8) {
7658 bi = parseBigInt(hLength, 16);
7659 } else {
7660 bi = parseBigInt(hLength.substring(2), 16);
7661 }
7662 return bi.intValue();
7663}
7664
7665/**
7666 * get ASN.1 value starting string position for ASN.1 object refered by index 'idx'.
7667 * @name getStartPosOfV_AtObj
7668 * @memberOf ASN1HEX
7669 * @function
7670 * @param {String} s hexadecimal string of ASN.1 DER encoded data
7671 * @param {Number} pos string index
7672 */
7673function _asnhex_getStartPosOfV_AtObj(s, pos) {
7674 var l_len = _asnhex_getByteLengthOfL_AtObj(s, pos);
7675 if (l_len < 0) return l_len;
7676 return pos + (l_len + 1) * 2;
7677}
7678
7679/**
7680 * get hexadecimal string of ASN.1 V(value)
7681 * @name getHexOfV_AtObj
7682 * @memberOf ASN1HEX
7683 * @function
7684 * @param {String} s hexadecimal string of ASN.1 DER encoded data
7685 * @param {Number} pos string index
7686 * @return {String} hexadecimal string of ASN.1 value.
7687 */
7688function _asnhex_getHexOfV_AtObj(s, pos) {
7689 var pos1 = _asnhex_getStartPosOfV_AtObj(s, pos);
7690 var len = _asnhex_getIntOfL_AtObj(s, pos);
7691 return s.substring(pos1, pos1 + len * 2);
7692}
7693
7694/**
7695 * get hexadecimal string of ASN.1 TLV at
7696 * @name getHexOfTLV_AtObj
7697 * @memberOf ASN1HEX
7698 * @function
7699 * @param {String} s hexadecimal string of ASN.1 DER encoded data
7700 * @param {Number} pos string index
7701 * @return {String} hexadecimal string of ASN.1 TLV.
7702 * @since 1.1
7703 */
7704function _asnhex_getHexOfTLV_AtObj(s, pos) {
7705 var hT = s.substr(pos, 2);
7706 var hL = _asnhex_getHexOfL_AtObj(s, pos);
7707 var hV = _asnhex_getHexOfV_AtObj(s, pos);
7708 return hT + hL + hV;
7709}
7710
7711/**
7712 * get next sibling starting index for ASN.1 object string
7713 * @name getPosOfNextSibling_AtObj
7714 * @memberOf ASN1HEX
7715 * @function
7716 * @param {String} s hexadecimal string of ASN.1 DER encoded data
7717 * @param {Number} pos string index
7718 * @return next sibling starting index for ASN.1 object string
7719 */
7720function _asnhex_getPosOfNextSibling_AtObj(s, pos) {
7721 var pos1 = _asnhex_getStartPosOfV_AtObj(s, pos);
7722 var len = _asnhex_getIntOfL_AtObj(s, pos);
7723 return pos1 + len * 2;
7724}
7725
7726/**
7727 * get array of indexes of child ASN.1 objects
7728 * @name getPosArrayOfChildren_AtObj
7729 * @memberOf ASN1HEX
7730 * @function
7731 * @param {String} s hexadecimal string of ASN.1 DER encoded data
7732 * @param {Number} start string index of ASN.1 object
7733 * @return {Array of Number} array of indexes for childen of ASN.1 objects
7734 */
7735function _asnhex_getPosArrayOfChildren_AtObj(h, pos) {
7736 var a = new Array();
7737 var p0 = _asnhex_getStartPosOfV_AtObj(h, pos);
7738 a.push(p0);
7739
7740 var len = _asnhex_getIntOfL_AtObj(h, pos);
7741 var p = p0;
7742 var k = 0;
7743 while (1) {
7744 var pNext = _asnhex_getPosOfNextSibling_AtObj(h, p);
7745 if (pNext == null || (pNext - p0 >= (len * 2))) break;
7746 if (k >= 200) break;
7747
7748 a.push(pNext);
7749 p = pNext;
7750
7751 k++;
7752 }
7753
7754 return a;
7755}
7756
7757/**
7758 * get string index of nth child object of ASN.1 object refered by h, idx
7759 * @name getNthChildIndex_AtObj
7760 * @memberOf ASN1HEX
7761 * @function
7762 * @param {String} h hexadecimal string of ASN.1 DER encoded data
7763 * @param {Number} idx start string index of ASN.1 object
7764 * @param {Number} nth for child
7765 * @return {Number} string index of nth child.
7766 * @since 1.1
7767 */
7768function _asnhex_getNthChildIndex_AtObj(h, idx, nth) {
7769 var a = _asnhex_getPosArrayOfChildren_AtObj(h, idx);
7770 return a[nth];
7771}
7772
7773// ========== decendant methods ==============================
7774
7775/**
7776 * get string index of nth child object of ASN.1 object refered by h, idx
7777 * @name getDecendantIndexByNthList
7778 * @memberOf ASN1HEX
7779 * @function
7780 * @param {String} h hexadecimal string of ASN.1 DER encoded data
7781 * @param {Number} currentIndex start string index of ASN.1 object
7782 * @param {Array of Number} nthList array list of nth
7783 * @return {Number} string index refered by nthList
7784 * @since 1.1
7785 */
7786function _asnhex_getDecendantIndexByNthList(h, currentIndex, nthList) {
7787 if (nthList.length == 0) {
7788 return currentIndex;
7789 }
7790 var firstNth = nthList.shift();
7791 var a = _asnhex_getPosArrayOfChildren_AtObj(h, currentIndex);
7792 return _asnhex_getDecendantIndexByNthList(h, a[firstNth], nthList);
7793}
7794
7795/**
7796 * get hexadecimal string of ASN.1 TLV refered by current index and nth index list.
7797 * @name getDecendantHexTLVByNthList
7798 * @memberOf ASN1HEX
7799 * @function
7800 * @param {String} h hexadecimal string of ASN.1 DER encoded data
7801 * @param {Number} currentIndex start string index of ASN.1 object
7802 * @param {Array of Number} nthList array list of nth
7803 * @return {Number} hexadecimal string of ASN.1 TLV refered by nthList
7804 * @since 1.1
7805 */
7806function _asnhex_getDecendantHexTLVByNthList(h, currentIndex, nthList) {
7807 var idx = _asnhex_getDecendantIndexByNthList(h, currentIndex, nthList);
7808 return _asnhex_getHexOfTLV_AtObj(h, idx);
7809}
7810
7811/**
7812 * get hexadecimal string of ASN.1 V refered by current index and nth index list.
7813 * @name getDecendantHexVByNthList
7814 * @memberOf ASN1HEX
7815 * @function
7816 * @param {String} h hexadecimal string of ASN.1 DER encoded data
7817 * @param {Number} currentIndex start string index of ASN.1 object
7818 * @param {Array of Number} nthList array list of nth
7819 * @return {Number} hexadecimal string of ASN.1 V refered by nthList
7820 * @since 1.1
7821 */
7822function _asnhex_getDecendantHexVByNthList(h, currentIndex, nthList) {
7823 var idx = _asnhex_getDecendantIndexByNthList(h, currentIndex, nthList);
7824 return _asnhex_getHexOfV_AtObj(h, idx);
7825}
7826
7827// ========== class definition ==============================
7828
7829/**
7830 * ASN.1 DER encoded hexadecimal string utility class
7831 * @class ASN.1 DER encoded hexadecimal string utility class
7832 * @author Kenji Urushima
7833 * @version 1.1 (09 May 2012)
7834 * @see <a href="http://kjur.github.com/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a>
7835 * @since 1.1
7836 */
7837function ASN1HEX() {
7838 return ASN1HEX;
7839}
7840
7841ASN1HEX.getByteLengthOfL_AtObj = _asnhex_getByteLengthOfL_AtObj;
7842ASN1HEX.getHexOfL_AtObj = _asnhex_getHexOfL_AtObj;
7843ASN1HEX.getIntOfL_AtObj = _asnhex_getIntOfL_AtObj;
7844ASN1HEX.getStartPosOfV_AtObj = _asnhex_getStartPosOfV_AtObj;
7845ASN1HEX.getHexOfV_AtObj = _asnhex_getHexOfV_AtObj;
7846ASN1HEX.getHexOfTLV_AtObj = _asnhex_getHexOfTLV_AtObj;
7847ASN1HEX.getPosOfNextSibling_AtObj = _asnhex_getPosOfNextSibling_AtObj;
7848ASN1HEX.getPosArrayOfChildren_AtObj = _asnhex_getPosArrayOfChildren_AtObj;
7849ASN1HEX.getNthChildIndex_AtObj = _asnhex_getNthChildIndex_AtObj;
7850ASN1HEX.getDecendantIndexByNthList = _asnhex_getDecendantIndexByNthList;
7851ASN1HEX.getDecendantHexVByNthList = _asnhex_getDecendantHexVByNthList;
7852ASN1HEX.getDecendantHexTLVByNthList = _asnhex_getDecendantHexTLVByNthList;
7853
7854/*! x509-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
7855 */
7856//
7857// x509.js - X509 class to read subject public key from certificate.
7858//
7859// version: 1.1 (10-May-2012)
7860//
7861// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
7862//
7863// This software is licensed under the terms of the MIT License.
7864// http://kjur.github.com/jsrsasign/license
7865//
7866// The above copyright and license notice shall be
7867// included in all copies or substantial portions of the Software.
7868//
7869
7870// Depends:
7871// base64.js
7872// rsa.js
7873// asn1hex.js
7874
7875function _x509_pemToBase64(sCertPEM) {
7876 var s = sCertPEM;
7877 s = s.replace("-----BEGIN CERTIFICATE-----", "");
7878 s = s.replace("-----END CERTIFICATE-----", "");
7879 s = s.replace(/[ \n]+/g, "");
7880 return s;
7881}
7882
7883function _x509_pemToHex(sCertPEM) {
7884 var b64Cert = _x509_pemToBase64(sCertPEM);
7885 var hCert = b64tohex(b64Cert);
7886 return hCert;
7887}
7888
7889function _x509_getHexTbsCertificateFromCert(hCert) {
7890 var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0);
7891 return pTbsCert;
7892}
7893
7894// NOTE: privateKeyUsagePeriod field of X509v2 not supported.
7895// NOTE: v1 and v3 supported
7896function _x509_getSubjectPublicKeyInfoPosFromCertHex(hCert) {
7897 var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0);
7898 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pTbsCert);
7899 if (a.length < 1) return -1;
7900 if (hCert.substring(a[0], a[0] + 10) == "a003020102") { // v3
7901 if (a.length < 6) return -1;
7902 return a[6];
7903 } else {
7904 if (a.length < 5) return -1;
7905 return a[5];
7906 }
7907}
7908
7909// NOTE: Without BITSTRING encapsulation.
7910function _x509_getSubjectPublicKeyPosFromCertHex(hCert) {
7911 var pInfo = _x509_getSubjectPublicKeyInfoPosFromCertHex(hCert);
7912 if (pInfo == -1) return -1;
7913 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pInfo);
7914
7915 if (a.length != 2) return -1;
7916 var pBitString = a[1];
7917 if (hCert.substring(pBitString, pBitString + 2) != '03') return -1;
7918 var pBitStringV = ASN1HEX.getStartPosOfV_AtObj(hCert, pBitString);
7919
7920 if (hCert.substring(pBitStringV, pBitStringV + 2) != '00') return -1;
7921 return pBitStringV + 2;
7922}
7923
7924function _x509_getPublicKeyHexArrayFromCertHex(hCert) {
7925 var p = _x509_getSubjectPublicKeyPosFromCertHex(hCert);
7926 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, p);
7927 //var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a[3]);
7928 if(LOG>4){
7929 console.log('a is now');
7930 console.log(a);
7931 }
7932
7933 //if (a.length != 2) return [];
7934 if (a.length < 2) return [];
7935
7936 var hN = ASN1HEX.getHexOfV_AtObj(hCert, a[0]);
7937 var hE = ASN1HEX.getHexOfV_AtObj(hCert, a[1]);
7938 if (hN != null && hE != null) {
7939 return [hN, hE];
7940 } else {
7941 return [];
7942 }
7943}
7944
7945function _x509_getPublicKeyHexArrayFromCertPEM(sCertPEM) {
7946 var hCert = _x509_pemToHex(sCertPEM);
7947 var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
7948 return a;
7949}
7950
7951// ===== get basic fields from hex =====================================
7952/**
7953 * get hexadecimal string of serialNumber field of certificate.<br/>
7954 * @name getSerialNumberHex
7955 * @memberOf X509#
7956 * @function
7957 */
7958function _x509_getSerialNumberHex() {
7959 return ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 1]);
7960}
7961
7962/**
7963 * get hexadecimal string of issuer field of certificate.<br/>
7964 * @name getIssuerHex
7965 * @memberOf X509#
7966 * @function
7967 */
7968function _x509_getIssuerHex() {
7969 return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]);
7970}
7971
7972/**
7973 * get string of issuer field of certificate.<br/>
7974 * @name getIssuerString
7975 * @memberOf X509#
7976 * @function
7977 */
7978function _x509_getIssuerString() {
7979 return _x509_hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]));
7980}
7981
7982/**
7983 * get hexadecimal string of subject field of certificate.<br/>
7984 * @name getSubjectHex
7985 * @memberOf X509#
7986 * @function
7987 */
7988function _x509_getSubjectHex() {
7989 return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]);
7990}
7991
7992/**
7993 * get string of subject field of certificate.<br/>
7994 * @name getSubjectString
7995 * @memberOf X509#
7996 * @function
7997 */
7998function _x509_getSubjectString() {
7999 return _x509_hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]));
8000}
8001
8002/**
8003 * get notBefore field string of certificate.<br/>
8004 * @name getNotBefore
8005 * @memberOf X509#
8006 * @function
8007 */
8008function _x509_getNotBefore() {
8009 var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 0]);
8010 s = s.replace(/(..)/g, "%$1");
8011 s = decodeURIComponent(s);
8012 return s;
8013}
8014
8015/**
8016 * get notAfter field string of certificate.<br/>
8017 * @name getNotAfter
8018 * @memberOf X509#
8019 * @function
8020 */
8021function _x509_getNotAfter() {
8022 var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 1]);
8023 s = s.replace(/(..)/g, "%$1");
8024 s = decodeURIComponent(s);
8025 return s;
8026}
8027
8028// ===== read certificate =====================================
8029
8030_x509_DN_ATTRHEX = {
8031 "0603550406": "C",
8032 "060355040a": "O",
8033 "060355040b": "OU",
8034 "0603550403": "CN",
8035 "0603550405": "SN",
8036 "0603550408": "ST",
8037 "0603550407": "L" };
8038
8039function _x509_hex2dn(hDN) {
8040 var s = "";
8041 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hDN, 0);
8042 for (var i = 0; i < a.length; i++) {
8043 var hRDN = ASN1HEX.getHexOfTLV_AtObj(hDN, a[i]);
8044 s = s + "/" + _x509_hex2rdn(hRDN);
8045 }
8046 return s;
8047}
8048
8049function _x509_hex2rdn(hRDN) {
8050 var hType = ASN1HEX.getDecendantHexTLVByNthList(hRDN, 0, [0, 0]);
8051 var hValue = ASN1HEX.getDecendantHexVByNthList(hRDN, 0, [0, 1]);
8052 var type = "";
8053 try { type = _x509_DN_ATTRHEX[hType]; } catch (ex) { type = hType; }
8054 hValue = hValue.replace(/(..)/g, "%$1");
8055 var value = decodeURIComponent(hValue);
8056 return type + "=" + value;
8057}
8058
8059// ===== read certificate =====================================
8060
8061
8062/**
8063 * read PEM formatted X.509 certificate from string.<br/>
8064 * @name readCertPEM
8065 * @memberOf X509#
8066 * @function
8067 * @param {String} sCertPEM string for PEM formatted X.509 certificate
8068 */
8069function _x509_readCertPEM(sCertPEM) {
8070 var hCert = _x509_pemToHex(sCertPEM);
8071 var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
8072 if(LOG>4){
8073 console.log('HEX VALUE IS ' + hCert);
8074 console.log('type of a' + typeof a);
8075 console.log('a VALUE IS ');
8076 console.log(a);
8077 console.log('a[0] VALUE IS ' + a[0]);
8078 console.log('a[1] VALUE IS ' + a[1]);
8079 }
8080 var rsa = new RSAKey();
8081 rsa.setPublic(a[0], a[1]);
8082 this.subjectPublicKeyRSA = rsa;
8083 this.subjectPublicKeyRSA_hN = a[0];
8084 this.subjectPublicKeyRSA_hE = a[1];
8085 this.hex = hCert;
8086}
8087
8088function _x509_readCertPEMWithoutRSAInit(sCertPEM) {
8089 var hCert = _x509_pemToHex(sCertPEM);
8090 var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
8091 this.subjectPublicKeyRSA.setPublic(a[0], a[1]);
8092 this.subjectPublicKeyRSA_hN = a[0];
8093 this.subjectPublicKeyRSA_hE = a[1];
8094 this.hex = hCert;
8095}
8096
8097/**
8098 * X.509 certificate class.<br/>
8099 * @class X.509 certificate class
8100 * @property {RSAKey} subjectPublicKeyRSA Tom Wu's RSAKey object
8101 * @property {String} subjectPublicKeyRSA_hN hexadecimal string for modulus of RSA public key
8102 * @property {String} subjectPublicKeyRSA_hE hexadecimal string for public exponent of RSA public key
8103 * @property {String} hex hexacedimal string for X.509 certificate.
8104 * @author Kenji Urushima
8105 * @version 1.0.1 (08 May 2012)
8106 * @see <a href="http://kjur.github.com/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a>
8107 */
8108function X509() {
8109 this.subjectPublicKeyRSA = null;
8110 this.subjectPublicKeyRSA_hN = null;
8111 this.subjectPublicKeyRSA_hE = null;
8112 this.hex = null;
8113}
8114
8115X509.prototype.readCertPEM = _x509_readCertPEM;
8116X509.prototype.readCertPEMWithoutRSAInit = _x509_readCertPEMWithoutRSAInit;
8117X509.prototype.getSerialNumberHex = _x509_getSerialNumberHex;
8118X509.prototype.getIssuerHex = _x509_getIssuerHex;
8119X509.prototype.getSubjectHex = _x509_getSubjectHex;
8120X509.prototype.getIssuerString = _x509_getIssuerString;
8121X509.prototype.getSubjectString = _x509_getSubjectString;
8122X509.prototype.getNotBefore = _x509_getNotBefore;
8123X509.prototype.getNotAfter = _x509_getNotAfter;
8124
8125
8126// Copyright (c) 2005 Tom Wu
8127// All Rights Reserved.
8128// See "LICENSE" for details.
8129
8130// Basic JavaScript BN library - subset useful for RSA encryption.
8131
8132// Bits per digit
8133var dbits;
8134
8135// JavaScript engine analysis
8136var canary = 0xdeadbeefcafe;
8137var j_lm = ((canary&0xffffff)==0xefcafe);
8138
8139// (public) Constructor
8140function BigInteger(a,b,c) {
8141 if(a != null)
8142 if("number" == typeof a) this.fromNumber(a,b,c);
8143 else if(b == null && "string" != typeof a) this.fromString(a,256);
8144 else this.fromString(a,b);
8145}
8146
8147// return new, unset BigInteger
8148function nbi() { return new BigInteger(null); }
8149
8150// am: Compute w_j += (x*this_i), propagate carries,
8151// c is initial carry, returns final carry.
8152// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
8153// We need to select the fastest one that works in this environment.
8154
8155// am1: use a single mult and divide to get the high bits,
8156// max digit bits should be 26 because
8157// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
8158function am1(i,x,w,j,c,n) {
8159 while(--n >= 0) {
8160 var v = x*this[i++]+w[j]+c;
8161 c = Math.floor(v/0x4000000);
8162 w[j++] = v&0x3ffffff;
8163 }
8164 return c;
8165}
8166// am2 avoids a big mult-and-extract completely.
8167// Max digit bits should be <= 30 because we do bitwise ops
8168// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
8169function am2(i,x,w,j,c,n) {
8170 var xl = x&0x7fff, xh = x>>15;
8171 while(--n >= 0) {
8172 var l = this[i]&0x7fff;
8173 var h = this[i++]>>15;
8174 var m = xh*l+h*xl;
8175 l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff);
8176 c = (l>>>30)+(m>>>15)+xh*h+(c>>>30);
8177 w[j++] = l&0x3fffffff;
8178 }
8179 return c;
8180}
8181// Alternately, set max digit bits to 28 since some
8182// browsers slow down when dealing with 32-bit numbers.
8183function am3(i,x,w,j,c,n) {
8184 var xl = x&0x3fff, xh = x>>14;
8185 while(--n >= 0) {
8186 var l = this[i]&0x3fff;
8187 var h = this[i++]>>14;
8188 var m = xh*l+h*xl;
8189 l = xl*l+((m&0x3fff)<<14)+w[j]+c;
8190 c = (l>>28)+(m>>14)+xh*h;
8191 w[j++] = l&0xfffffff;
8192 }
8193 return c;
8194}
8195if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
8196 BigInteger.prototype.am = am2;
8197 dbits = 30;
8198}
8199else if(j_lm && (navigator.appName != "Netscape")) {
8200 BigInteger.prototype.am = am1;
8201 dbits = 26;
8202}
8203else { // Mozilla/Netscape seems to prefer am3
8204 BigInteger.prototype.am = am3;
8205 dbits = 28;
8206}
8207
8208BigInteger.prototype.DB = dbits;
8209BigInteger.prototype.DM = ((1<<dbits)-1);
8210BigInteger.prototype.DV = (1<<dbits);
8211
8212var BI_FP = 52;
8213BigInteger.prototype.FV = Math.pow(2,BI_FP);
8214BigInteger.prototype.F1 = BI_FP-dbits;
8215BigInteger.prototype.F2 = 2*dbits-BI_FP;
8216
8217// Digit conversions
8218var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
8219var BI_RC = new Array();
8220var rr,vv;
8221rr = "0".charCodeAt(0);
8222for(vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
8223rr = "a".charCodeAt(0);
8224for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
8225rr = "A".charCodeAt(0);
8226for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
8227
8228function int2char(n) { return BI_RM.charAt(n); }
8229function intAt(s,i) {
8230 var c = BI_RC[s.charCodeAt(i)];
8231 return (c==null)?-1:c;
8232}
8233
8234// (protected) copy this to r
8235function bnpCopyTo(r) {
8236 for(var i = this.t-1; i >= 0; --i) r[i] = this[i];
8237 r.t = this.t;
8238 r.s = this.s;
8239}
8240
8241// (protected) set from integer value x, -DV <= x < DV
8242function bnpFromInt(x) {
8243 this.t = 1;
8244 this.s = (x<0)?-1:0;
8245 if(x > 0) this[0] = x;
8246 else if(x < -1) this[0] = x+DV;
8247 else this.t = 0;
8248}
8249
8250// return bigint initialized to value
8251function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
8252
8253// (protected) set from string and radix
8254function bnpFromString(s,b) {
8255 var k;
8256 if(b == 16) k = 4;
8257 else if(b == 8) k = 3;
8258 else if(b == 256) k = 8; // byte array
8259 else if(b == 2) k = 1;
8260 else if(b == 32) k = 5;
8261 else if(b == 4) k = 2;
8262 else { this.fromRadix(s,b); return; }
8263 this.t = 0;
8264 this.s = 0;
8265 var i = s.length, mi = false, sh = 0;
8266 while(--i >= 0) {
8267 var x = (k==8)?s[i]&0xff:intAt(s,i);
8268 if(x < 0) {
8269 if(s.charAt(i) == "-") mi = true;
8270 continue;
8271 }
8272 mi = false;
8273 if(sh == 0)
8274 this[this.t++] = x;
8275 else if(sh+k > this.DB) {
8276 this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<<sh;
8277 this[this.t++] = (x>>(this.DB-sh));
8278 }
8279 else
8280 this[this.t-1] |= x<<sh;
8281 sh += k;
8282 if(sh >= this.DB) sh -= this.DB;
8283 }
8284 if(k == 8 && (s[0]&0x80) != 0) {
8285 this.s = -1;
8286 if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh;
8287 }
8288 this.clamp();
8289 if(mi) BigInteger.ZERO.subTo(this,this);
8290}
8291
8292// (protected) clamp off excess high words
8293function bnpClamp() {
8294 var c = this.s&this.DM;
8295 while(this.t > 0 && this[this.t-1] == c) --this.t;
8296}
8297
8298// (public) return string representation in given radix
8299function bnToString(b) {
8300 if(this.s < 0) return "-"+this.negate().toString(b);
8301 var k;
8302 if(b == 16) k = 4;
8303 else if(b == 8) k = 3;
8304 else if(b == 2) k = 1;
8305 else if(b == 32) k = 5;
8306 else if(b == 4) k = 2;
8307 else return this.toRadix(b);
8308 var km = (1<<k)-1, d, m = false, r = "", i = this.t;
8309 var p = this.DB-(i*this.DB)%k;
8310 if(i-- > 0) {
8311 if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); }
8312 while(i >= 0) {
8313 if(p < k) {
8314 d = (this[i]&((1<<p)-1))<<(k-p);
8315 d |= this[--i]>>(p+=this.DB-k);
8316 }
8317 else {
8318 d = (this[i]>>(p-=k))&km;
8319 if(p <= 0) { p += this.DB; --i; }
8320 }
8321 if(d > 0) m = true;
8322 if(m) r += int2char(d);
8323 }
8324 }
8325 return m?r:"0";
8326}
8327
8328// (public) -this
8329function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }
8330
8331// (public) |this|
8332function bnAbs() { return (this.s<0)?this.negate():this; }
8333
8334// (public) return + if this > a, - if this < a, 0 if equal
8335function bnCompareTo(a) {
8336 var r = this.s-a.s;
8337 if(r != 0) return r;
8338 var i = this.t;
8339 r = i-a.t;
8340 if(r != 0) return r;
8341 while(--i >= 0) if((r=this[i]-a[i]) != 0) return r;
8342 return 0;
8343}
8344
8345// returns bit length of the integer x
8346function nbits(x) {
8347 var r = 1, t;
8348 if((t=x>>>16) != 0) { x = t; r += 16; }
8349 if((t=x>>8) != 0) { x = t; r += 8; }
8350 if((t=x>>4) != 0) { x = t; r += 4; }
8351 if((t=x>>2) != 0) { x = t; r += 2; }
8352 if((t=x>>1) != 0) { x = t; r += 1; }
8353 return r;
8354}
8355
8356// (public) return the number of bits in "this"
8357function bnBitLength() {
8358 if(this.t <= 0) return 0;
8359 return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM));
8360}
8361
8362// (protected) r = this << n*DB
8363function bnpDLShiftTo(n,r) {
8364 var i;
8365 for(i = this.t-1; i >= 0; --i) r[i+n] = this[i];
8366 for(i = n-1; i >= 0; --i) r[i] = 0;
8367 r.t = this.t+n;
8368 r.s = this.s;
8369}
8370
8371// (protected) r = this >> n*DB
8372function bnpDRShiftTo(n,r) {
8373 for(var i = n; i < this.t; ++i) r[i-n] = this[i];
8374 r.t = Math.max(this.t-n,0);
8375 r.s = this.s;
8376}
8377
8378// (protected) r = this << n
8379function bnpLShiftTo(n,r) {
8380 var bs = n%this.DB;
8381 var cbs = this.DB-bs;
8382 var bm = (1<<cbs)-1;
8383 var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i;
8384 for(i = this.t-1; i >= 0; --i) {
8385 r[i+ds+1] = (this[i]>>cbs)|c;
8386 c = (this[i]&bm)<<bs;
8387 }
8388 for(i = ds-1; i >= 0; --i) r[i] = 0;
8389 r[ds] = c;
8390 r.t = this.t+ds+1;
8391 r.s = this.s;
8392 r.clamp();
8393}
8394
8395// (protected) r = this >> n
8396function bnpRShiftTo(n,r) {
8397 r.s = this.s;
8398 var ds = Math.floor(n/this.DB);
8399 if(ds >= this.t) { r.t = 0; return; }
8400 var bs = n%this.DB;
8401 var cbs = this.DB-bs;
8402 var bm = (1<<bs)-1;
8403 r[0] = this[ds]>>bs;
8404 for(var i = ds+1; i < this.t; ++i) {
8405 r[i-ds-1] |= (this[i]&bm)<<cbs;
8406 r[i-ds] = this[i]>>bs;
8407 }
8408 if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs;
8409 r.t = this.t-ds;
8410 r.clamp();
8411}
8412
8413// (protected) r = this - a
8414function bnpSubTo(a,r) {
8415 var i = 0, c = 0, m = Math.min(a.t,this.t);
8416 while(i < m) {
8417 c += this[i]-a[i];
8418 r[i++] = c&this.DM;
8419 c >>= this.DB;
8420 }
8421 if(a.t < this.t) {
8422 c -= a.s;
8423 while(i < this.t) {
8424 c += this[i];
8425 r[i++] = c&this.DM;
8426 c >>= this.DB;
8427 }
8428 c += this.s;
8429 }
8430 else {
8431 c += this.s;
8432 while(i < a.t) {
8433 c -= a[i];
8434 r[i++] = c&this.DM;
8435 c >>= this.DB;
8436 }
8437 c -= a.s;
8438 }
8439 r.s = (c<0)?-1:0;
8440 if(c < -1) r[i++] = this.DV+c;
8441 else if(c > 0) r[i++] = c;
8442 r.t = i;
8443 r.clamp();
8444}
8445
8446// (protected) r = this * a, r != this,a (HAC 14.12)
8447// "this" should be the larger one if appropriate.
8448function bnpMultiplyTo(a,r) {
8449 var x = this.abs(), y = a.abs();
8450 var i = x.t;
8451 r.t = i+y.t;
8452 while(--i >= 0) r[i] = 0;
8453 for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t);
8454 r.s = 0;
8455 r.clamp();
8456 if(this.s != a.s) BigInteger.ZERO.subTo(r,r);
8457}
8458
8459// (protected) r = this^2, r != this (HAC 14.16)
8460function bnpSquareTo(r) {
8461 var x = this.abs();
8462 var i = r.t = 2*x.t;
8463 while(--i >= 0) r[i] = 0;
8464 for(i = 0; i < x.t-1; ++i) {
8465 var c = x.am(i,x[i],r,2*i,0,1);
8466 if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) {
8467 r[i+x.t] -= x.DV;
8468 r[i+x.t+1] = 1;
8469 }
8470 }
8471 if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1);
8472 r.s = 0;
8473 r.clamp();
8474}
8475
8476// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
8477// r != q, this != m. q or r may be null.
8478function bnpDivRemTo(m,q,r) {
8479 var pm = m.abs();
8480 if(pm.t <= 0) return;
8481 var pt = this.abs();
8482 if(pt.t < pm.t) {
8483 if(q != null) q.fromInt(0);
8484 if(r != null) this.copyTo(r);
8485 return;
8486 }
8487 if(r == null) r = nbi();
8488 var y = nbi(), ts = this.s, ms = m.s;
8489 var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus
8490 if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); }
8491 else { pm.copyTo(y); pt.copyTo(r); }
8492 var ys = y.t;
8493 var y0 = y[ys-1];
8494 if(y0 == 0) return;
8495 var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0);
8496 var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
8497 var i = r.t, j = i-ys, t = (q==null)?nbi():q;
8498 y.dlShiftTo(j,t);
8499 if(r.compareTo(t) >= 0) {
8500 r[r.t++] = 1;
8501 r.subTo(t,r);
8502 }
8503 BigInteger.ONE.dlShiftTo(ys,t);
8504 t.subTo(y,y); // "negative" y so we can replace sub with am later
8505 while(y.t < ys) y[y.t++] = 0;
8506 while(--j >= 0) {
8507 // Estimate quotient digit
8508 var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);
8509 if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out
8510 y.dlShiftTo(j,t);
8511 r.subTo(t,r);
8512 while(r[i] < --qd) r.subTo(t,r);
8513 }
8514 }
8515 if(q != null) {
8516 r.drShiftTo(ys,q);
8517 if(ts != ms) BigInteger.ZERO.subTo(q,q);
8518 }
8519 r.t = ys;
8520 r.clamp();
8521 if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder
8522 if(ts < 0) BigInteger.ZERO.subTo(r,r);
8523}
8524
8525// (public) this mod a
8526function bnMod(a) {
8527 var r = nbi();
8528 this.abs().divRemTo(a,null,r);
8529 if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r);
8530 return r;
8531}
8532
8533// Modular reduction using "classic" algorithm
8534function Classic(m) { this.m = m; }
8535function cConvert(x) {
8536 if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
8537 else return x;
8538}
8539function cRevert(x) { return x; }
8540function cReduce(x) { x.divRemTo(this.m,null,x); }
8541function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
8542function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
8543
8544Classic.prototype.convert = cConvert;
8545Classic.prototype.revert = cRevert;
8546Classic.prototype.reduce = cReduce;
8547Classic.prototype.mulTo = cMulTo;
8548Classic.prototype.sqrTo = cSqrTo;
8549
8550// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
8551// justification:
8552// xy == 1 (mod m)
8553// xy = 1+km
8554// xy(2-xy) = (1+km)(1-km)
8555// x[y(2-xy)] = 1-k^2m^2
8556// x[y(2-xy)] == 1 (mod m^2)
8557// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
8558// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
8559// JS multiply "overflows" differently from C/C++, so care is needed here.
8560function bnpInvDigit() {
8561 if(this.t < 1) return 0;
8562 var x = this[0];
8563 if((x&1) == 0) return 0;
8564 var y = x&3; // y == 1/x mod 2^2
8565 y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4
8566 y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8
8567 y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16
8568 // last step - calculate inverse mod DV directly;
8569 // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
8570 y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits
8571 // we really want the negative inverse, and -DV < y < DV
8572 return (y>0)?this.DV-y:-y;
8573}
8574
8575// Montgomery reduction
8576function Montgomery(m) {
8577 this.m = m;
8578 this.mp = m.invDigit();
8579 this.mpl = this.mp&0x7fff;
8580 this.mph = this.mp>>15;
8581 this.um = (1<<(m.DB-15))-1;
8582 this.mt2 = 2*m.t;
8583}
8584
8585// xR mod m
8586function montConvert(x) {
8587 var r = nbi();
8588 x.abs().dlShiftTo(this.m.t,r);
8589 r.divRemTo(this.m,null,r);
8590 if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r);
8591 return r;
8592}
8593
8594// x/R mod m
8595function montRevert(x) {
8596 var r = nbi();
8597 x.copyTo(r);
8598 this.reduce(r);
8599 return r;
8600}
8601
8602// x = x/R mod m (HAC 14.32)
8603function montReduce(x) {
8604 while(x.t <= this.mt2) // pad x so am has enough room later
8605 x[x.t++] = 0;
8606 for(var i = 0; i < this.m.t; ++i) {
8607 // faster way of calculating u0 = x[i]*mp mod DV
8608 var j = x[i]&0x7fff;
8609 var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM;
8610 // use am to combine the multiply-shift-add into one call
8611 j = i+this.m.t;
8612 x[j] += this.m.am(0,u0,x,i,0,this.m.t);
8613 // propagate carry
8614 while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; }
8615 }
8616 x.clamp();
8617 x.drShiftTo(this.m.t,x);
8618 if(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
8619}
8620
8621// r = "x^2/R mod m"; x != r
8622function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
8623
8624// r = "xy/R mod m"; x,y != r
8625function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
8626
8627Montgomery.prototype.convert = montConvert;
8628Montgomery.prototype.revert = montRevert;
8629Montgomery.prototype.reduce = montReduce;
8630Montgomery.prototype.mulTo = montMulTo;
8631Montgomery.prototype.sqrTo = montSqrTo;
8632
8633// (protected) true iff this is even
8634function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; }
8635
8636// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
8637function bnpExp(e,z) {
8638 if(e > 0xffffffff || e < 1) return BigInteger.ONE;
8639 var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1;
8640 g.copyTo(r);
8641 while(--i >= 0) {
8642 z.sqrTo(r,r2);
8643 if((e&(1<<i)) > 0) z.mulTo(r2,g,r);
8644 else { var t = r; r = r2; r2 = t; }
8645 }
8646 return z.revert(r);
8647}
8648
8649// (public) this^e % m, 0 <= e < 2^32
8650function bnModPowInt(e,m) {
8651 var z;
8652 if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
8653 return this.exp(e,z);
8654}
8655
8656// protected
8657BigInteger.prototype.copyTo = bnpCopyTo;
8658BigInteger.prototype.fromInt = bnpFromInt;
8659BigInteger.prototype.fromString = bnpFromString;
8660BigInteger.prototype.clamp = bnpClamp;
8661BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
8662BigInteger.prototype.drShiftTo = bnpDRShiftTo;
8663BigInteger.prototype.lShiftTo = bnpLShiftTo;
8664BigInteger.prototype.rShiftTo = bnpRShiftTo;
8665BigInteger.prototype.subTo = bnpSubTo;
8666BigInteger.prototype.multiplyTo = bnpMultiplyTo;
8667BigInteger.prototype.squareTo = bnpSquareTo;
8668BigInteger.prototype.divRemTo = bnpDivRemTo;
8669BigInteger.prototype.invDigit = bnpInvDigit;
8670BigInteger.prototype.isEven = bnpIsEven;
8671BigInteger.prototype.exp = bnpExp;
8672
8673// public
8674BigInteger.prototype.toString = bnToString;
8675BigInteger.prototype.negate = bnNegate;
8676BigInteger.prototype.abs = bnAbs;
8677BigInteger.prototype.compareTo = bnCompareTo;
8678BigInteger.prototype.bitLength = bnBitLength;
8679BigInteger.prototype.mod = bnMod;
8680BigInteger.prototype.modPowInt = bnModPowInt;
8681
8682// "constants"
8683BigInteger.ZERO = nbv(0);
8684BigInteger.ONE = nbv(1);
8685
8686// Copyright (c) 2005-2009 Tom Wu
8687// All Rights Reserved.
8688// See "LICENSE" for details.
8689
8690// Extended JavaScript BN functions, required for RSA private ops.
8691
8692// Version 1.1: new BigInteger("0", 10) returns "proper" zero
8693
8694// (public)
8695function bnClone() { var r = nbi(); this.copyTo(r); return r; }
8696
8697// (public) return value as integer
8698function bnIntValue() {
8699 if(this.s < 0) {
8700 if(this.t == 1) return this[0]-this.DV;
8701 else if(this.t == 0) return -1;
8702 }
8703 else if(this.t == 1) return this[0];
8704 else if(this.t == 0) return 0;
8705 // assumes 16 < DB < 32
8706 return ((this[1]&((1<<(32-this.DB))-1))<<this.DB)|this[0];
8707}
8708
8709// (public) return value as byte
8710function bnByteValue() { return (this.t==0)?this.s:(this[0]<<24)>>24; }
8711
8712// (public) return value as short (assumes DB>=16)
8713function bnShortValue() { return (this.t==0)?this.s:(this[0]<<16)>>16; }
8714
8715// (protected) return x s.t. r^x < DV
8716function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); }
8717
8718// (public) 0 if this == 0, 1 if this > 0
8719function bnSigNum() {
8720 if(this.s < 0) return -1;
8721 else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
8722 else return 1;
8723}
8724
8725// (protected) convert to radix string
8726function bnpToRadix(b) {
8727 if(b == null) b = 10;
8728 if(this.signum() == 0 || b < 2 || b > 36) return "0";
8729 var cs = this.chunkSize(b);
8730 var a = Math.pow(b,cs);
8731 var d = nbv(a), y = nbi(), z = nbi(), r = "";
8732 this.divRemTo(d,y,z);
8733 while(y.signum() > 0) {
8734 r = (a+z.intValue()).toString(b).substr(1) + r;
8735 y.divRemTo(d,y,z);
8736 }
8737 return z.intValue().toString(b) + r;
8738}
8739
8740// (protected) convert from radix string
8741function bnpFromRadix(s,b) {
8742 this.fromInt(0);
8743 if(b == null) b = 10;
8744 var cs = this.chunkSize(b);
8745 var d = Math.pow(b,cs), mi = false, j = 0, w = 0;
8746 for(var i = 0; i < s.length; ++i) {
8747 var x = intAt(s,i);
8748 if(x < 0) {
8749 if(s.charAt(i) == "-" && this.signum() == 0) mi = true;
8750 continue;
8751 }
8752 w = b*w+x;
8753 if(++j >= cs) {
8754 this.dMultiply(d);
8755 this.dAddOffset(w,0);
8756 j = 0;
8757 w = 0;
8758 }
8759 }
8760 if(j > 0) {
8761 this.dMultiply(Math.pow(b,j));
8762 this.dAddOffset(w,0);
8763 }
8764 if(mi) BigInteger.ZERO.subTo(this,this);
8765}
8766
8767// (protected) alternate constructor
8768function bnpFromNumber(a,b,c) {
8769 if("number" == typeof b) {
8770 // new BigInteger(int,int,RNG)
8771 if(a < 2) this.fromInt(1);
8772 else {
8773 this.fromNumber(a,c);
8774 if(!this.testBit(a-1)) // force MSB set
8775 this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this);
8776 if(this.isEven()) this.dAddOffset(1,0); // force odd
8777 while(!this.isProbablePrime(b)) {
8778 this.dAddOffset(2,0);
8779 if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this);
8780 }
8781 }
8782 }
8783 else {
8784 // new BigInteger(int,RNG)
8785 var x = new Array(), t = a&7;
8786 x.length = (a>>3)+1;
8787 b.nextBytes(x);
8788 if(t > 0) x[0] &= ((1<<t)-1); else x[0] = 0;
8789 this.fromString(x,256);
8790 }
8791}
8792
8793// (public) convert to bigendian byte array
8794function bnToByteArray() {
8795 var i = this.t, r = new Array();
8796 r[0] = this.s;
8797 var p = this.DB-(i*this.DB)%8, d, k = 0;
8798 if(i-- > 0) {
8799 if(p < this.DB && (d = this[i]>>p) != (this.s&this.DM)>>p)
8800 r[k++] = d|(this.s<<(this.DB-p));
8801 while(i >= 0) {
8802 if(p < 8) {
8803 d = (this[i]&((1<<p)-1))<<(8-p);
8804 d |= this[--i]>>(p+=this.DB-8);
8805 }
8806 else {
8807 d = (this[i]>>(p-=8))&0xff;
8808 if(p <= 0) { p += this.DB; --i; }
8809 }
8810 if((d&0x80) != 0) d |= -256;
8811 if(k == 0 && (this.s&0x80) != (d&0x80)) ++k;
8812 if(k > 0 || d != this.s) r[k++] = d;
8813 }
8814 }
8815 return r;
8816}
8817
8818function bnEquals(a) { return(this.compareTo(a)==0); }
8819function bnMin(a) { return(this.compareTo(a)<0)?this:a; }
8820function bnMax(a) { return(this.compareTo(a)>0)?this:a; }
8821
8822// (protected) r = this op a (bitwise)
8823function bnpBitwiseTo(a,op,r) {
8824 var i, f, m = Math.min(a.t,this.t);
8825 for(i = 0; i < m; ++i) r[i] = op(this[i],a[i]);
8826 if(a.t < this.t) {
8827 f = a.s&this.DM;
8828 for(i = m; i < this.t; ++i) r[i] = op(this[i],f);
8829 r.t = this.t;
8830 }
8831 else {
8832 f = this.s&this.DM;
8833 for(i = m; i < a.t; ++i) r[i] = op(f,a[i]);
8834 r.t = a.t;
8835 }
8836 r.s = op(this.s,a.s);
8837 r.clamp();
8838}
8839
8840// (public) this & a
8841function op_and(x,y) { return x&y; }
8842function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; }
8843
8844// (public) this | a
8845function op_or(x,y) { return x|y; }
8846function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; }
8847
8848// (public) this ^ a
8849function op_xor(x,y) { return x^y; }
8850function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; }
8851
8852// (public) this & ~a
8853function op_andnot(x,y) { return x&~y; }
8854function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; }
8855
8856// (public) ~this
8857function bnNot() {
8858 var r = nbi();
8859 for(var i = 0; i < this.t; ++i) r[i] = this.DM&~this[i];
8860 r.t = this.t;
8861 r.s = ~this.s;
8862 return r;
8863}
8864
8865// (public) this << n
8866function bnShiftLeft(n) {
8867 var r = nbi();
8868 if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r);
8869 return r;
8870}
8871
8872// (public) this >> n
8873function bnShiftRight(n) {
8874 var r = nbi();
8875 if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r);
8876 return r;
8877}
8878
8879// return index of lowest 1-bit in x, x < 2^31
8880function lbit(x) {
8881 if(x == 0) return -1;
8882 var r = 0;
8883 if((x&0xffff) == 0) { x >>= 16; r += 16; }
8884 if((x&0xff) == 0) { x >>= 8; r += 8; }
8885 if((x&0xf) == 0) { x >>= 4; r += 4; }
8886 if((x&3) == 0) { x >>= 2; r += 2; }
8887 if((x&1) == 0) ++r;
8888 return r;
8889}
8890
8891// (public) returns index of lowest 1-bit (or -1 if none)
8892function bnGetLowestSetBit() {
8893 for(var i = 0; i < this.t; ++i)
8894 if(this[i] != 0) return i*this.DB+lbit(this[i]);
8895 if(this.s < 0) return this.t*this.DB;
8896 return -1;
8897}
8898
8899// return number of 1 bits in x
8900function cbit(x) {
8901 var r = 0;
8902 while(x != 0) { x &= x-1; ++r; }
8903 return r;
8904}
8905
8906// (public) return number of set bits
8907function bnBitCount() {
8908 var r = 0, x = this.s&this.DM;
8909 for(var i = 0; i < this.t; ++i) r += cbit(this[i]^x);
8910 return r;
8911}
8912
8913// (public) true iff nth bit is set
8914function bnTestBit(n) {
8915 var j = Math.floor(n/this.DB);
8916 if(j >= this.t) return(this.s!=0);
8917 return((this[j]&(1<<(n%this.DB)))!=0);
8918}
8919
8920// (protected) this op (1<<n)
8921function bnpChangeBit(n,op) {
8922 var r = BigInteger.ONE.shiftLeft(n);
8923 this.bitwiseTo(r,op,r);
8924 return r;
8925}
8926
8927// (public) this | (1<<n)
8928function bnSetBit(n) { return this.changeBit(n,op_or); }
8929
8930// (public) this & ~(1<<n)
8931function bnClearBit(n) { return this.changeBit(n,op_andnot); }
8932
8933// (public) this ^ (1<<n)
8934function bnFlipBit(n) { return this.changeBit(n,op_xor); }
8935
8936// (protected) r = this + a
8937function bnpAddTo(a,r) {
8938 var i = 0, c = 0, m = Math.min(a.t,this.t);
8939 while(i < m) {
8940 c += this[i]+a[i];
8941 r[i++] = c&this.DM;
8942 c >>= this.DB;
8943 }
8944 if(a.t < this.t) {
8945 c += a.s;
8946 while(i < this.t) {
8947 c += this[i];
8948 r[i++] = c&this.DM;
8949 c >>= this.DB;
8950 }
8951 c += this.s;
8952 }
8953 else {
8954 c += this.s;
8955 while(i < a.t) {
8956 c += a[i];
8957 r[i++] = c&this.DM;
8958 c >>= this.DB;
8959 }
8960 c += a.s;
8961 }
8962 r.s = (c<0)?-1:0;
8963 if(c > 0) r[i++] = c;
8964 else if(c < -1) r[i++] = this.DV+c;
8965 r.t = i;
8966 r.clamp();
8967}
8968
8969// (public) this + a
8970function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; }
8971
8972// (public) this - a
8973function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; }
8974
8975// (public) this * a
8976function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; }
8977
8978// (public) this / a
8979function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; }
8980
8981// (public) this % a
8982function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; }
8983
8984// (public) [this/a,this%a]
8985function bnDivideAndRemainder(a) {
8986 var q = nbi(), r = nbi();
8987 this.divRemTo(a,q,r);
8988 return new Array(q,r);
8989}
8990
8991// (protected) this *= n, this >= 0, 1 < n < DV
8992function bnpDMultiply(n) {
8993 this[this.t] = this.am(0,n-1,this,0,0,this.t);
8994 ++this.t;
8995 this.clamp();
8996}
8997
8998// (protected) this += n << w words, this >= 0
8999function bnpDAddOffset(n,w) {
9000 if(n == 0) return;
9001 while(this.t <= w) this[this.t++] = 0;
9002 this[w] += n;
9003 while(this[w] >= this.DV) {
9004 this[w] -= this.DV;
9005 if(++w >= this.t) this[this.t++] = 0;
9006 ++this[w];
9007 }
9008}
9009
9010// A "null" reducer
9011function NullExp() {}
9012function nNop(x) { return x; }
9013function nMulTo(x,y,r) { x.multiplyTo(y,r); }
9014function nSqrTo(x,r) { x.squareTo(r); }
9015
9016NullExp.prototype.convert = nNop;
9017NullExp.prototype.revert = nNop;
9018NullExp.prototype.mulTo = nMulTo;
9019NullExp.prototype.sqrTo = nSqrTo;
9020
9021// (public) this^e
9022function bnPow(e) { return this.exp(e,new NullExp()); }
9023
9024// (protected) r = lower n words of "this * a", a.t <= n
9025// "this" should be the larger one if appropriate.
9026function bnpMultiplyLowerTo(a,n,r) {
9027 var i = Math.min(this.t+a.t,n);
9028 r.s = 0; // assumes a,this >= 0
9029 r.t = i;
9030 while(i > 0) r[--i] = 0;
9031 var j;
9032 for(j = r.t-this.t; i < j; ++i) r[i+this.t] = this.am(0,a[i],r,i,0,this.t);
9033 for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a[i],r,i,0,n-i);
9034 r.clamp();
9035}
9036
9037// (protected) r = "this * a" without lower n words, n > 0
9038// "this" should be the larger one if appropriate.
9039function bnpMultiplyUpperTo(a,n,r) {
9040 --n;
9041 var i = r.t = this.t+a.t-n;
9042 r.s = 0; // assumes a,this >= 0
9043 while(--i >= 0) r[i] = 0;
9044 for(i = Math.max(n-this.t,0); i < a.t; ++i)
9045 r[this.t+i-n] = this.am(n-i,a[i],r,0,0,this.t+i-n);
9046 r.clamp();
9047 r.drShiftTo(1,r);
9048}
9049
9050// Barrett modular reduction
9051function Barrett(m) {
9052 // setup Barrett
9053 this.r2 = nbi();
9054 this.q3 = nbi();
9055 BigInteger.ONE.dlShiftTo(2*m.t,this.r2);
9056 this.mu = this.r2.divide(m);
9057 this.m = m;
9058}
9059
9060function barrettConvert(x) {
9061 if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m);
9062 else if(x.compareTo(this.m) < 0) return x;
9063 else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; }
9064}
9065
9066function barrettRevert(x) { return x; }
9067
9068// x = x mod m (HAC 14.42)
9069function barrettReduce(x) {
9070 x.drShiftTo(this.m.t-1,this.r2);
9071 if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); }
9072 this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3);
9073 this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);
9074 while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1);
9075 x.subTo(this.r2,x);
9076 while(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
9077}
9078
9079// r = x^2 mod m; x != r
9080function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
9081
9082// r = x*y mod m; x,y != r
9083function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
9084
9085Barrett.prototype.convert = barrettConvert;
9086Barrett.prototype.revert = barrettRevert;
9087Barrett.prototype.reduce = barrettReduce;
9088Barrett.prototype.mulTo = barrettMulTo;
9089Barrett.prototype.sqrTo = barrettSqrTo;
9090
9091// (public) this^e % m (HAC 14.85)
9092function bnModPow(e,m) {
9093 var i = e.bitLength(), k, r = nbv(1), z;
9094 if(i <= 0) return r;
9095 else if(i < 18) k = 1;
9096 else if(i < 48) k = 3;
9097 else if(i < 144) k = 4;
9098 else if(i < 768) k = 5;
9099 else k = 6;
9100 if(i < 8)
9101 z = new Classic(m);
9102 else if(m.isEven())
9103 z = new Barrett(m);
9104 else
9105 z = new Montgomery(m);
9106
9107 // precomputation
9108 var g = new Array(), n = 3, k1 = k-1, km = (1<<k)-1;
9109 g[1] = z.convert(this);
9110 if(k > 1) {
9111 var g2 = nbi();
9112 z.sqrTo(g[1],g2);
9113 while(n <= km) {
9114 g[n] = nbi();
9115 z.mulTo(g2,g[n-2],g[n]);
9116 n += 2;
9117 }
9118 }
9119
9120 var j = e.t-1, w, is1 = true, r2 = nbi(), t;
9121 i = nbits(e[j])-1;
9122 while(j >= 0) {
9123 if(i >= k1) w = (e[j]>>(i-k1))&km;
9124 else {
9125 w = (e[j]&((1<<(i+1))-1))<<(k1-i);
9126 if(j > 0) w |= e[j-1]>>(this.DB+i-k1);
9127 }
9128
9129 n = k;
9130 while((w&1) == 0) { w >>= 1; --n; }
9131 if((i -= n) < 0) { i += this.DB; --j; }
9132 if(is1) { // ret == 1, don't bother squaring or multiplying it
9133 g[w].copyTo(r);
9134 is1 = false;
9135 }
9136 else {
9137 while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; }
9138 if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; }
9139 z.mulTo(r2,g[w],r);
9140 }
9141
9142 while(j >= 0 && (e[j]&(1<<i)) == 0) {
9143 z.sqrTo(r,r2); t = r; r = r2; r2 = t;
9144 if(--i < 0) { i = this.DB-1; --j; }
9145 }
9146 }
9147 return z.revert(r);
9148}
9149
9150// (public) gcd(this,a) (HAC 14.54)
9151function bnGCD(a) {
9152 var x = (this.s<0)?this.negate():this.clone();
9153 var y = (a.s<0)?a.negate():a.clone();
9154 if(x.compareTo(y) < 0) { var t = x; x = y; y = t; }
9155 var i = x.getLowestSetBit(), g = y.getLowestSetBit();
9156 if(g < 0) return x;
9157 if(i < g) g = i;
9158 if(g > 0) {
9159 x.rShiftTo(g,x);
9160 y.rShiftTo(g,y);
9161 }
9162 while(x.signum() > 0) {
9163 if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x);
9164 if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y);
9165 if(x.compareTo(y) >= 0) {
9166 x.subTo(y,x);
9167 x.rShiftTo(1,x);
9168 }
9169 else {
9170 y.subTo(x,y);
9171 y.rShiftTo(1,y);
9172 }
9173 }
9174 if(g > 0) y.lShiftTo(g,y);
9175 return y;
9176}
9177
9178// (protected) this % n, n < 2^26
9179function bnpModInt(n) {
9180 if(n <= 0) return 0;
9181 var d = this.DV%n, r = (this.s<0)?n-1:0;
9182 if(this.t > 0)
9183 if(d == 0) r = this[0]%n;
9184 else for(var i = this.t-1; i >= 0; --i) r = (d*r+this[i])%n;
9185 return r;
9186}
9187
9188// (public) 1/this % m (HAC 14.61)
9189function bnModInverse(m) {
9190 var ac = m.isEven();
9191 if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
9192 var u = m.clone(), v = this.clone();
9193 var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
9194 while(u.signum() != 0) {
9195 while(u.isEven()) {
9196 u.rShiftTo(1,u);
9197 if(ac) {
9198 if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); }
9199 a.rShiftTo(1,a);
9200 }
9201 else if(!b.isEven()) b.subTo(m,b);
9202 b.rShiftTo(1,b);
9203 }
9204 while(v.isEven()) {
9205 v.rShiftTo(1,v);
9206 if(ac) {
9207 if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); }
9208 c.rShiftTo(1,c);
9209 }
9210 else if(!d.isEven()) d.subTo(m,d);
9211 d.rShiftTo(1,d);
9212 }
9213 if(u.compareTo(v) >= 0) {
9214 u.subTo(v,u);
9215 if(ac) a.subTo(c,a);
9216 b.subTo(d,b);
9217 }
9218 else {
9219 v.subTo(u,v);
9220 if(ac) c.subTo(a,c);
9221 d.subTo(b,d);
9222 }
9223 }
9224 if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
9225 if(d.compareTo(m) >= 0) return d.subtract(m);
9226 if(d.signum() < 0) d.addTo(m,d); else return d;
9227 if(d.signum() < 0) return d.add(m); else return d;
9228}
9229
9230var 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];
9231var lplim = (1<<26)/lowprimes[lowprimes.length-1];
9232
9233// (public) test primality with certainty >= 1-.5^t
9234function bnIsProbablePrime(t) {
9235 var i, x = this.abs();
9236 if(x.t == 1 && x[0] <= lowprimes[lowprimes.length-1]) {
9237 for(i = 0; i < lowprimes.length; ++i)
9238 if(x[0] == lowprimes[i]) return true;
9239 return false;
9240 }
9241 if(x.isEven()) return false;
9242 i = 1;
9243 while(i < lowprimes.length) {
9244 var m = lowprimes[i], j = i+1;
9245 while(j < lowprimes.length && m < lplim) m *= lowprimes[j++];
9246 m = x.modInt(m);
9247 while(i < j) if(m%lowprimes[i++] == 0) return false;
9248 }
9249 return x.millerRabin(t);
9250}
9251
9252// (protected) true if probably prime (HAC 4.24, Miller-Rabin)
9253function bnpMillerRabin(t) {
9254 var n1 = this.subtract(BigInteger.ONE);
9255 var k = n1.getLowestSetBit();
9256 if(k <= 0) return false;
9257 var r = n1.shiftRight(k);
9258 t = (t+1)>>1;
9259 if(t > lowprimes.length) t = lowprimes.length;
9260 var a = nbi();
9261 for(var i = 0; i < t; ++i) {
9262 a.fromInt(lowprimes[i]);
9263 var y = a.modPow(r,this);
9264 if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {
9265 var j = 1;
9266 while(j++ < k && y.compareTo(n1) != 0) {
9267 y = y.modPowInt(2,this);
9268 if(y.compareTo(BigInteger.ONE) == 0) return false;
9269 }
9270 if(y.compareTo(n1) != 0) return false;
9271 }
9272 }
9273 return true;
9274}
9275
9276// protected
9277BigInteger.prototype.chunkSize = bnpChunkSize;
9278BigInteger.prototype.toRadix = bnpToRadix;
9279BigInteger.prototype.fromRadix = bnpFromRadix;
9280BigInteger.prototype.fromNumber = bnpFromNumber;
9281BigInteger.prototype.bitwiseTo = bnpBitwiseTo;
9282BigInteger.prototype.changeBit = bnpChangeBit;
9283BigInteger.prototype.addTo = bnpAddTo;
9284BigInteger.prototype.dMultiply = bnpDMultiply;
9285BigInteger.prototype.dAddOffset = bnpDAddOffset;
9286BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo;
9287BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo;
9288BigInteger.prototype.modInt = bnpModInt;
9289BigInteger.prototype.millerRabin = bnpMillerRabin;
9290
9291// public
9292BigInteger.prototype.clone = bnClone;
9293BigInteger.prototype.intValue = bnIntValue;
9294BigInteger.prototype.byteValue = bnByteValue;
9295BigInteger.prototype.shortValue = bnShortValue;
9296BigInteger.prototype.signum = bnSigNum;
9297BigInteger.prototype.toByteArray = bnToByteArray;
9298BigInteger.prototype.equals = bnEquals;
9299BigInteger.prototype.min = bnMin;
9300BigInteger.prototype.max = bnMax;
9301BigInteger.prototype.and = bnAnd;
9302BigInteger.prototype.or = bnOr;
9303BigInteger.prototype.xor = bnXor;
9304BigInteger.prototype.andNot = bnAndNot;
9305BigInteger.prototype.not = bnNot;
9306BigInteger.prototype.shiftLeft = bnShiftLeft;
9307BigInteger.prototype.shiftRight = bnShiftRight;
9308BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit;
9309BigInteger.prototype.bitCount = bnBitCount;
9310BigInteger.prototype.testBit = bnTestBit;
9311BigInteger.prototype.setBit = bnSetBit;
9312BigInteger.prototype.clearBit = bnClearBit;
9313BigInteger.prototype.flipBit = bnFlipBit;
9314BigInteger.prototype.add = bnAdd;
9315BigInteger.prototype.subtract = bnSubtract;
9316BigInteger.prototype.multiply = bnMultiply;
9317BigInteger.prototype.divide = bnDivide;
9318BigInteger.prototype.remainder = bnRemainder;
9319BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder;
9320BigInteger.prototype.modPow = bnModPow;
9321BigInteger.prototype.modInverse = bnModInverse;
9322BigInteger.prototype.pow = bnPow;
9323BigInteger.prototype.gcd = bnGCD;
9324BigInteger.prototype.isProbablePrime = bnIsProbablePrime;
9325
9326// BigInteger interfaces not implemented in jsbn:
9327
9328// BigInteger(int signum, byte[] magnitude)
9329// double doubleValue()
9330// float floatValue()
9331// int hashCode()
9332// long longValue()
9333// static BigInteger valueOf(long val)
9334