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