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