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