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