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