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