blob: 5d23258a6ebfbced0f48da3ee6ca5d8a84598230 [file] [log] [blame]
Wentao Shangc0311e52012-12-03 10:38:23 -08001/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002 * @author: Jeff Thompson
3 * See COPYING for copyright and distribution information.
4 * Provide the callback closure for the async communication methods in the NDN class.
5 * This is a port of Closure.py from PyCCN, written by:
6 * Derek Kulinski <takeda@takeda.tk>
7 * Jeff Burke <jburke@ucla.edu>
8 */
9
10/*
11 * Create a subclass of Closure and pass an object to async calls.
12 */
13var Closure = function Closure() {
14 // I don't think storing NDN's closure is needed
15 // and it creates a reference loop, as of now both
16 // of those variables are never set -- Derek
17 //
18 // Use instance variables to return data to callback
19 this.ndn_data = null; // this holds the ndn_closure
20 this.ndn_data_dirty = false;
Wentao Shangc0311e52012-12-03 10:38:23 -080021
22 this.timerID = -1; // Store the interest timer; used to cancel the timer upon receiving interest
Wentao Shang0e291c82012-12-02 23:36:29 -080023};
24
25// Upcall result
26Closure.RESULT_ERR = -1; // upcall detected an error
27Closure.RESULT_OK = 0; // normal upcall return
28Closure.RESULT_REEXPRESS = 1; // reexpress the same interest again
29Closure.RESULT_INTEREST_CONSUMED = 2; // upcall claims to consume interest
30Closure.RESULT_VERIFY = 3; // force an unverified result to be verified
31Closure.RESULT_FETCHKEY = 4; // get the key in the key locator and re-call the interest
32 // with the key available in the local storage
33
34// Upcall kind
35Closure.UPCALL_FINAL = 0; // handler is about to be deregistered
36Closure.UPCALL_INTEREST = 1; // incoming interest
37Closure.UPCALL_CONSUMED_INTEREST = 2; // incoming interest, someone has answered
38Closure.UPCALL_CONTENT = 3; // incoming verified content
39Closure.UPCALL_INTEREST_TIMED_OUT = 4; // interest timed out
40Closure.UPCALL_CONTENT_UNVERIFIED = 5; // content that has not been verified
41Closure.UPCALL_CONTENT_BAD = 6; // verification failed
42
43/*
44 * Override this in your subclass.
45 * If you're getting strange errors in upcall()
46 * check your code whether you're returning a value.
47 */
48Closure.prototype.upcall = function(kind, upcallInfo) {
49 //dump('upcall ' + this + " " + kind + " " + upcallInfo + "\n");
50 return Closure.RESULT_OK;
51};
52
53var UpcallInfo = function UpcallInfo(ndn, interest, matchedComps, contentObject) {
54 this.ndn = ndn; // NDN object (not used)
55 this.interest = interest; // Interest object
56 this.matchedComps = matchedComps; // int
57 this.contentObject = contentObject; // Content object
58};
59
60UpcallInfo.prototype.toString = function() {
61 var ret = "ndn = " + this.ndn;
62 ret += "\nInterest = " + this.interest;
63 ret += "\nmatchedComps = " + this.matchedComps;
64 ret += "\nContentObject: " + this.contentObject;
65 return ret;
66}
Wentao Shangc0311e52012-12-03 10:38:23 -080067/**
Wentao Shang0e291c82012-12-02 23:36:29 -080068 * @author: Meki Cherkaoui, Jeff Thompson, Wentao Shang
69 * See COPYING for copyright and distribution information.
70 * This class represents the top-level object for communicating with an NDN host.
71 */
72
Wentao Shangc0311e52012-12-03 10:38:23 -080073var LOG = 0;
Wentao Shang0e291c82012-12-02 23:36:29 -080074
75/**
76 * settings is an associative array with the following defaults:
77 * {
Wentao Shang0e291c82012-12-02 23:36:29 -080078 * getTransport: function() { return new WebSocketTransport(); }
Jeff Thompson3dfddaa2012-12-16 17:55:47 -080079 * getHostAndPort: transport.defaultGetHostAndPort,
80 * host: 'localhost', // If null, use getHostAndPort when connecting.
81 * port: 9696,
Wentao Shangc0311e52012-12-03 10:38:23 -080082 * onopen: function() { if (LOG > 3) console.log("NDN connection established."); }
83 * onclose: function() { if (LOG > 3) console.log("NDN connection closed."); }
Wentao Shang0e291c82012-12-02 23:36:29 -080084 * }
Jeff Thompson3dfddaa2012-12-16 17:55:47 -080085 *
86 * getHostAndPort is a function, on each call it returns a new { host: host, port: port } or
87 * null if there are no more hosts.
Wentao Shang0e291c82012-12-02 23:36:29 -080088 */
89var NDN = function NDN(settings) {
90 settings = (settings || {});
Wentao Shang0e291c82012-12-02 23:36:29 -080091 var getTransport = (settings.getTransport || function() { return new WebSocketTransport(); });
92 this.transport = getTransport();
Jeff Thompson3dfddaa2012-12-16 17:55:47 -080093 this.getHostAndPort = (settings.getHostAndPort || this.transport.defaultGetHostAndPort);
94 this.host = (settings.host !== undefined ? settings.host : 'localhost');
Jeff Thompson3dfddaa2012-12-16 17:55:47 -080095 this.port = (settings.port || 9696);
Wentao Shang0e291c82012-12-02 23:36:29 -080096 this.readyStatus = NDN.UNOPEN;
97 // Event handler
Wentao Shangc0311e52012-12-03 10:38:23 -080098 this.onopen = (settings.onopen || function() { if (LOG > 3) console.log("NDN connection established."); });
99 this.onclose = (settings.onclose || function() { if (LOG > 3) console.log("NDN connection closed."); });
Wentao Shang0e291c82012-12-02 23:36:29 -0800100};
101
102NDN.UNOPEN = 0; // created but not opened yet
103NDN.OPENED = 1; // connection to ccnd opened
104NDN.CLOSED = 2; // connection to ccnd closed
105
Jeff Thompson3dfddaa2012-12-16 17:55:47 -0800106NDN.ccndIdFetcher = '/%C1.M.S.localhost/%C1.M.SRV/ccnd/KEY';
Wentao Shang0e291c82012-12-02 23:36:29 -0800107
108NDN.prototype.createRoute = function(host,port){
109 this.host=host;
110 this.port=port;
111}
112
Wentao Shang82854bd2012-12-27 14:14:41 -0800113
114NDN.KeyStore = new Array();
115
Wentao Shangb5d0c3e2012-12-30 11:12:03 -0800116var KeyStoreEntry = function KeyStoreEntry(name, rsa, time) {
Wentao Shang82854bd2012-12-27 14:14:41 -0800117 this.keyName = name; // KeyName
Wentao Shang82854bd2012-12-27 14:14:41 -0800118 this.rsaKey = rsa; // RSA key
Wentao Shangb5d0c3e2012-12-30 11:12:03 -0800119 this.timeStamp = time; // Time Stamp
120};
121
122NDN.addKeyEntry = function(/* KeyStoreEntry */ keyEntry) {
123 var result = NDN.getKeyByName(keyEntry.keyName);
124 if (result == null)
125 NDN.KeyStore.push(keyEntry);
126 else
127 result = keyEntry;
Wentao Shang82854bd2012-12-27 14:14:41 -0800128};
129
130NDN.getKeyByName = function(/* KeyName */ name) {
131 var result = null;
132
133 for (var i = 0; i < NDN.KeyStore.length; i++) {
134 if (NDN.KeyStore[i].keyName.matches_name(name.contentName)) {
135 if (result == null ||
136 NDN.KeyStore[i].keyName.contentName.components.length > result.keyName.contentName.components.length)
137 result = NDN.KeyStore[i];
138 }
139 }
140
141 return result;
142};
143
Jeff Thompson3dfddaa2012-12-16 17:55:47 -0800144// For fetching data
145NDN.PITTable = new Array();
146
147var PITEntry = function PITEntry(interest, closure) {
148 this.interest = interest; // Interest
149 this.closure = closure; // Closure
150};
151
152// Return the longest entry from NDN.PITTable that matches name.
153NDN.getEntryForExpressedInterest = function(/*Name*/ name) {
154 // TODO: handle multiple matches? Maybe not from registerPrefix because multiple ContentObject
155 // could be sent for one Interest?
156 var result = null;
157
158 for (var i = 0; i < NDN.PITTable.length; i++) {
159 if (NDN.PITTable[i].interest.matches_name(name)) {
160 if (result == null ||
161 NDN.PITTable[i].interest.name.components.length > result.interest.name.components.length)
162 result = NDN.PITTable[i];
163 }
164 }
165
166 return result;
167};
168
169/*
170 * Return a function that selects a host at random from hostList and returns { host: host, port: port }.
171 * If no more hosts remain, return null.
172 */
173NDN.makeShuffledGetHostAndPort = function(hostList, port) {
174 // Make a copy.
175 hostList = hostList.slice(0, hostList.length);
176 DataUtils.shuffle(hostList);
177
178 return function() {
179 if (hostList.length == 0)
180 return null;
181
182 return { host: hostList.splice(0, 1)[0], port: port };
183 };
184};
185
Wentao Shang0e291c82012-12-02 23:36:29 -0800186/** Encode name as an Interest. If template is not null, use its attributes.
187 * Send the interest to host:port, read the entire response and call
188 * closure.upcall(Closure.UPCALL_CONTENT (or Closure.UPCALL_CONTENT_UNVERIFIED),
189 * new UpcallInfo(this, interest, 0, contentObject)).
190 */
191NDN.prototype.expressInterest = function(
192 // Name
193 name,
194 // Closure
195 closure,
196 // Interest
197 template) {
Wentao Shang0e291c82012-12-02 23:36:29 -0800198 var interest = new Interest(name);
199 if (template != null) {
200 interest.minSuffixComponents = template.minSuffixComponents;
201 interest.maxSuffixComponents = template.maxSuffixComponents;
202 interest.publisherPublicKeyDigest = template.publisherPublicKeyDigest;
203 interest.exclude = template.exclude;
204 interest.childSelector = template.childSelector;
205 interest.answerOriginKind = template.answerOriginKind;
206 interest.scope = template.scope;
207 interest.interestLifetime = template.interestLifetime;
208 }
209 else
Jeff Thompson42806a12012-12-29 18:19:39 -0800210 interest.interestLifetime = 4000; // default interest timeout value in milliseconds.
Wentao Shang0e291c82012-12-02 23:36:29 -0800211
Jeff Thompson3dfddaa2012-12-16 17:55:47 -0800212 if (this.host == null || this.port == null) {
213 if (this.getHostAndPort == null)
214 console.log('ERROR: host OR port NOT SET');
215 else
216 this.connectAndExpressInterest(interest, closure);
217 }
218 else
219 this.transport.expressInterest(this, interest, closure);
220};
Wentao Shang0e291c82012-12-02 23:36:29 -0800221
222NDN.prototype.registerPrefix = function(name, closure, flag) {
223 return this.transport.registerPrefix(this, name, closure, flag);
224}
Jeff Thompson3dfddaa2012-12-16 17:55:47 -0800225
226/*
227 * Assume this.getHostAndPort is not null. This is called when this.host is null or its host
228 * is not alive. Get a host and port, connect, then express callerInterest with callerClosure.
229 */
230NDN.prototype.connectAndExpressInterest = function(callerInterest, callerClosure) {
231 var hostAndPort = this.getHostAndPort();
232 if (hostAndPort == null) {
233 console.log('ERROR: No more hosts from getHostAndPort');
234 this.host = null;
235 return;
236 }
237
238 if (hostAndPort.host == this.host && hostAndPort.port == this.port) {
239 console.log('ERROR: The host returned by getHostAndPort is not alive: ' +
240 this.host + ":" + this.port);
241 return;
242 }
243
244 this.host = hostAndPort.host;
245 this.port = hostAndPort.port;
246 console.log("Trying host from getHostAndPort: " + this.host);
247
248 // Fetch the ccndId.
249 var interest = new Interest(new Name(NDN.ccndIdFetcher));
Jeff Thompson42806a12012-12-29 18:19:39 -0800250 interest.interestLifetime = 4000; // milliseconds
Jeff Thompson3dfddaa2012-12-16 17:55:47 -0800251
252 var thisNDN = this;
253 var timerID = setTimeout(function() {
254 console.log("Timeout waiting for host " + thisNDN.host);
255 // Try again.
256 thisNDN.connectAndExpressInterest(callerInterest, callerClosure);
257 }, 3000);
258
259 this.transport.expressInterest
260 (this, interest, new NDN.ConnectClosure(this, callerInterest, callerClosure, timerID));
261}
262
263NDN.ConnectClosure = function ConnectClosure(ndn, callerInterest, callerClosure, timerID) {
264 // Inherit from Closure.
265 Closure.call(this);
266
267 this.ndn = ndn;
268 this.callerInterest = callerInterest;
269 this.callerClosure = callerClosure;
270 this.timerID = timerID;
271};
272
273NDN.ConnectClosure.prototype.upcall = function(kind, upcallInfo) {
274 if (!(kind == Closure.UPCALL_CONTENT ||
275 kind == Closure.UPCALL_CONTENT_UNVERIFIED ||
276 kind == Closure.UPCALL_INTEREST))
277 // The upcall is not for us.
278 return Closure.RESULT_ERR;
279
280 // The host is alive, so cancel the timeout and issue the caller's interest.
281 clearTimeout(this.timerID);
282 console.log(this.ndn.host + ": Host is alive. Fetching callerInterest.");
283 this.ndn.transport.expressInterest(this.ndn, this.callerInterest, this.callerClosure);
284
285 return Closure.RESULT_OK;
286};
287
Wentao Shangc0311e52012-12-03 10:38:23 -0800288/**
Wentao Shang0e291c82012-12-02 23:36:29 -0800289 * @author: Wentao Shang
290 * See COPYING for copyright and distribution information.
Wentao Shang0e291c82012-12-02 23:36:29 -0800291 */
292
293var WebSocketTransport = function WebSocketTransport() {
294 this.ws = null;
295 this.ccndid = null;
296 this.maxBufferSize = 10000; // Currently support 10000 bytes data input, consistent with BinaryXMLEncoder
297 this.buffer = new Uint8Array(this.maxBufferSize);
Wentao Shang2b740e62012-12-07 00:02:53 -0800298 this.bufferOffset = 0;
Wentao Shang0e291c82012-12-02 23:36:29 -0800299 this.structureDecoder = new BinaryXMLStructureDecoder();
Jeff Thompson3dfddaa2012-12-16 17:55:47 -0800300 this.defaultGetHostAndPort = NDN.makeShuffledGetHostAndPort
301 (["A.ws.ndn.ucla.edu", "B.ws.ndn.ucla.edu", "C.ws.ndn.ucla.edu", "D.ws.ndn.ucla.edu",
302 "E.ws.ndn.ucla.edu"],
303 9696);
Wentao Shang0e291c82012-12-02 23:36:29 -0800304};
305
Wentao Shang0e291c82012-12-02 23:36:29 -0800306WebSocketTransport.prototype.connectWebSocket = function(ndn) {
307 if (this.ws != null)
308 delete this.ws;
309
310 this.ws = new WebSocket('ws://' + ndn.host + ':' + ndn.port);
Wentao Shangc0311e52012-12-03 10:38:23 -0800311 if (LOG > 0) console.log('ws connection created.');
Wentao Shang0e291c82012-12-02 23:36:29 -0800312
313 this.ws.binaryType = "arraybuffer";
314
315 var self = this;
316 this.ws.onmessage = function(ev) {
317 var result = ev.data;
318 //console.log('RecvHandle called.');
319
320 if(result == null || result == undefined || result == "" ) {
321 console.log('INVALID ANSWER');
322 } else if (result instanceof ArrayBuffer) {
323 var bytearray = new Uint8Array(result);
324
Wentao Shangc0311e52012-12-03 10:38:23 -0800325 if (LOG>3) console.log('BINARY RESPONSE IS ' + DataUtils.toHex(bytearray));
Wentao Shang0e291c82012-12-02 23:36:29 -0800326
327 try {
Wentao Shang2b740e62012-12-07 00:02:53 -0800328 if (bytearray.length + self.bufferOffset >= self.buffer.byteLength) {
329 if (LOG>3) {
330 console.log("NDN.ws.onmessage: buffer overflow. Accumulate received length: " + self.bufferOffset
331 + ". Current packet length: " + bytearray.length + ".");
332 }
333
Wentao Shang0e291c82012-12-02 23:36:29 -0800334 // Purge and quit.
335 delete self.structureDecoder;
336 delete self.buffer;
337 self.structureDecoder = new BinaryXMLStructureDecoder();
338 self.buffer = new Uint8Array(self.maxBufferSize);
Wentao Shang2b740e62012-12-07 00:02:53 -0800339 self.bufferOffset = 0;
Wentao Shang0e291c82012-12-02 23:36:29 -0800340 return;
341 }
342
343 /*for (var i = 0; i < bytearray.length; i++) {
344 self.buffer.push(bytearray[i]);
345 }*/
Wentao Shang2b740e62012-12-07 00:02:53 -0800346 self.buffer.set(bytearray, self.bufferOffset);
347 self.bufferOffset += bytearray.length;
Wentao Shang0e291c82012-12-02 23:36:29 -0800348
Wentao Shang2b740e62012-12-07 00:02:53 -0800349 if (!self.structureDecoder.findElementEnd(self.buffer.subarray(0, self.bufferOffset))) {
Wentao Shang0e291c82012-12-02 23:36:29 -0800350 // Need more data to decode
Wentao Shang2b740e62012-12-07 00:02:53 -0800351 if (LOG>3) console.log('Incomplete packet received. Length ' + bytearray.length + '. Wait for more input.');
Wentao Shang0e291c82012-12-02 23:36:29 -0800352 return;
353 }
Wentao Shang2b740e62012-12-07 00:02:53 -0800354 if (LOG>3) console.log('Complete packet received. Length ' + bytearray.length + '. Start decoding.');
Wentao Shang0e291c82012-12-02 23:36:29 -0800355 } catch (ex) {
356 console.log("NDN.ws.onmessage exception: " + ex);
357 return;
358 }
359
360 var decoder = new BinaryXMLDecoder(self.buffer);
361 // Dispatch according to packet type
362 if (decoder.peekStartElement(CCNProtocolDTags.Interest)) { // Interest packet
Wentao Shangc0311e52012-12-03 10:38:23 -0800363 if (LOG > 3) console.log('Interest packet received.');
Wentao Shang0e291c82012-12-02 23:36:29 -0800364
365 var interest = new Interest();
366 interest.from_ccnb(decoder);
367 if (LOG>3) console.log(interest);
368 var nameStr = escape(interest.name.getName());
Wentao Shangc0311e52012-12-03 10:38:23 -0800369 if (LOG > 3) console.log(nameStr);
Wentao Shang0e291c82012-12-02 23:36:29 -0800370
371 var entry = getEntryForRegisteredPrefix(nameStr);
372 if (entry != null) {
373 //console.log(entry);
Wentao Shangf8b4a7d2012-12-25 12:52:07 -0800374 var info = new UpcallInfo(ndn, interest, 0, null);
375 var ret = entry.closure.upcall(Closure.UPCALL_INTEREST, info);
376 if (ret == Closure.RESULT_INTEREST_CONSUMED && info.contentObject != null) {
377 var coBinary = encodeToBinaryContentObject(info.contentObject);
378 // If we directly use coBinary.buffer to feed ws.send(), WebSocket
379 // will end up sending a packet with 10000 bytes of data. That
380 // is, WebSocket will flush the entire buffer in BinaryXMLEncoder
381 // regardless of the offset of the Uint8Array. So we have to
382 // create a new Uint8Array buffer with just the right size and
383 // copy the content from coBinary to the new buffer.
384 // ---Wentao
385 var bytearray = new Uint8Array(coBinary.length);
386 bytearray.set(coBinary);
387
388 self.ws.send(bytearray.buffer);
389 }
Wentao Shang0e291c82012-12-02 23:36:29 -0800390 }
391
392 } else if (decoder.peekStartElement(CCNProtocolDTags.ContentObject)) { // Content packet
Wentao Shang98b595c2012-12-30 10:14:26 -0800393 if (LOG > 3) console.log('ContentObject packet received.');
Wentao Shang0e291c82012-12-02 23:36:29 -0800394
395 var co = new ContentObject();
396 co.from_ccnb(decoder);
Wentao Shangc0311e52012-12-03 10:38:23 -0800397 if (LOG > 3) console.log(co);
Wentao Shangf8b4a7d2012-12-25 12:52:07 -0800398 var nameStr = co.name.getName();
399 console.log(nameStr);
400
Jeff Thompson3dfddaa2012-12-16 17:55:47 -0800401 if (self.ccndid == null && nameStr.match(NDN.ccndIdFetcher) != null) {
Wentao Shang0e291c82012-12-02 23:36:29 -0800402 // We are in starting phase, record publisherPublicKeyDigest in self.ccndid
403 if(!co.signedInfo || !co.signedInfo.publisher
404 || !co.signedInfo.publisher.publisherPublicKeyDigest) {
Wentao Shangc0311e52012-12-03 10:38:23 -0800405 console.log("Cannot contact router, close NDN now.");
Wentao Shang0e291c82012-12-02 23:36:29 -0800406
407 // Close NDN if we fail to connect to a ccn router
408 ndn.readyStatus = NDN.CLOSED;
409 ndn.onclose();
Wentao Shangc0311e52012-12-03 10:38:23 -0800410 //console.log("NDN.onclose event fired.");
Wentao Shang0e291c82012-12-02 23:36:29 -0800411 } else {
Wentao Shangc0311e52012-12-03 10:38:23 -0800412 //console.log('Connected to ccnd.');
Wentao Shang0e291c82012-12-02 23:36:29 -0800413 self.ccndid = co.signedInfo.publisher.publisherPublicKeyDigest;
414 if (LOG>3) console.log(self.ccndid);
415
416 // Call NDN.onopen after success
417 ndn.readyStatus = NDN.OPENED;
418 ndn.onopen();
Wentao Shangc0311e52012-12-03 10:38:23 -0800419 //console.log("NDN.onopen event fired.");
Wentao Shang0e291c82012-12-02 23:36:29 -0800420 }
421 } else {
Jeff Thompson3dfddaa2012-12-16 17:55:47 -0800422 var pitEntry = NDN.getEntryForExpressedInterest(co.name);
Wentao Shang0e291c82012-12-02 23:36:29 -0800423 if (pitEntry != null) {
424 //console.log(pitEntry);
Jeff Thompson3dfddaa2012-12-16 17:55:47 -0800425 // Remove PIT entry from NDN.PITTable
426 var index = NDN.PITTable.indexOf(pitEntry);
427 if (index >= 0)
Wentao Shangfa245962012-12-25 20:26:26 -0800428 NDN.PITTable.splice(index, 1);
Wentao Shangbd63e462012-12-03 16:19:33 -0800429
Wentao Shangfa245962012-12-25 20:26:26 -0800430 var currentClosure = pitEntry.closure;
431
432 // Cancel interest timer
433 clearTimeout(currentClosure.timerID);
434 //console.log("Clear interest timer");
435 //console.log(currentClosure.timerID);
436
437 // Key verification
Wentao Shangfa245962012-12-25 20:26:26 -0800438
Wentao Shang82854bd2012-12-27 14:14:41 -0800439 // Recursive key fetching & verification closure
Wentao Shangfa245962012-12-25 20:26:26 -0800440 var KeyFetchClosure = function KeyFetchClosure(content, closure, key, signature) {
441 this.contentObject = content; // unverified content object
442 this.closure = closure; // closure corresponding to the contentObject
443 this.keyName = key; // name of current key to be fetched
444 this.signature = signature; // hex signature string to be verified
445
446 Closure.call(this);
447 };
448
449 KeyFetchClosure.prototype.upcall = function(kind, upcallInfo) {
450 if (kind == Closure.UPCALL_INTEREST_TIMED_OUT) {
451 console.log("In KeyFetchClosure.upcall: interest time out.");
452 } else if (kind == Closure.UPCALL_CONTENT) {
Wentao Shang82854bd2012-12-27 14:14:41 -0800453 console.log("In KeyFetchClosure.upcall: signature verification passed");
Wentao Shangfa245962012-12-25 20:26:26 -0800454
Wentao Shangb5d0c3e2012-12-30 11:12:03 -0800455 var rsakey = decodeSubjectPublicKeyInfo(upcallInfo.contentObject.content);
Wentao Shang82854bd2012-12-27 14:14:41 -0800456 var verified = rsakey.verifyByteArray(this.contentObject.rawSignatureData, this.signature);
Wentao Shangfa245962012-12-25 20:26:26 -0800457 var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
458
Wentao Shang98b595c2012-12-30 10:14:26 -0800459 //console.log("raise encapsulated closure");
Wentao Shangfa245962012-12-25 20:26:26 -0800460 this.closure.upcall(flag, new UpcallInfo(ndn, null, 0, this.contentObject));
Wentao Shangb5d0c3e2012-12-30 11:12:03 -0800461
462 // Store key in cache
463 var keyEntry = new KeyStoreEntry(keylocator.keyName, rsakey, new Date().getTime());
464 NDN.addKeyEntry(keyEntry);
465 //console.log(NDN.KeyStore);
Wentao Shangfa245962012-12-25 20:26:26 -0800466 }
467 };
468
469 if (co.signedInfo && co.signedInfo.locator && co.signature) {
470 if (LOG > 3) console.log("Key verification...");
471 var sigHex = DataUtils.toHex(co.signature.signature).toLowerCase();
472
473 var keylocator = co.signedInfo.locator;
474 if (keylocator.type == KeyLocatorType.KEYNAME) {
475 console.log("KeyLocator contains KEYNAME");
476 var keyname = keylocator.keyName.contentName.getName();
477 console.log(keyname);
478
Wentao Shang82854bd2012-12-27 14:14:41 -0800479 if (nameStr.match(keyname)) {
480 console.log("Content is key itself");
481
Wentao Shangb5d0c3e2012-12-30 11:12:03 -0800482 var rsakey = decodeSubjectPublicKeyInfo(co.content);
Wentao Shang82854bd2012-12-27 14:14:41 -0800483 var verified = rsakey.verifyByteArray(co.rawSignatureData, sigHex);
484 var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
485
486 currentClosure.upcall(flag, new UpcallInfo(ndn, null, 0, co));
Wentao Shange086b6d2012-12-30 10:17:21 -0800487
Wentao Shangb5d0c3e2012-12-30 11:12:03 -0800488 // SWT: We don't need to store key here since the same key will be
489 // stored again in the closure.
490 //var keyEntry = new KeyStoreEntry(keylocator.keyName, rsakey, new Date().getTime());
491 //NDN.addKeyEntry(keyEntry);
492 //console.log(NDN.KeyStore);
Wentao Shangfa245962012-12-25 20:26:26 -0800493 } else {
494 console.log("Fetch key according to keylocator");
Wentao Shang82854bd2012-12-27 14:14:41 -0800495
496 // Check local key store
497 var keyEntry = NDN.getKeyByName(keylocator.keyName);
498 if (keyEntry) {
499 // Key found, verify now
500 console.log("Local key cache hit");
501 var rsakey = keyEntry.rsaKey;
Wentao Shangb5d0c3e2012-12-30 11:12:03 -0800502 var verified = rsakey.verifyByteArray(co.rawSignatureData, sigHex);
Wentao Shang82854bd2012-12-27 14:14:41 -0800503 var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
504
505 // Raise callback
Wentao Shangb5d0c3e2012-12-30 11:12:03 -0800506 currentClosure.upcall(flag, new UpcallInfo(ndn, null, 0, co));
Wentao Shang82854bd2012-12-27 14:14:41 -0800507 } else {
508 // Not found, fetch now
509 var nextClosure = new KeyFetchClosure(co, currentClosure, keyname, sigHex);
510 var interest = new Interest(keylocator.keyName.contentName.getPrefix(4));
511 interest.interestLifetime = 4.0;
512 self.expressInterest(ndn, interest, nextClosure);
513 }
Wentao Shangfa245962012-12-25 20:26:26 -0800514 }
515 } else if (keylocator.type == KeyLocatorType.KEY) {
516 console.log("Keylocator contains KEY");
Wentao Shangfa245962012-12-25 20:26:26 -0800517
Wentao Shangb5d0c3e2012-12-30 11:12:03 -0800518 var rsakey = decodeSubjectPublicKeyInfo(co.signedInfo.locator.publicKey);
519 var verified = rsakey.verifyByteArray(co.rawSignatureData, sigHex);
Wentao Shangfa245962012-12-25 20:26:26 -0800520 var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
521
522 // Raise callback
523 currentClosure.upcall(Closure.UPCALL_CONTENT, new UpcallInfo(ndn, null, 0, co));
Wentao Shang82854bd2012-12-27 14:14:41 -0800524
Wentao Shangb5d0c3e2012-12-30 11:12:03 -0800525 // Since KeyLocator does not contain key name for this key,
526 // we have no way to store it as a key entry in KeyStore.
Wentao Shangfa245962012-12-25 20:26:26 -0800527 } else {
528 var cert = keylocator.certificate;
529 console.log("KeyLocator contains CERT");
530 console.log(cert);
531
532 // TODO: verify certificate
533 }
534 }
Wentao Shang0e291c82012-12-02 23:36:29 -0800535 }
536 }
537 } else {
538 console.log('Incoming packet is not Interest or ContentObject. Discard now.');
539 }
540
541 delete decoder;
542
543 // Renew StrcutureDecoder and buffer after we process a full packet
544 delete self.structureDecoder;
545 delete self.buffer;
546 self.structureDecoder = new BinaryXMLStructureDecoder();
547 self.buffer = new Uint8Array(self.maxBufferSize);
Wentao Shang2b740e62012-12-07 00:02:53 -0800548 self.bufferOffset = 0;
Wentao Shang0e291c82012-12-02 23:36:29 -0800549 }
550 }
551
552 this.ws.onopen = function(ev) {
Wentao Shangc0311e52012-12-03 10:38:23 -0800553 if (LOG > 3) console.log(ev);
554 if (LOG > 3) console.log('ws.onopen: WebSocket connection opened.');
555 if (LOG > 3) console.log('ws.onopen: ReadyState: ' + this.readyState);
Wentao Shang0e291c82012-12-02 23:36:29 -0800556
557 // Fetch ccndid now
Jeff Thompson3dfddaa2012-12-16 17:55:47 -0800558 var interest = new Interest(new Name(NDN.ccndIdFetcher));
Jeff Thompson42806a12012-12-29 18:19:39 -0800559 interest.interestLifetime = 4000; // milliseconds
Jeff Thompson84db2632012-12-09 22:31:39 -0800560 var subarray = encodeToBinaryInterest(interest);
Wentao Shang0e291c82012-12-02 23:36:29 -0800561
Jeff Thompson84db2632012-12-09 22:31:39 -0800562 var bytes = new Uint8Array(subarray.length);
563 bytes.set(subarray);
Wentao Shang0e291c82012-12-02 23:36:29 -0800564
565 self.ws.send(bytes.buffer);
566 }
567
568 this.ws.onerror = function(ev) {
569 console.log('ws.onerror: ReadyState: ' + this.readyState);
570 console.log(ev);
571 console.log('ws.onerror: WebSocket error: ' + ev.data);
572 }
573
574 this.ws.onclose = function(ev) {
575 console.log('ws.onclose: WebSocket connection closed.');
576 self.ws = null;
577
578 // Close NDN when WebSocket is closed
579 ndn.readyStatus = NDN.CLOSED;
580 ndn.onclose();
Wentao Shangc0311e52012-12-03 10:38:23 -0800581 //console.log("NDN.onclose event fired.");
Wentao Shang0e291c82012-12-02 23:36:29 -0800582 }
Jeff Thompson3dfddaa2012-12-16 17:55:47 -0800583};
Wentao Shang0e291c82012-12-02 23:36:29 -0800584
Wentao Shangc0311e52012-12-03 10:38:23 -0800585WebSocketTransport.prototype.expressInterest = function(ndn, interest, closure) {
586 if (this.ws != null) {
587 //TODO: check local content store first
588
589 var binaryInterest = encodeToBinaryInterest(interest);
590 var bytearray = new Uint8Array(binaryInterest.length);
591 bytearray.set(binaryInterest);
592
Jeff Thompson3dfddaa2012-12-16 17:55:47 -0800593 var pitEntry = new PITEntry(interest, closure);
594 NDN.PITTable.push(pitEntry);
Wentao Shangc0311e52012-12-03 10:38:23 -0800595
596 this.ws.send(bytearray.buffer);
597 if (LOG > 3) console.log('ws.send() returned.');
598
599 // Set interest timer
600 closure.timerID = setTimeout(function() {
Wentao Shangbd63e462012-12-03 16:19:33 -0800601 if (LOG > 3) console.log("Interest time out.");
Wentao Shangc0311e52012-12-03 10:38:23 -0800602
Jeff Thompson3dfddaa2012-12-16 17:55:47 -0800603 // Remove PIT entry from NDN.PITTable
604 var index = NDN.PITTable.indexOf(pitEntry);
605 //console.log(NDN.PITTable);
606 if (index >= 0)
607 NDN.PITTable.splice(index, 1);
608 //console.log(NDN.PITTable);
Wentao Shangc0311e52012-12-03 10:38:23 -0800609 // Raise closure callback
610 closure.upcall(Closure.UPCALL_INTEREST_TIMED_OUT, new UpcallInfo(ndn, interest, 0, null));
Jeff Thompson96978b42012-12-29 21:59:54 -0800611 }, interest.interestLifetime); // interestLifetime is in milliseconds.
Wentao Shangc0311e52012-12-03 10:38:23 -0800612 //console.log(closure.timerID);
613 }
614 else
615 console.log('WebSocket connection is not established.');
616};
617
Wentao Shang0e291c82012-12-02 23:36:29 -0800618
619// For publishing data
620var CSTable = new Array();
621
622var CSEntry = function CSEntry(name, closure) {
623 this.name = name; // String
624 this.closure = closure; // Closure
Jeff Thompson3dfddaa2012-12-16 17:55:47 -0800625};
Wentao Shang0e291c82012-12-02 23:36:29 -0800626
627function getEntryForRegisteredPrefix(name) {
628 for (var i = 0; i < CSTable.length; i++) {
629 if (CSTable[i].name.match(name) != null)
630 return CSTable[i];
631 }
632 return null;
633}
634
635WebSocketTransport.prototype.registerPrefix = function(ndn, name, closure, flag) {
636 if (this.ws != null) {
637 if (this.ccndid == null) {
638 console.log('ccnd node ID unkonwn. Cannot register prefix.');
Wentao Shangc0311e52012-12-03 10:38:23 -0800639 return -1;
Wentao Shang0e291c82012-12-02 23:36:29 -0800640 }
641
642 var fe = new ForwardingEntry('selfreg', name, null, null, 3, 2147483647);
643 var bytes = encodeForwardingEntry(fe);
644
645 var si = new SignedInfo();
646 si.setFields();
647
648 var co = new ContentObject(new Name(), si, bytes, new Signature());
649 co.sign();
650 var coBinary = encodeToBinaryContentObject(co);
651
652 //var nodename = unescape('%00%88%E2%F4%9C%91%16%16%D6%21%8E%A0c%95%A5%A6r%11%E0%A0%82%89%A6%A9%85%AB%D6%E2%065%DB%AF');
653 var nodename = this.ccndid;
654 var interestName = new Name(['ccnx', nodename, 'selfreg', coBinary]);
655
656 var interest = new Interest(interestName);
657 interest.scope = 1;
Wentao Shang0e291c82012-12-02 23:36:29 -0800658 var binaryInterest = encodeToBinaryInterest(interest);
659 // If we directly use binaryInterest.buffer to feed ws.send(),
660 // WebSocket will end up sending a packet with 10000 bytes of data.
661 // That is, WebSocket will flush the entire buffer in BinaryXMLEncoder
662 // regardless of the offset of the Uint8Array. So we have to create
663 // a new Uint8Array buffer with just the right size and copy the
664 // content from binaryInterest to the new buffer.
665 // ---Wentao
666 var bytearray = new Uint8Array(binaryInterest.length);
667 bytearray.set(binaryInterest);
Wentao Shangc0311e52012-12-03 10:38:23 -0800668 if (LOG > 3) console.log('Send Interest registration packet.');
Wentao Shang0e291c82012-12-02 23:36:29 -0800669
670 var csEntry = new CSEntry(name.getName(), closure);
671 CSTable.push(csEntry);
672
673 this.ws.send(bytearray.buffer);
674
675 return 0;
676 } else {
677 console.log('WebSocket connection is not established.');
678 return -1;
679 }
Jeff Thompson3dfddaa2012-12-16 17:55:47 -0800680};
Wentao Shang0e291c82012-12-02 23:36:29 -0800681
Wentao Shangbd63e462012-12-03 16:19:33 -0800682/**
Wentao Shang0e291c82012-12-02 23:36:29 -0800683 * @author: Meki Cheraoui
684 * See COPYING for copyright and distribution information.
685 * This class contains all CCNx tags
686 */
687
688
689var CCNProtocolDTags = {
690
691 /**
692 * Note if you add one of these, add it to the reverse string map as well.
693 * Emphasize getting the work done at compile time over trying to make something
694 * flexible and developer error-proof.
695 */
696
697 Any : 13,
698 Name : 14,
699 Component : 15,
700 Certificate : 16,
701 Collection : 17,
702 CompleteName : 18,
703 Content : 19,
704 SignedInfo : 20,
705 ContentDigest : 21,
706 ContentHash : 22,
707 Count : 24,
708 Header : 25,
709 Interest : 26, /* 20090915 */
710 Key : 27,
711 KeyLocator : 28,
712 KeyName : 29,
713 Length : 30,
714 Link : 31,
715 LinkAuthenticator : 32,
716 NameComponentCount : 33, /* DeprecatedInInterest */
717 RootDigest : 36,
718 Signature : 37,
719 Start : 38,
720 Timestamp : 39,
721 Type : 40,
722 Nonce : 41,
723 Scope : 42,
724 Exclude : 43,
725 Bloom : 44,
726 BloomSeed : 45,
727 AnswerOriginKind : 47,
728 InterestLifetime : 48,
729 Witness : 53,
730 SignatureBits : 54,
731 DigestAlgorithm : 55,
732 BlockSize : 56,
733 FreshnessSeconds : 58,
734 FinalBlockID : 59,
735 PublisherPublicKeyDigest : 60,
736 PublisherCertificateDigest : 61,
737 PublisherIssuerKeyDigest : 62,
738 PublisherIssuerCertificateDigest : 63,
739 ContentObject : 64, /* 20090915 */
740 WrappedKey : 65,
741 WrappingKeyIdentifier : 66,
742 WrapAlgorithm : 67,
743 KeyAlgorithm : 68,
744 Label : 69,
745 EncryptedKey : 70,
746 EncryptedNonceKey : 71,
747 WrappingKeyName : 72,
748 Action : 73,
749 FaceID : 74,
750 IPProto : 75,
751 Host : 76,
752 Port : 77,
753 MulticastInterface : 78,
754 ForwardingFlags : 79,
755 FaceInstance : 80,
756 ForwardingEntry : 81,
757 MulticastTTL : 82,
758 MinSuffixComponents : 83,
759 MaxSuffixComponents : 84,
760 ChildSelector : 85,
761 RepositoryInfo : 86,
762 Version : 87,
763 RepositoryVersion : 88,
764 GlobalPrefix : 89,
765 LocalName : 90,
766 Policy : 91,
767 Namespace : 92,
768 GlobalPrefixName : 93,
769 PolicyVersion : 94,
770 KeyValueSet : 95,
771 KeyValuePair : 96,
772 IntegerValue : 97,
773 DecimalValue : 98,
774 StringValue : 99,
775 BinaryValue : 100,
776 NameValue : 101,
777 Entry : 102,
778 ACL : 103,
779 ParameterizedName : 104,
780 Prefix : 105,
781 Suffix : 106,
782 Root : 107,
783 ProfileName : 108,
784 Parameters : 109,
785 InfoString : 110,
786 // 111 unallocated
787 StatusResponse : 112,
788 StatusCode : 113,
789 StatusText : 114,
790
791 // Sync protocol
792 SyncNode : 115,
793 SyncNodeKind : 116,
794 SyncNodeElement : 117,
795 SyncVersion : 118,
796 SyncNodeElements : 119,
797 SyncContentHash : 120,
798 SyncLeafCount : 121,
799 SyncTreeDepth : 122,
800 SyncByteCount : 123,
801 ConfigSlice : 124,
802 ConfigSliceList : 125,
803 ConfigSliceOp : 126,
804
805 // Remember to keep in sync with schema/tagnames.csvsdict
806 CCNProtocolDataUnit : 17702112,
807 CCNPROTOCOL_DATA_UNIT : "CCNProtocolDataUnit"
808};
809
810var CCNProtocolDTagsStrings = [
811 null, null, null, null, null, null, null, null, null, null, null,
812 null, null,
813 "Any", "Name", "Component", "Certificate", "Collection", "CompleteName",
814 "Content", "SignedInfo", "ContentDigest", "ContentHash", null, "Count", "Header",
815 "Interest", "Key", "KeyLocator", "KeyName", "Length", "Link", "LinkAuthenticator",
816 "NameComponentCount", null, null, "RootDigest", "Signature", "Start", "Timestamp", "Type",
817 "Nonce", "Scope", "Exclude", "Bloom", "BloomSeed", null, "AnswerOriginKind",
818 "InterestLifetime", null, null, null, null, "Witness", "SignatureBits", "DigestAlgorithm", "BlockSize",
819 null, "FreshnessSeconds", "FinalBlockID", "PublisherPublicKeyDigest", "PublisherCertificateDigest",
820 "PublisherIssuerKeyDigest", "PublisherIssuerCertificateDigest", "ContentObject",
821 "WrappedKey", "WrappingKeyIdentifier", "WrapAlgorithm", "KeyAlgorithm", "Label",
822 "EncryptedKey", "EncryptedNonceKey", "WrappingKeyName", "Action", "FaceID", "IPProto",
823 "Host", "Port", "MulticastInterface", "ForwardingFlags", "FaceInstance",
824 "ForwardingEntry", "MulticastTTL", "MinSuffixComponents", "MaxSuffixComponents", "ChildSelector",
825 "RepositoryInfo", "Version", "RepositoryVersion", "GlobalPrefix", "LocalName",
826 "Policy", "Namespace", "GlobalPrefixName", "PolicyVersion", "KeyValueSet", "KeyValuePair",
827 "IntegerValue", "DecimalValue", "StringValue", "BinaryValue", "NameValue", "Entry",
828 "ACL", "ParameterizedName", "Prefix", "Suffix", "Root", "ProfileName", "Parameters",
829 "InfoString", null,
830 "StatusResponse", "StatusCode", "StatusText", "SyncNode", "SyncNodeKind", "SyncNodeElement",
831 "SyncVersion", "SyncNodeElements", "SyncContentHash", "SyncLeafCount", "SyncTreeDepth", "SyncByteCount",
832 "ConfigSlice", "ConfigSliceList", "ConfigSliceOp" ];
833
834
835//TESTING
836//console.log(exports.CCNProtocolDTagsStrings[17]);
837
Wentao Shangbd63e462012-12-03 16:19:33 -0800838/**
Wentao Shang0e291c82012-12-02 23:36:29 -0800839 * @author: Meki Cheraoui
840 * See COPYING for copyright and distribution information.
841 * This class represents CCNTime Objects
842 */
843
844var CCNTime = function CCNTime(
845
846 input) {
847
848
849
850
851 this.NANOS_MAX = 999877929;
852
853 /*if(typeof input =='object'){
854 this.longDate = DataUtils.byteArrayToUnsignedLong(input);
855 this.binaryDate = input;
856 }*/
857 if(typeof input =='number'){
858 this.msec = input;
859 //this.binaryDate = DataUtils.unsignedLongToByteArray(input);
860
861 }
862 else{
863 if(LOG>1) console.log('UNRECOGNIZED TYPE FOR TIME');
864 }
865};
866
867
868CCNTime.prototype.getJavascriptDate = function(){
869 var d = new Date();
870 d.setTime( this.msec );
871 return d
872};
873
874 /**
875 * Create a CCNTime
876 * @param timestamp source timestamp to initialize from, some precision will be lost
877 */
878
879
880 /**
881 * Create a CCNTime from its binary encoding
882 * @param binaryTime12 the binary representation of a CCNTime
883 */
884/*CCNTime.prototype.setDateBinary = function(
885 //byte []
886 binaryTime12) {
887
888
889 if ((null == binaryTime12) || (binaryTime12.length == 0)) {
890 throw new IllegalArgumentException("Invalid binary time!");
891 }
892
893
894 value = 0;
895 for(i = 0; i < binaryTime12.length; i++) {
896 value = value << 8;
897 b = (binaryTime12[i]) & 0xFF;
898 value |= b;
899 }
900
901 //this.date = new Date(value);
902
903};
904
905//byte[]
906CCNTime.prototype.toBinaryTime = function() {
907
908 return this.msec; //unsignedLongToByteArray(this.date.getTime());
909
910}*/
911/*
912unsignedLongToByteArray= function( value) {
913 if( 0 == value )
914 return [0];
915
916 if( 0 <= value && value <= 0x00FF ) {
917 //byte []
918 bb = new Array[1];
919 bb[0] = (value & 0x00FF);
920 return bb;
921 }
922
923
924 //byte []
925 out = null;
926 //int
927 offset = -1;
928 for(var i = 7; i >=0; --i) {
929 //byte
930 b = ((value >> (i * 8)) & 0xFF);
931 if( out == null && b != 0 ) {
932 out = new Array(i+1);//byte[i+1];
933 offset = i;
934 }
935 if( out != null )
936 out[ offset - i ] = b;
937 }
938 return out;
939}*/
940
Wentao Shangbd63e462012-12-03 16:19:33 -0800941/**
Wentao Shang0e291c82012-12-02 23:36:29 -0800942 * @author: Meki Cheraoui, Jeff Thompson
943 * See COPYING for copyright and distribution information.
944 * This class represents a Name as an array of components where each is a byte array.
945 */
946
947/*
948 * Create a new Name from _components.
949 * If _components is a string, parse it as a URI. Otherwise it is an array of components
950 * where each is a string, byte array, ArrayBuffer or Uint8Array.
951 * Convert and store as an array of Uint8Array.
952 * If a component is a string, encode as utf8.
953 */
954var Name = function Name(_components){
955 if( typeof _components == 'string') {
956 if(LOG>3)console.log('Content Name String '+_components);
957 this.components = Name.createNameArray(_components);
958 }
959 else if(typeof _components === 'object'){
960 if(LOG>4)console.log('Content Name Array '+_components);
961 this.components = [];
962 for (var i = 0; i < _components.length; ++i)
963 this.add(_components[i]);
964 }
965 else if(_components==null)
966 this.components =[];
967 else
968 if(LOG>1)console.log("NO CONTENT NAME GIVEN");
969};
970
971Name.prototype.getName = function() {
972 return this.to_uri();
973};
974
975/* Parse name as a URI and return an array of Uint8Array components.
976 *
977 */
978Name.createNameArray = function(name) {
979 name = name.trim();
980 if (name.length <= 0)
981 return [];
982
983 var iColon = name.indexOf(':');
984 if (iColon >= 0) {
985 // Make sure the colon came before a '/'.
986 var iFirstSlash = name.indexOf('/');
987 if (iFirstSlash < 0 || iColon < iFirstSlash)
988 // Omit the leading protocol such as ndn:
989 name = name.substr(iColon + 1, name.length - iColon - 1).trim();
990 }
991
992 if (name[0] == '/') {
993 if (name.length >= 2 && name[1] == '/') {
994 // Strip the authority following "//".
995 var iAfterAuthority = name.indexOf('/', 2);
996 if (iAfterAuthority < 0)
997 // Unusual case: there was only an authority.
998 return [];
999 else
1000 name = name.substr(iAfterAuthority + 1, name.length - iAfterAuthority - 1).trim();
1001 }
1002 else
1003 name = name.substr(1, name.length - 1).trim();
1004 }
1005
1006 var array = name.split('/');
1007
1008 // Unescape the components.
1009 for (var i = 0; i < array.length; ++i) {
1010 var component = unescape(array[i].trim());
1011
1012 if (component.match(/[^.]/) == null) {
1013 // Special case for component of only periods.
1014 if (component.length <= 2) {
1015 // Zero, one or two periods is illegal. Ignore this componenent to be
1016 // consistent with the C implmentation.
1017 // This also gets rid of a trailing '/'.
1018 array.splice(i, 1);
1019 --i;
1020 continue;
1021 }
1022 else
1023 // Remove 3 periods.
1024 array[i] = component.substr(3, component.length - 3);
1025 }
1026 else
1027 array[i] = component;
1028
1029 // Change the component to Uint8Array now.
1030 array[i] = DataUtils.toNumbersFromString(array[i]);
1031 }
1032
1033 return array;
1034}
1035
1036
1037Name.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
1038 decoder.readStartElement(this.getElementLabel());
1039
1040
1041 this.components = new Array(); //new ArrayList<byte []>();
1042
1043 while (decoder.peekStartElement(CCNProtocolDTags.Component)) {
1044 this.add(decoder.readBinaryElement(CCNProtocolDTags.Component));
1045 }
1046
1047 decoder.readEndElement();
1048};
1049
1050Name.prototype.to_ccnb = function(/*XMLEncoder*/ encoder) {
1051
1052 if( this.components ==null )
1053 throw new Error("CANNOT ENCODE EMPTY CONTENT NAME");
1054
1055 encoder.writeStartElement(this.getElementLabel());
1056 var count = this.components.length;
1057 for (var i=0; i < count; i++) {
1058 encoder.writeElement(CCNProtocolDTags.Component, this.components[i]);
1059 }
1060 encoder.writeEndElement();
1061};
1062
1063Name.prototype.getElementLabel = function(){
1064 return CCNProtocolDTags.Name;
1065};
1066
1067/*
1068 * component is a string, byte array, ArrayBuffer or Uint8Array.
1069 * Convert to Uint8Array and add to this Name.
1070 * If a component is a string, encode as utf8.
1071 * Return the converted value.
1072 */
1073Name.prototype.add = function(component){
1074 var result;
1075 if(typeof component == 'string')
1076 result = DataUtils.stringToUtf8Array(component);
1077 else if(typeof component == 'object' && component instanceof Uint8Array)
1078 result = new Uint8Array(component);
1079 else if(typeof component == 'object' && component instanceof ArrayBuffer) {
1080 // Make a copy. Don't use ArrayBuffer.slice since it isn't always supported.
1081 result = new Uint8Array(new ArrayBuffer(component.byteLength));
1082 result.set(new Uint8Array(component));
1083 }
1084 else if(typeof component == 'object')
1085 // Assume component is a byte array. We can't check instanceof Array because
1086 // this doesn't work in JavaScript if the array comes from a different module.
1087 result = new Uint8Array(component);
1088 else
1089 throw new Error("Cannot add Name element at index " + this.components.length +
1090 ": Invalid type");
1091
1092 return this.components.push(result);
1093};
1094
1095// Return the escaped name string according to "CCNx URI Scheme".
1096Name.prototype.to_uri = function() {
1097 var result = "";
1098
1099 for(var i = 0; i < this.components.length; ++i)
1100 result += "/"+ Name.toEscapedString(this.components[i]);
1101
1102 return result;
1103};
1104
1105/*
1106 * Return a new Name with the first nComponents components of this Name.
1107 */
1108Name.prototype.getPrefix = function(nComponents) {
1109 return new Name(this.components.slice(0, nComponents));
1110}
1111
1112/*
1113 * Return a new ArrayBuffer of the component at i.
1114 */
1115Name.prototype.getComponent = function(i) {
1116 var result = new ArrayBuffer(this.components[i].length);
1117 new Uint8Array(result).set(this.components[i]);
1118 return result;
1119}
1120
1121/*
1122 * The "file name" in a name is the last component that isn't blank and doesn't start with one of the
1123 * special marker octets (for version, etc.). Return the index in this.components of
1124 * the file name, or -1 if not found.
1125 */
1126Name.prototype.indexOfFileName = function() {
1127 for (var i = this.components.length - 1; i >= 0; --i) {
1128 var component = this.components[i];
1129 if (component.length <= 0)
1130 continue;
1131
1132 if (component[0] == 0 || component[0] == 0xC0 || component[0] == 0xC1 ||
1133 (component[0] >= 0xF5 && component[0] <= 0xFF))
1134 continue;
1135
1136 return i;
1137 }
1138
1139 return -1;
1140}
1141
Wentao Shangc0311e52012-12-03 10:38:23 -08001142/*
Jeff Thompson3dfddaa2012-12-16 17:55:47 -08001143 * Return true if this Name has the same components as name.
1144 */
1145Name.prototype.equalsName = function(name) {
1146 if (this.components.length != name.components.length)
1147 return false;
1148
1149 // Start from the last component because they are more likely to differ.
1150 for (var i = this.components.length - 1; i >= 0; --i) {
1151 if (!DataUtils.arraysEqual(this.components[i], name.components[i]))
1152 return false;
1153 }
1154
1155 return true;
1156}
1157
1158/*
Wentao Shangc0311e52012-12-03 10:38:23 -08001159 * Find the last component in name that has a ContentDigest and return the digest value as Uint8Array,
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08001160 * or null if not found. See Name.getComponentContentDigestValue.
Wentao Shangc0311e52012-12-03 10:38:23 -08001161 */
1162Name.prototype.getContentDigestValue = function() {
Wentao Shangc0311e52012-12-03 10:38:23 -08001163 for (var i = this.components.length - 1; i >= 0; --i) {
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08001164 var digestValue = Name.getComponentContentDigestValue(this.components[i]);
1165 if (digestValue != null)
1166 return digestValue;
Wentao Shangc0311e52012-12-03 10:38:23 -08001167 }
1168
1169 return null;
1170}
1171
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08001172/*
1173 * If component is a ContentDigest, return the digest value as a Uint8Array subarray (don't modify!).
1174 * If not a ContentDigest, return null.
1175 * A ContentDigest component is Name.ContentDigestPrefix + 32 bytes + Name.ContentDigestSuffix.
1176 */
1177Name.getComponentContentDigestValue = function(component) {
1178 var digestComponentLength = Name.ContentDigestPrefix.length + 32 + Name.ContentDigestSuffix.length;
1179 // Check for the correct length and equal ContentDigestPrefix and ContentDigestSuffix.
1180 if (component.length == digestComponentLength &&
1181 DataUtils.arraysEqual(component.subarray(0, Name.ContentDigestPrefix.length),
1182 Name.ContentDigestPrefix) &&
1183 DataUtils.arraysEqual(component.subarray
1184 (component.length - Name.ContentDigestSuffix.length, component.length),
1185 Name.ContentDigestSuffix))
1186 return component.subarray(Name.ContentDigestPrefix.length, Name.ContentDigestPrefix.length + 32);
1187 else
1188 return null;
1189}
1190
Wentao Shangc0311e52012-12-03 10:38:23 -08001191// Meta GUID "%C1.M.G%C1" + ContentDigest with a 32 byte BLOB.
1192Name.ContentDigestPrefix = new Uint8Array([0xc1, 0x2e, 0x4d, 0x2e, 0x47, 0xc1, 0x01, 0xaa, 0x02, 0x85]);
1193Name.ContentDigestSuffix = new Uint8Array([0x00]);
1194
Wentao Shang0e291c82012-12-02 23:36:29 -08001195/**
1196 * Return component as an escaped string according to "CCNx URI Scheme".
1197 * We can't use encodeURIComponent because that doesn't encode all the characters we want to.
1198 */
1199Name.toEscapedString = function(component) {
1200 var result = "";
1201 var gotNonDot = false;
1202 for (var i = 0; i < component.length; ++i) {
1203 if (component[i] != 0x2e) {
1204 gotNonDot = true;
1205 break;
1206 }
1207 }
1208 if (!gotNonDot) {
1209 // Special case for component of zero or more periods. Add 3 periods.
1210 result = "...";
1211 for (var i = 0; i < component.length; ++i)
1212 result += ".";
1213 }
1214 else {
1215 for (var i = 0; i < component.length; ++i) {
1216 var value = component[i];
1217 // Check for 0-9, A-Z, a-z, (+), (-), (.), (_)
1218 if (value >= 0x30 && value <= 0x39 || value >= 0x41 && value <= 0x5a ||
1219 value >= 0x61 && value <= 0x7a || value == 0x2b || value == 0x2d ||
1220 value == 0x2e || value == 0x5f)
1221 result += String.fromCharCode(value);
1222 else
1223 result += "%" + (value < 16 ? "0" : "") + value.toString(16).toUpperCase();
1224 }
1225 }
1226 return result;
1227};
Wentao Shangbd63e462012-12-03 16:19:33 -08001228/**
Wentao Shang0e291c82012-12-02 23:36:29 -08001229 * @author: Meki Cheraoui
1230 * See COPYING for copyright and distribution information.
1231 * This class represents ContentObject Objects
1232 */
1233var ContentObject = function ContentObject(_name,_signedInfo,_content,_signature){
1234
1235
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08001236 if (typeof _name == 'string') {
Wentao Shang0e291c82012-12-02 23:36:29 -08001237 this.name = new Name(_name);
1238 }
1239 else{
1240 //TODO Check the class of _name
1241 this.name = _name;
1242 }
1243 this.signedInfo = _signedInfo;
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08001244
1245 if (typeof _content == 'string') {
1246 this.content = DataUtils.toNumbersFromString(_content);
1247 } else {
1248 this.content = _content;
1249 }
1250
Wentao Shang0e291c82012-12-02 23:36:29 -08001251 this.signature = _signature;
1252
1253
1254 this.startSIG = null;
1255 this.endSIG = null;
1256
1257 this.startSignedInfo = null;
1258 this.endContent = null;
1259
1260 this.rawSignatureData = null;
1261};
1262
1263ContentObject.prototype.sign = function(){
1264
1265 var n1 = this.encodeObject(this.name);
1266 var n2 = this.encodeObject(this.signedInfo);
1267 var n3 = this.encodeContent();
1268 /*console.log('sign: ');
1269 console.log(n1);
1270 console.log(n2);
1271 console.log(n3);*/
1272
1273 //var n = n1.concat(n2,n3);
1274 var tempBuf = new ArrayBuffer(n1.length + n2.length + n3.length);
1275 var n = new Uint8Array(tempBuf);
1276 //console.log(n);
1277 n.set(n1, 0);
1278 //console.log(n);
1279 n.set(n2, n1.length);
1280 //console.log(n);
1281 n.set(n3, n1.length + n2.length);
1282 //console.log(n);
1283
1284 if(LOG>4)console.log('Signature Data is (binary) '+n);
1285
1286 if(LOG>4)console.log('Signature Data is (RawString)');
1287
1288 if(LOG>4)console.log( DataUtils.toString(n) );
1289
1290 //var sig = DataUtils.toString(n);
1291
1292
1293 var rsa = new RSAKey();
1294
1295 rsa.readPrivateKeyFromPEMString(globalKeyManager.privateKey);
1296
1297 //var hSig = rsa.signString(sig, "sha256");
1298
1299 var hSig = rsa.signByteArrayWithSHA256(n);
1300
1301
1302 if(LOG>4)console.log('SIGNATURE SAVED IS');
1303
1304 if(LOG>4)console.log(hSig);
1305
1306 if(LOG>4)console.log( DataUtils.toNumbers(hSig.trim()));
1307
1308 this.signature.signature = DataUtils.toNumbers(hSig.trim());
1309
1310
1311};
1312
1313ContentObject.prototype.encodeObject = function encodeObject(obj){
1314 var enc = new BinaryXMLEncoder();
1315
1316 obj.to_ccnb(enc);
1317
1318 var num = enc.getReducedOstream();
1319
1320 return num;
1321
1322
1323};
1324
1325ContentObject.prototype.encodeContent = function encodeContent(obj){
1326 var enc = new BinaryXMLEncoder();
1327
1328 enc.writeElement(CCNProtocolDTags.Content, this.content);
1329
1330 var num = enc.getReducedOstream();
1331
1332 return num;
1333
1334
1335};
1336
1337ContentObject.prototype.saveRawData = function(bytes){
1338
1339 var sigBits = bytes.subarray(this.startSIG, this.endSIG);
1340
1341 this.rawSignatureData = sigBits;
1342};
1343
1344ContentObject.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
1345
1346 // TODO VALIDATE THAT ALL FIELDS EXCEPT SIGNATURE ARE PRESENT
1347
1348 decoder.readStartElement(this.getElementLabel());
1349
1350
1351 if( decoder.peekStartElement(CCNProtocolDTags.Signature) ){
1352 this.signature = new Signature();
1353 this.signature.from_ccnb(decoder);
1354 }
1355
1356 //this.endSIG = decoder.offset;
1357
1358 this.startSIG = decoder.offset;
1359
1360 this.name = new Name();
1361 this.name.from_ccnb(decoder);
1362
1363 //this.startSignedInfo = decoder.offset;
1364
1365
1366 if( decoder.peekStartElement(CCNProtocolDTags.SignedInfo) ){
1367 this.signedInfo = new SignedInfo();
1368 this.signedInfo.from_ccnb(decoder);
1369 }
1370
1371 this.content = decoder.readBinaryElement(CCNProtocolDTags.Content);
1372
1373
1374 //this.endContent = decoder.offset;
1375 this.endSIG = decoder.offset;
1376
1377
1378 decoder.readEndElement();
1379
1380 this.saveRawData(decoder.istream);
1381};
1382
1383ContentObject.prototype.to_ccnb = function(/*XMLEncoder*/ encoder) {
1384
1385 //TODO verify name, SignedInfo and Signature is present
1386
1387
1388 encoder.writeStartElement(this.getElementLabel());
1389
1390
1391
1392
1393 if(null!=this.signature) this.signature.to_ccnb(encoder);
1394
1395
1396 this.startSIG = encoder.offset;
1397
1398
1399 if(null!=this.name) this.name.to_ccnb(encoder);
1400
1401 //this.endSIG = encoder.offset;
1402 //this.startSignedInfo = encoder.offset;
1403
1404
1405 if(null!=this.signedInfo) this.signedInfo.to_ccnb(encoder);
1406
1407 encoder.writeElement(CCNProtocolDTags.Content, this.content);
1408
1409
1410 this.endSIG = encoder.offset;
1411
1412 //this.endContent = encoder.offset;
1413
1414
1415 encoder.writeEndElement();
1416
1417 this.saveRawData(encoder.ostream);
1418
1419};
1420
1421ContentObject.prototype.getElementLabel= function(){return CCNProtocolDTags.ContentObject;};
1422
1423/**
1424 * Signature
1425 */
1426var Signature = function Signature(_witness,_signature,_digestAlgorithm) {
1427
1428 this.Witness = _witness;//byte [] _witness;
1429 this.signature = _signature;//byte [] _signature;
1430 this.digestAlgorithm = _digestAlgorithm//String _digestAlgorithm;
1431};
1432
Wentao Shang0e291c82012-12-02 23:36:29 -08001433Signature.prototype.from_ccnb =function( decoder) {
1434 decoder.readStartElement(this.getElementLabel());
1435
1436 if(LOG>4)console.log('STARTED DECODING SIGNATURE ');
1437
1438 if (decoder.peekStartElement(CCNProtocolDTags.DigestAlgorithm)) {
1439
1440 if(LOG>4)console.log('DIGIEST ALGORITHM FOUND');
1441 this.digestAlgorithm = decoder.readUTF8Element(CCNProtocolDTags.DigestAlgorithm);
1442 }
1443 if (decoder.peekStartElement(CCNProtocolDTags.Witness)) {
1444 if(LOG>4)console.log('WITNESS FOUND FOUND');
1445 this.Witness = decoder.readBinaryElement(CCNProtocolDTags.Witness);
1446 }
1447
1448 //FORCE TO READ A SIGNATURE
1449
1450 //if(LOG>4)console.log('SIGNATURE FOUND ');
1451 this.signature = decoder.readBinaryElement(CCNProtocolDTags.SignatureBits);
1452 if(LOG>4)console.log('READ SIGNATURE ');
1453
1454 decoder.readEndElement();
1455
1456};
1457
1458
1459Signature.prototype.to_ccnb= function( encoder){
1460
1461 if (!this.validate()) {
1462 throw new Error("Cannot encode: field values missing.");
1463 }
1464
1465 encoder.writeStartElement(this.getElementLabel());
1466
1467 if ((null != this.digestAlgorithm) && (!this.digestAlgorithm.equals(CCNDigestHelper.DEFAULT_DIGEST_ALGORITHM))) {
1468 encoder.writeElement(CCNProtocolDTags.DigestAlgorithm, OIDLookup.getDigestOID(this.DigestAlgorithm));
1469 }
1470
1471 if (null != this.Witness) {
1472 // needs to handle null witness
1473 encoder.writeElement(CCNProtocolDTags.Witness, this.Witness);
1474 }
1475
1476 encoder.writeElement(CCNProtocolDTags.SignatureBits, this.signature);
1477
1478 encoder.writeEndElement();
1479};
1480
1481Signature.prototype.getElementLabel = function() { return CCNProtocolDTags.Signature; };
1482
1483
1484Signature.prototype.validate = function() {
1485 return null != this.signature;
1486};
1487
1488
1489/**
1490 * SignedInfo
1491 */
1492var ContentType = {DATA:0, ENCR:1, GONE:2, KEY:3, LINK:4, NACK:5};
1493var ContentTypeValue = {0:0x0C04C0, 1:0x10D091,2:0x18E344,3:0x28463F,4:0x2C834A,5:0x34008A};
1494var ContentTypeValueReverse = {0x0C04C0:0, 0x10D091:1,0x18E344:2,0x28463F:3,0x2C834A:4,0x34008A:5};
1495
1496var SignedInfo = function SignedInfo(_publisher,_timestamp,_type,_locator,_freshnessSeconds,_finalBlockID){
1497
1498 //TODO, Check types
1499
1500 this.publisher = _publisher; //publisherPublicKeyDigest
1501 this.timestamp=_timestamp; // CCN Time
1502 this.type=_type; // ContentType
1503 this.locator =_locator;//KeyLocator
1504 this.freshnessSeconds =_freshnessSeconds; // Integer
1505 this.finalBlockID=_finalBlockID; //byte array
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08001506
1507 // SWT: merge setFields() method into constructor
1508 this.setFields();
Wentao Shang0e291c82012-12-02 23:36:29 -08001509
1510};
1511
1512SignedInfo.prototype.setFields = function(){
1513 //BASE64 -> RAW STRING
1514
1515 //this.locator = new KeyLocator( DataUtils.toNumbersFromString(stringCertificate) ,KeyLocatorType.CERTIFICATE );
1516
1517 var publicKeyHex = globalKeyManager.publicKey;
1518
1519 if(LOG>4)console.log('PUBLIC KEY TO WRITE TO CONTENT OBJECT IS ');
1520 if(LOG>4)console.log(publicKeyHex);
1521
1522 var publicKeyBytes = DataUtils.toNumbers(globalKeyManager.publicKey) ;
1523
1524
1525
1526 //var stringCertificate = DataUtils.base64toString(globalKeyManager.certificate);
1527
1528 //if(LOG>3)console.log('string Certificate is '+stringCertificate);
1529
1530 //HEX -> BYTE ARRAY
1531 //var publisherkey = DataUtils.toNumbers(hex_sha256(stringCertificate));
1532
1533 //if(LOG>3)console.log('publisher key is ');
1534 //if(LOG>3)console.log(publisherkey);
1535
1536 var publisherKeyDigest = hex_sha256_from_bytes(publicKeyBytes);
1537
1538 this.publisher = new PublisherPublicKeyDigest( DataUtils.toNumbers( publisherKeyDigest ) );
1539
1540 //this.publisher = new PublisherPublicKeyDigest(publisherkey);
1541
1542 var d = new Date();
1543
1544 var time = d.getTime();
1545
1546
1547 this.timestamp = new CCNTime( time );
1548
1549 if(LOG>4)console.log('TIME msec is');
1550
1551 if(LOG>4)console.log(this.timestamp.msec);
1552
1553 //DATA
1554 this.type = 0;//0x0C04C0;//ContentTypeValue[ContentType.DATA];
1555
1556 //if(LOG>4)console.log('toNumbersFromString(stringCertificate) '+DataUtils.toNumbersFromString(stringCertificate));
1557
1558 if(LOG>4)console.log('PUBLIC KEY TO WRITE TO CONTENT OBJECT IS ');
1559 if(LOG>4)console.log(publicKeyBytes);
1560
1561 this.locator = new KeyLocator( publicKeyBytes ,KeyLocatorType.KEY );
1562
1563 //this.locator = new KeyLocator( DataUtils.toNumbersFromString(stringCertificate) ,KeyLocatorType.CERTIFICATE );
1564
1565};
1566
1567SignedInfo.prototype.from_ccnb = function( decoder){
1568
1569 decoder.readStartElement( this.getElementLabel() );
1570
1571 if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
1572 if(LOG>3) console.log('DECODING PUBLISHER KEY');
1573 this.publisher = new PublisherPublicKeyDigest();
1574 this.publisher.from_ccnb(decoder);
1575 }
1576
1577 if (decoder.peekStartElement(CCNProtocolDTags.Timestamp)) {
1578 this.timestamp = decoder.readDateTime(CCNProtocolDTags.Timestamp);
1579 if(LOG>4)console.log('TIMESTAMP FOUND IS '+this.timestamp);
1580
1581 }
1582
1583 if (decoder.peekStartElement(CCNProtocolDTags.Type)) {
1584 binType = decoder.readBinaryElement(CCNProtocolDTags.Type);//byte []
1585
1586
1587 //TODO Implement type of Key Reading
1588
1589 if(LOG>4)console.log('Binary Type of of Signed Info is '+binType);
1590
1591 this.type = binType;
1592
1593
1594 //TODO Implement type of Key Reading
1595
1596
1597 if (null == this.type) {
1598 throw new Error("Cannot parse signedInfo type: bytes.");
1599 }
1600
1601 } else {
1602 this.type = ContentType.DATA; // default
1603 }
1604
1605 if (decoder.peekStartElement(CCNProtocolDTags.FreshnessSeconds)) {
1606 this.freshnessSeconds = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
1607 if(LOG>4) console.log('FRESHNESS IN SECONDS IS '+ this.freshnessSeconds);
1608 }
1609
1610 if (decoder.peekStartElement(CCNProtocolDTags.FinalBlockID)) {
1611 this.finalBlockID = decoder.readBinaryElement(CCNProtocolDTags.FinalBlockID);
1612 }
1613
1614 if (decoder.peekStartElement(CCNProtocolDTags.KeyLocator)) {
1615 this.locator = new KeyLocator();
1616 this.locator.from_ccnb(decoder);
1617 }
1618
1619 decoder.readEndElement();
1620};
1621
1622SignedInfo.prototype.to_ccnb = function( encoder) {
1623 if (!this.validate()) {
1624 throw new Error("Cannot encode : field values missing.");
1625 }
1626 encoder.writeStartElement(this.getElementLabel());
1627
1628 if (null!=this.publisher) {
1629 if(LOG>3) console.log('ENCODING PUBLISHER KEY' + this.publisher.publisherPublicKeyDigest);
1630
1631 this.publisher.to_ccnb(encoder);
1632 }
1633
1634 if (null!=this.timestamp) {
1635 encoder.writeDateTime(CCNProtocolDTags.Timestamp, this.timestamp );
1636 }
1637
1638 if (null!=this.type && this.type !=0) {
1639
1640 encoder.writeElement(CCNProtocolDTags.type, this.type);
1641 }
1642
1643 if (null!=this.freshnessSeconds) {
1644 encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.freshnessSeconds);
1645 }
1646
1647 if (null!=this.finalBlockID) {
1648 encoder.writeElement(CCNProtocolDTags.FinalBlockID, this.finalBlockID);
1649 }
1650
1651 if (null!=this.locator) {
1652 this.locator.to_ccnb(encoder);
1653 }
1654
1655 encoder.writeEndElement();
1656};
1657
1658SignedInfo.prototype.valueToType = function(){
1659 //for (Entry<byte [], ContentType> entry : ContentValueTypes.entrySet()) {
1660 //if (Arrays.equals(value, entry.getKey()))
1661 //return entry.getValue();
1662 //}
1663 return null;
1664
1665};
1666
1667SignedInfo.prototype.getElementLabel = function() {
1668 return CCNProtocolDTags.SignedInfo;
1669};
1670
1671SignedInfo.prototype.validate = function() {
1672 // We don't do partial matches any more, even though encoder/decoder
1673 // is still pretty generous.
1674 if (null ==this.publisher || null==this.timestamp ||null== this.locator)
1675 return false;
1676 return true;
1677};
1678/*
1679 * Date Format 1.2.3
1680 * (c) 2007-2009 Steven Levithan <stevenlevithan.com>
1681 * MIT license
1682 *
1683 * Includes enhancements by Scott Trenda <scott.trenda.net>
1684 * and Kris Kowal <cixar.com/~kris.kowal/>
1685 *
1686 * Accepts a date, a mask, or a date and a mask.
1687 * Returns a formatted version of the given date.
1688 * The date defaults to the current date/time.
1689 * The mask defaults to dateFormat.masks.default.
1690 */
1691
1692var DateFormat = function () {
1693 var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
1694 timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
1695 timezoneClip = /[^-+\dA-Z]/g,
1696 pad = function (val, len) {
1697 val = String(val);
1698 len = len || 2;
1699 while (val.length < len) val = "0" + val;
1700 return val;
1701 };
1702
1703 // Regexes and supporting functions are cached through closure
1704 return function (date, mask, utc) {
1705 var dF = dateFormat;
1706
1707 // You can't provide utc if you skip other args (use the "UTC:" mask prefix)
1708 if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) {
1709 mask = date;
1710 date = undefined;
1711 }
1712
1713 // Passing date through Date applies Date.parse, if necessary
1714 date = date ? new Date(date) : new Date;
1715 if (isNaN(date)) throw SyntaxError("invalid date");
1716
1717 mask = String(dF.masks[mask] || mask || dF.masks["default"]);
1718
1719 // Allow setting the utc argument via the mask
1720 if (mask.slice(0, 4) == "UTC:") {
1721 mask = mask.slice(4);
1722 utc = true;
1723 }
1724
1725 var _ = utc ? "getUTC" : "get",
1726 d = date[_ + "Date"](),
1727 D = date[_ + "Day"](),
1728 m = date[_ + "Month"](),
1729 y = date[_ + "FullYear"](),
1730 H = date[_ + "Hours"](),
1731 M = date[_ + "Minutes"](),
1732 s = date[_ + "Seconds"](),
1733 L = date[_ + "Milliseconds"](),
1734 o = utc ? 0 : date.getTimezoneOffset(),
1735 flags = {
1736 d: d,
1737 dd: pad(d),
1738 ddd: dF.i18n.dayNames[D],
1739 dddd: dF.i18n.dayNames[D + 7],
1740 m: m + 1,
1741 mm: pad(m + 1),
1742 mmm: dF.i18n.monthNames[m],
1743 mmmm: dF.i18n.monthNames[m + 12],
1744 yy: String(y).slice(2),
1745 yyyy: y,
1746 h: H % 12 || 12,
1747 hh: pad(H % 12 || 12),
1748 H: H,
1749 HH: pad(H),
1750 M: M,
1751 MM: pad(M),
1752 s: s,
1753 ss: pad(s),
1754 l: pad(L, 3),
1755 L: pad(L > 99 ? Math.round(L / 10) : L),
1756 t: H < 12 ? "a" : "p",
1757 tt: H < 12 ? "am" : "pm",
1758 T: H < 12 ? "A" : "P",
1759 TT: H < 12 ? "AM" : "PM",
1760 Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
1761 o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
1762 S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
1763 };
1764
1765 return mask.replace(token, function ($0) {
1766 return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
1767 });
1768 };
1769}();
1770
1771// Some common format strings
1772DateFormat.masks = {
1773 "default": "ddd mmm dd yyyy HH:MM:ss",
1774 shortDate: "m/d/yy",
1775 mediumDate: "mmm d, yyyy",
1776 longDate: "mmmm d, yyyy",
1777 fullDate: "dddd, mmmm d, yyyy",
1778 shortTime: "h:MM TT",
1779 mediumTime: "h:MM:ss TT",
1780 longTime: "h:MM:ss TT Z",
1781 isoDate: "yyyy-mm-dd",
1782 isoTime: "HH:MM:ss",
1783 isoDateTime: "yyyy-mm-dd'T'HH:MM:ss",
1784 isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
1785};
1786
1787// Internationalization strings
1788DateFormat.i18n = {
1789 dayNames: [
1790 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
1791 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
1792 ],
1793 monthNames: [
1794 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
1795 "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
1796 ]
1797};
1798
1799// For convenience...
1800Date.prototype.format = function (mask, utc) {
1801 return dateFormat(this, mask, utc);
1802};
Wentao Shangbd63e462012-12-03 16:19:33 -08001803/**
Wentao Shang0e291c82012-12-02 23:36:29 -08001804 * @author: Meki Cheraoui
1805 * See COPYING for copyright and distribution information.
1806 * This class represents Interest Objects
1807 */
1808
Jeff Thompson42806a12012-12-29 18:19:39 -08001809// _interestLifetime is in milliseconds.
Wentao Shang0e291c82012-12-02 23:36:29 -08001810var Interest = function Interest(_name,_faceInstance,_minSuffixComponents,_maxSuffixComponents,_publisherPublicKeyDigest, _exclude, _childSelector,_answerOriginKind,_scope,_interestLifetime,_nonce){
1811
1812 this.name = _name;
1813 this.faceInstance = _faceInstance;
1814 this.maxSuffixComponents = _maxSuffixComponents;
1815 this.minSuffixComponents = _minSuffixComponents;
1816
1817 this.publisherPublicKeyDigest = _publisherPublicKeyDigest;
1818 this.exclude = _exclude;
1819 this.childSelector = _childSelector;
1820 this.answerOriginKind = _answerOriginKind;
1821 this.scope = _scope;
Jeff Thompson42806a12012-12-29 18:19:39 -08001822 this.interestLifetime = _interestLifetime; // milli seconds
Wentao Shang0e291c82012-12-02 23:36:29 -08001823 this.nonce = _nonce;
1824};
1825
1826Interest.RECURSIVE_POSTFIX = "*";
1827
1828Interest.CHILD_SELECTOR_LEFT = 0;
1829Interest.CHILD_SELECTOR_RIGHT = 1;
1830Interest.ANSWER_CONTENT_STORE = 1;
1831Interest.ANSWER_GENERATED = 2;
1832Interest.ANSWER_STALE = 4; // Stale answer OK
1833Interest.MARK_STALE = 16; // Must have scope 0. Michael calls this a "hack"
1834
1835Interest.DEFAULT_ANSWER_ORIGIN_KIND = Interest.ANSWER_CONTENT_STORE | Interest.ANSWER_GENERATED;
1836
1837
1838Interest.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
1839
1840 decoder.readStartElement(CCNProtocolDTags.Interest);
1841
1842 this.name = new Name();
1843 this.name.from_ccnb(decoder);
1844
1845 if (decoder.peekStartElement(CCNProtocolDTags.MinSuffixComponents))
1846 this.minSuffixComponents = decoder.readIntegerElement(CCNProtocolDTags.MinSuffixComponents);
1847
1848 if (decoder.peekStartElement(CCNProtocolDTags.MaxSuffixComponents))
1849 this.maxSuffixComponents = decoder.readIntegerElement(CCNProtocolDTags.MaxSuffixComponents);
1850
1851 if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
1852 this.publisherPublicKeyDigest = new PublisherPublicKeyDigest();
1853 this.publisherPublicKeyDigest.from_ccnb(decoder);
1854 }
1855
1856 if (decoder.peekStartElement(CCNProtocolDTags.Exclude)) {
1857 this.exclude = new Exclude();
1858 this.exclude.from_ccnb(decoder);
1859 }
1860
1861 if (decoder.peekStartElement(CCNProtocolDTags.ChildSelector))
1862 this.childSelector = decoder.readIntegerElement(CCNProtocolDTags.ChildSelector);
1863
1864 if (decoder.peekStartElement(CCNProtocolDTags.AnswerOriginKind))
1865 this.answerOriginKind = decoder.readIntegerElement(CCNProtocolDTags.AnswerOriginKind);
1866
1867 if (decoder.peekStartElement(CCNProtocolDTags.Scope))
1868 this.scope = decoder.readIntegerElement(CCNProtocolDTags.Scope);
1869
1870 if (decoder.peekStartElement(CCNProtocolDTags.InterestLifetime))
Jeff Thompson42806a12012-12-29 18:19:39 -08001871 this.interestLifetime = 1000.0 * DataUtils.bigEndianToUnsignedInt
Wentao Shang0e291c82012-12-02 23:36:29 -08001872 (decoder.readBinaryElement(CCNProtocolDTags.InterestLifetime)) / 4096;
1873
1874 if (decoder.peekStartElement(CCNProtocolDTags.Nonce))
1875 this.nonce = decoder.readBinaryElement(CCNProtocolDTags.Nonce);
1876
1877 decoder.readEndElement();
1878};
1879
1880Interest.prototype.to_ccnb = function(/*XMLEncoder*/ encoder){
1881 //Could check if name is present
1882
1883 encoder.writeStartElement(CCNProtocolDTags.Interest);
1884
1885 this.name.to_ccnb(encoder);
1886
1887 if (null != this.minSuffixComponents)
1888 encoder.writeElement(CCNProtocolDTags.MinSuffixComponents, this.minSuffixComponents);
1889
1890 if (null != this.maxSuffixComponents)
1891 encoder.writeElement(CCNProtocolDTags.MaxSuffixComponents, this.maxSuffixComponents);
1892
1893 if (null != this.publisherPublicKeyDigest)
1894 this.publisherPublicKeyDigest.to_ccnb(encoder);
1895
1896 if (null != this.exclude)
1897 this.exclude.to_ccnb(encoder);
1898
1899 if (null != this.childSelector)
1900 encoder.writeElement(CCNProtocolDTags.ChildSelector, this.childSelector);
1901
1902 if (this.DEFAULT_ANSWER_ORIGIN_KIND != this.answerOriginKind && this.answerOriginKind!=null)
1903 encoder.writeElement(CCNProtocolDTags.AnswerOriginKind, this.answerOriginKind);
1904
1905 if (null != this.scope)
1906 encoder.writeElement(CCNProtocolDTags.Scope, this.scope);
1907
1908 if (null != this.interestLifetime)
1909 encoder.writeElement(CCNProtocolDTags.InterestLifetime,
Jeff Thompson42806a12012-12-29 18:19:39 -08001910 DataUtils.nonNegativeIntToBigEndian((this.interestLifetime / 1000.0) * 4096));
Wentao Shang0e291c82012-12-02 23:36:29 -08001911
1912 if (null != this.nonce)
1913 encoder.writeElement(CCNProtocolDTags.Nonce, this.nonce);
1914
1915 encoder.writeEndElement();
1916
1917};
1918
1919Interest.prototype.matches_name = function(/*Name*/ name){
1920 var i_name = this.name.components;
1921 var o_name = name.components;
1922
1923 // The intrest name is longer than the name we are checking it against.
1924 if (i_name.length > o_name.length)
1925 return false;
1926
1927 // Check if at least one of given components doesn't match.
1928 for (var i = 0; i < i_name.length; ++i) {
1929 if (!DataUtils.arraysEqual(i_name[i], o_name[i]))
1930 return false;
1931 }
1932
1933 return true;
1934}
1935
1936/**
1937 * Exclude
1938 */
1939var Exclude = function Exclude(_values){
1940
1941 this.OPTIMUM_FILTER_SIZE = 100;
1942
1943
1944 this.values = _values; //array of elements
1945
1946}
1947
1948Exclude.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
1949
1950
1951
1952 decoder.readStartElement(this.getElementLabel());
1953
1954 //TODO APPLY FILTERS/EXCLUDE
1955
1956 //TODO
1957 /*var component;
1958 var any = false;
1959 while ((component = decoder.peekStartElement(CCNProtocolDTags.Component)) ||
1960 (any = decoder.peekStartElement(CCNProtocolDTags.Any)) ||
1961 decoder.peekStartElement(CCNProtocolDTags.Bloom)) {
1962 var ee = component?new ExcludeComponent(): any ? new ExcludeAny() : new BloomFilter();
1963 ee.decode(decoder);
1964 _values.add(ee);
1965 }*/
1966
1967 decoder.readEndElement();
1968
1969};
1970
1971Exclude.prototype.to_ccnb=function(/*XMLEncoder*/ encoder) {
1972 if (!validate()) {
1973 throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
1974 }
1975
1976 if (empty())
1977 return;
1978
1979 encoder.writeStartElement(getElementLabel());
1980
1981 encoder.writeEndElement();
1982
1983 };
1984
1985Exclude.prototype.getElementLabel = function() { return CCNProtocolDTags.Exclude; };
1986
1987
1988/**
1989 * ExcludeAny
1990 */
1991var ExcludeAny = function ExcludeAny() {
1992
1993};
1994
1995ExcludeAny.prototype.from_ccnb = function(decoder) {
1996 decoder.readStartElement(this.getElementLabel());
1997 decoder.readEndElement();
1998};
1999
2000
2001ExcludeAny.prototype.to_ccnb = function( encoder) {
2002 encoder.writeStartElement(this.getElementLabel());
2003 encoder.writeEndElement();
2004};
2005
2006ExcludeAny.prototype.getElementLabel=function() { return CCNProtocolDTags.Any; };
2007
2008
2009/**
2010 * ExcludeComponent
2011 */
2012var ExcludeComponent = function ExcludeComponent(_body) {
2013
2014 //TODO Check BODY is an Array of componenets.
2015
2016 this.body = _body
2017};
2018
2019ExcludeComponent.prototype.from_ccnb = function( decoder) {
2020 this.body = decoder.readBinaryElement(this.getElementLabel());
2021};
2022
2023ExcludeComponent.prototype.to_ccnb = function(encoder) {
2024 encoder.writeElement(this.getElementLabel(), this.body);
2025};
2026
2027ExcludeComponent.prototype.getElementLabel = function() { return CCNProtocolDTags.Component; };
Wentao Shangbd63e462012-12-03 16:19:33 -08002028/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002029 * @author: Meki Cheraoui
2030 * See COPYING for copyright and distribution information.
2031 * This class represents Key Objects
2032 */
2033
2034var Key = function Key(){
2035 /* TODO: Port from PyCCN:
2036 generateRSA()
2037 privateToDER()
2038 publicToDER()
2039 privateToPEM()
2040 publicToPEM()
2041 fromDER()
2042 fromPEM()
2043 */
2044}
2045
2046/**
2047 * KeyLocator
2048 */
2049var KeyLocatorType = {
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08002050 KEY:1,
2051 CERTIFICATE:2,
2052 KEYNAME:3
Wentao Shang0e291c82012-12-02 23:36:29 -08002053};
2054
2055var KeyLocator = function KeyLocator(_input,_type){
2056
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08002057 this.type = _type;
Wentao Shang0e291c82012-12-02 23:36:29 -08002058
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08002059 if (_type == KeyLocatorType.KEYNAME){
2060 if (LOG>3) console.log('KeyLocator: SET KEYNAME');
Wentao Shang0e291c82012-12-02 23:36:29 -08002061 this.keyName = _input;
2062 }
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08002063 else if (_type == KeyLocatorType.KEY){
2064 if (LOG>3) console.log('KeyLocator: SET KEY');
Wentao Shang0e291c82012-12-02 23:36:29 -08002065 this.publicKey = _input;
2066 }
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08002067 else if (_type == KeyLocatorType.CERTIFICATE){
2068 if (LOG>3) console.log('KeyLocator: SET CERTIFICATE');
Wentao Shang0e291c82012-12-02 23:36:29 -08002069 this.certificate = _input;
2070 }
2071
2072};
2073
2074KeyLocator.prototype.from_ccnb = function(decoder) {
2075
Wentao Shang82854bd2012-12-27 14:14:41 -08002076 decoder.readStartElement(this.getElementLabel());
Wentao Shang0e291c82012-12-02 23:36:29 -08002077
Wentao Shang82854bd2012-12-27 14:14:41 -08002078 if (decoder.peekStartElement(CCNProtocolDTags.Key)) {
2079 try {
2080 encodedKey = decoder.readBinaryElement(CCNProtocolDTags.Key);
2081 // This is a DER-encoded SubjectPublicKeyInfo.
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08002082
Wentao Shang82854bd2012-12-27 14:14:41 -08002083 //TODO FIX THIS, This should create a Key Object instead of keeping bytes
2084
2085 this.publicKey = encodedKey;//CryptoUtil.getPublicKey(encodedKey);
2086 this.type = KeyLocatorType.KEY;
2087
2088
2089 if(LOG>4) console.log('PUBLIC KEY FOUND: '+ this.publicKey);
2090 //this.publicKey = encodedKey;
2091
2092
2093 } catch (e) {
2094 throw new Error("Cannot parse key: ", e);
2095 }
2096
2097 if (null == this.publicKey) {
2098 throw new Error("Cannot parse key: ");
Wentao Shang0e291c82012-12-02 23:36:29 -08002099 }
Wentao Shang82854bd2012-12-27 14:14:41 -08002100
2101 } else if ( decoder.peekStartElement(CCNProtocolDTags.Certificate)) {
2102 try {
2103 encodedCert = decoder.readBinaryElement(CCNProtocolDTags.Certificate);
2104
2105 /*
2106 * Certificates not yet working
2107 */
2108
2109 //CertificateFactory factory = CertificateFactory.getInstance("X.509");
2110 //this.certificate = (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(encodedCert));
2111
2112
2113 this.certificate = encodedCert;
2114 this.type = KeyLocatorType.CERTIFICATE;
2115
2116 if(LOG>4) console.log('CERTIFICATE FOUND: '+ this.certificate);
2117
2118 } catch ( e) {
2119 throw new Error("Cannot decode certificate: " + e);
2120 }
2121 if (null == this.certificate) {
2122 throw new Error("Cannot parse certificate! ");
2123 }
2124 } else {
2125 this.type = KeyLocatorType.KEYNAME;
2126
2127 this.keyName = new KeyName();
2128 this.keyName.from_ccnb(decoder);
Wentao Shang0e291c82012-12-02 23:36:29 -08002129 }
Wentao Shang82854bd2012-12-27 14:14:41 -08002130 decoder.readEndElement();
2131};
Wentao Shang0e291c82012-12-02 23:36:29 -08002132
2133
Wentao Shang82854bd2012-12-27 14:14:41 -08002134KeyLocator.prototype.to_ccnb = function( encoder) {
2135
2136 if(LOG>4) console.log('type is is ' + this.type);
2137 //TODO Check if Name is missing
2138 if (!this.validate()) {
2139 throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
2140 }
Wentao Shang0e291c82012-12-02 23:36:29 -08002141
Wentao Shang82854bd2012-12-27 14:14:41 -08002142
2143 //TODO FIX THIS TOO
2144 encoder.writeStartElement(this.getElementLabel());
2145
2146 if (this.type == KeyLocatorType.KEY) {
2147 if(LOG>5)console.log('About to encode a public key' +this.publicKey);
2148 encoder.writeElement(CCNProtocolDTags.Key, this.publicKey);
Wentao Shang0e291c82012-12-02 23:36:29 -08002149
Wentao Shang82854bd2012-12-27 14:14:41 -08002150 } else if (this.type == KeyLocatorType.CERTIFICATE) {
Wentao Shang0e291c82012-12-02 23:36:29 -08002151
Wentao Shang82854bd2012-12-27 14:14:41 -08002152 try {
2153 encoder.writeElement(CCNProtocolDTags.Certificate, this.certificate);
2154 } catch ( e) {
2155 throw new Error("CertificateEncodingException attempting to write key locator: " + e);
Wentao Shang0e291c82012-12-02 23:36:29 -08002156 }
Wentao Shang0e291c82012-12-02 23:36:29 -08002157
Wentao Shang82854bd2012-12-27 14:14:41 -08002158 } else if (this.type == KeyLocatorType.KEYNAME) {
2159
2160 this.keyName.to_ccnb(encoder);
2161 }
2162 encoder.writeEndElement();
2163
Wentao Shang0e291c82012-12-02 23:36:29 -08002164};
2165
2166KeyLocator.prototype.getElementLabel = function() {
2167 return CCNProtocolDTags.KeyLocator;
2168};
2169
2170KeyLocator.prototype.validate = function() {
2171 return ( (null != this.keyName) || (null != this.publicKey) || (null != this.certificate) );
2172};
2173
2174/**
2175 * KeyName is only used by KeyLocator.
2176 */
2177var KeyName = function KeyName() {
Wentao Shang98b595c2012-12-30 10:14:26 -08002178 this.contentName = this.contentName; //contentName
2179 this.publisherID = this.publisherID; //publisherID
Wentao Shang0e291c82012-12-02 23:36:29 -08002180
2181};
2182
2183KeyName.prototype.from_ccnb=function( decoder){
2184
2185
2186 decoder.readStartElement(this.getElementLabel());
2187
2188 this.contentName = new Name();
2189 this.contentName.from_ccnb(decoder);
2190
2191 if(LOG>4) console.log('KEY NAME FOUND: ');
2192
2193 if ( PublisherID.peek(decoder) ) {
2194 this.publisherID = new PublisherID();
2195 this.publisherID.from_ccnb(decoder);
2196 }
2197
2198 decoder.readEndElement();
2199};
2200
2201KeyName.prototype.to_ccnb = function( encoder) {
2202 if (!this.validate()) {
2203 throw new Error("Cannot encode : field values missing.");
2204 }
2205
2206 encoder.writeStartElement(this.getElementLabel());
2207
2208 this.contentName.to_ccnb(encoder);
2209 if (null != this.publisherID)
2210 this.publisherID.to_ccnb(encoder);
2211
2212 encoder.writeEndElement();
2213};
2214
2215KeyName.prototype.getElementLabel = function() { return CCNProtocolDTags.KeyName; };
2216
2217KeyName.prototype.validate = function() {
2218 // DKS -- do we do recursive validation?
2219 // null signedInfo ok
2220 return (null != this.contentName);
2221};
Wentao Shang82854bd2012-12-27 14:14:41 -08002222
2223KeyName.prototype.matches_name = function(/*Name*/ name) {
2224 var i_name = this.contentName.components;
2225 var o_name = name.components;
2226
2227 // The intrest name is longer than the name we are checking it against.
2228 if (i_name.length > o_name.length)
2229 return false;
2230
2231 // Check if at least one of given components doesn't match.
2232 for (var i = 0; i < i_name.length; ++i) {
2233 if (!DataUtils.arraysEqual(i_name[i], o_name[i]))
2234 return false;
2235 }
2236
2237 return true;
2238}
2239
Wentao Shangbd63e462012-12-03 16:19:33 -08002240/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002241 * @author: Meki Cheraoui
2242 * See COPYING for copyright and distribution information.
2243 * This class represents Publisher and PublisherType Objects
2244 */
2245
2246
2247var PublisherType = function PublisherType(_tag){
2248 this.KEY =(CCNProtocolDTags.PublisherPublicKeyDigest);
2249 this.CERTIFICATE= (CCNProtocolDTags.PublisherCertificateDigest);
2250 this.ISSUER_KEY= (CCNProtocolDTags.PublisherIssuerKeyDigest);
2251 this.ISSUER_CERTIFICATE =(CCNProtocolDTags.PublisherIssuerCertificateDigest);
2252
2253 this.Tag = _tag;
2254};
2255
2256var isTypeTagVal = function(tagVal) {
2257 if ((tagVal == CCNProtocolDTags.PublisherPublicKeyDigest) ||
2258 (tagVal == CCNProtocolDTags.PublisherCertificateDigest) ||
2259 (tagVal == CCNProtocolDTags.PublisherIssuerKeyDigest) ||
2260 (tagVal == CCNProtocolDTags.PublisherIssuerCertificateDigest)) {
2261 return true;
2262 }
2263 return false;
2264};
2265
2266
2267
2268
2269var PublisherID = function PublisherID() {
2270
2271 this.PUBLISHER_ID_DIGEST_ALGORITHM = "SHA-256";
2272 this.PUBLISHER_ID_LEN = 256/8;
2273
2274 //TODO, implement publisherID creation and key creation
2275
2276 //TODO implement generatePublicKeyDigest
2277 this.publisherID =null;//= generatePublicKeyDigest(key);//ByteArray
2278
2279 //TODO implement generate key
2280 //CryptoUtil.generateKeyID(PUBLISHER_ID_DIGEST_ALGORITHM, key);
2281 this.publisherType = null;//isIssuer ? PublisherType.ISSUER_KEY : PublisherType.KEY;//publisher Type
2282
2283};
2284
2285
2286PublisherID.prototype.from_ccnb = function(decoder) {
2287
2288 // We have a choice here of one of 4 binary element types.
2289 var nextTag = decoder.peekStartElementAsLong();
2290
2291 if (null == nextTag) {
2292 throw new Error("Cannot parse publisher ID.");
2293 }
2294
2295 this.publisherType = new PublisherType(nextTag);
2296
2297 if (!isTypeTagVal(nextTag)) {
2298 throw new Error("Invalid publisher ID, got unexpected type: " + nextTag);
2299 }
2300 this.publisherID = decoder.readBinaryElement(nextTag);
2301 if (null == this.publisherID) {
2302 throw new ContentDecodingException(new Error("Cannot parse publisher ID of type : " + nextTag + "."));
2303 }
2304};
2305
2306PublisherID.prototype.to_ccnb = function(encoder) {
2307 if (!this.validate()) {
2308 throw new Error("Cannot encode " + this.getClass().getName() + ": field values missing.");
2309 }
2310
2311 encoder.writeElement(this.getElementLabel(), this.publisherID);
2312};
2313
2314PublisherID.peek = function(/* XMLDecoder */ decoder) {
2315
2316 //Long
2317 nextTag = decoder.peekStartElementAsLong();
2318
2319 if (null == nextTag) {
2320 // on end element
2321 return false;
2322 }
2323 return (isTypeTagVal(nextTag));
2324 };
2325
2326PublisherID.prototype.getElementLabel = function() {
2327 return this.publisherType.Tag;
2328};
2329
2330PublisherID.prototype.validate = function(){
2331 return ((null != id() && (null != type())));
2332};
2333
2334
2335
Wentao Shangbd63e462012-12-03 16:19:33 -08002336/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002337 * @author: Meki Cheraoui
2338 * See COPYING for copyright and distribution information.
2339 * This class represents PublisherPublicKeyDigest Objects
2340 */
2341var PublisherPublicKeyDigest = function PublisherPublicKeyDigest(_pkd){
2342
2343 //this.PUBLISHER_ID_LEN = 256/8;
2344 this.PUBLISHER_ID_LEN = 512/8;
2345
2346
2347 this.publisherPublicKeyDigest = _pkd;
2348 //if( typeof _pkd == "object") this.publisherPublicKeyDigest = _pkd; // Byte Array
2349 //else if( typeof _pkd == "PublicKey") ;//TODO...
2350
2351};
2352
2353PublisherPublicKeyDigest.prototype.from_ccnb = function( decoder) {
2354
2355 this.publisherPublicKeyDigest = decoder.readBinaryElement(this.getElementLabel());
2356
2357 if(LOG>4)console.log('Publisher public key digest is ' + this.publisherPublicKeyDigest);
2358
2359 if (null == this.publisherPublicKeyDigest) {
2360 throw new Error("Cannot parse publisher key digest.");
2361 }
2362
2363 //TODO check if the length of the PublisherPublicKeyDigest is correct ( Security reason)
2364
2365 if (this.publisherPublicKeyDigest.length != this.PUBLISHER_ID_LEN) {
2366 if (LOG > 0)
2367 console.log('LENGTH OF PUBLISHER ID IS WRONG! Expected ' + this.PUBLISHER_ID_LEN + ", got " + this.publisherPublicKeyDigest.length);
2368
2369 //this.publisherPublicKeyDigest = new PublisherPublicKeyDigest(this.PublisherPublicKeyDigest).PublisherKeyDigest;
2370 }
2371 };
2372
2373PublisherPublicKeyDigest.prototype.to_ccnb= function( encoder) {
2374 //TODO Check that the ByteArray for the key is present
2375 if (!this.validate()) {
2376 throw new Error("Cannot encode : field values missing.");
2377 }
2378 if(LOG>3) console.log('PUBLISHER KEY DIGEST IS'+this.publisherPublicKeyDigest);
2379 encoder.writeElement(this.getElementLabel(), this.publisherPublicKeyDigest);
2380};
2381
2382PublisherPublicKeyDigest.prototype.getElementLabel = function() { return CCNProtocolDTags.PublisherPublicKeyDigest; };
2383
2384PublisherPublicKeyDigest.prototype.validate =function() {
2385 return (null != this.publisherPublicKeyDigest);
2386};
Wentao Shangbd63e462012-12-03 16:19:33 -08002387/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002388 * @author: Meki Cheraoui
2389 * See COPYING for copyright and distribution information.
2390 * This class represents Face Instances
2391 */
2392
2393var NetworkProtocol = { TCP:6, UDP:17};
2394
2395var FaceInstance = function FaceInstance(
2396 _action,
2397 _publisherPublicKeyDigest,
2398 _faceID,
2399 _ipProto,
2400 _host,
2401 _port,
2402 _multicastInterface,
2403 _multicastTTL,
2404 _freshnessSeconds){
2405
2406
2407 this.action = _action;
2408 this.publisherPublicKeyDigest = _publisherPublicKeyDigest;
2409 this.faceID = _faceID;
2410 this.ipProto = _ipProto;
2411 this.host = _host;
2412 this.Port = _port;
2413 this.multicastInterface =_multicastInterface;
2414 this.multicastTTL =_multicastTTL;
2415 this.freshnessSeconds = _freshnessSeconds;
2416
2417 //action ::= ("newface" | "destroyface" | "queryface")
2418 //publisherPublicKeyDigest ::= SHA-256 digest
2419 //faceID ::= nonNegativeInteger
2420 //ipProto ::= nonNegativeInteger [IANA protocol number, 6=TCP, 17=UDP]
2421 //Host ::= textual representation of numeric IPv4 or IPv6 address
2422 //Port ::= nonNegativeInteger [1..65535]
2423 //MulticastInterface ::= textual representation of numeric IPv4 or IPv6 address
2424 //MulticastTTL ::= nonNegativeInteger [1..255]
2425 //freshnessSeconds ::= nonNegativeInteger
2426
2427};
2428
2429/**
2430 * Used by NetworkObject to decode the object from a network stream.
2431 */
2432FaceInstance.prototype.from_ccnb = function(//XMLDecoder
2433 decoder) {
2434
2435 decoder.readStartElement(this.getElementLabel());
2436
2437 if (decoder.peekStartElement(CCNProtocolDTags.Action)) {
2438
2439 this.action = decoder.readUTF8Element(CCNProtocolDTags.Action);
2440
2441 }
2442 if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
2443
2444 this.publisherPublicKeyDigest = new PublisherPublicKeyDigest();
2445 this.publisherPublicKeyDigest.from_ccnb(decoder);
2446
2447 }
2448 if (decoder.peekStartElement(CCNProtocolDTags.FaceID)) {
2449
2450 this.faceID = decoder.readIntegerElement(CCNProtocolDTags.FaceID);
2451
2452 }
2453 if (decoder.peekStartElement(CCNProtocolDTags.IPProto)) {
2454
2455 //int
2456 var pI = decoder.readIntegerElement(CCNProtocolDTags.IPProto);
2457
2458 this.ipProto = null;
2459
2460 if (NetworkProtocol.TCP == pI) {
2461
2462 this.ipProto = NetworkProtocol.TCP;
2463
2464 } else if (NetworkProtocol.UDP == pI) {
2465
2466 this.ipProto = NetworkProtocol.UDP;
2467
2468 } else {
2469
2470 throw new Error("FaceInstance.decoder. Invalid " +
2471 CCNProtocolDTags.tagToString(CCNProtocolDTags.IPProto) + " field: " + pI);
2472
2473 }
2474 }
2475
2476 if (decoder.peekStartElement(CCNProtocolDTags.Host)) {
2477
2478 this.host = decoder.readUTF8Element(CCNProtocolDTags.Host);
2479
2480 }
2481
2482 if (decoder.peekStartElement(CCNProtocolDTags.Port)) {
2483 this.Port = decoder.readIntegerElement(CCNProtocolDTags.Port);
2484 }
2485
2486 if (decoder.peekStartElement(CCNProtocolDTags.MulticastInterface)) {
2487 this.multicastInterface = decoder.readUTF8Element(CCNProtocolDTags.MulticastInterface);
2488 }
2489
2490 if (decoder.peekStartElement(CCNProtocolDTags.MulticastTTL)) {
2491 this.multicastTTL = decoder.readIntegerElement(CCNProtocolDTags.MulticastTTL);
2492 }
2493
2494 if (decoder.peekStartElement(CCNProtocolDTags.FreshnessSeconds)) {
2495 this.freshnessSeconds = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
2496 }
2497 decoder.readEndElement();
2498}
2499
2500/**
2501 * Used by NetworkObject to encode the object to a network stream.
2502 */
2503FaceInstance.prototype.to_ccnb = function(//XMLEncoder
2504 encoder){
2505
2506 //if (!this.validate()) {
2507 //throw new Error("Cannot encode : field values missing.");
2508 //throw new Error("")
2509 //}
2510 encoder.writeStartElement(this.getElementLabel());
2511
2512 if (null != this.action && this.action.length != 0)
2513 encoder.writeElement(CCNProtocolDTags.Action, this.action);
2514
2515 if (null != this.publisherPublicKeyDigest) {
2516 this.publisherPublicKeyDigest.to_ccnb(encoder);
2517 }
2518 if (null != this.faceID) {
2519 encoder.writeElement(CCNProtocolDTags.FaceID, this.faceID);
2520 }
2521 if (null != this.ipProto) {
2522 //encoder.writeElement(CCNProtocolDTags.IPProto, this.IpProto.value());
2523 encoder.writeElement(CCNProtocolDTags.IPProto, this.ipProto);
2524 }
2525 if (null != this.host && this.host.length != 0) {
2526 encoder.writeElement(CCNProtocolDTags.Host, this.host);
2527 }
2528 if (null != this.Port) {
2529 encoder.writeElement(CCNProtocolDTags.Port, this.Port);
2530 }
2531 if (null != this.multicastInterface && this.multicastInterface.length != 0) {
2532 encoder.writeElement(CCNProtocolDTags.MulticastInterface, this.multicastInterface);
2533 }
2534 if (null != this.multicastTTL) {
2535 encoder.writeElement(CCNProtocolDTags.MulticastTTL, this.multicastTTL);
2536 }
2537 if (null != this.freshnessSeconds) {
2538 encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.freshnessSeconds);
2539 }
2540 encoder.writeEndElement();
2541}
2542
2543
2544FaceInstance.prototype.getElementLabel= function(){return CCNProtocolDTags.FaceInstance;};
2545
Wentao Shangbd63e462012-12-03 16:19:33 -08002546/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002547 * @author: Meki Cheraoui
2548 * See COPYING for copyright and distribution information.
2549 * This class represents Forwarding Entries
2550 */
2551
2552var ForwardingEntry = function ForwardingEntry(
2553 //ActionType
2554 _action,
2555 //Name
2556 _prefixName,
2557 //PublisherPublicKeyDigest
2558 _ccndId,
2559 //Integer
2560 _faceID,
2561 //Integer
2562 _flags,
2563 //Integer
2564 _lifetime){
2565
2566
2567
2568 //String
2569 this.action = _action;
2570 //Name\
2571 this.prefixName = _prefixName;
2572 //PublisherPublicKeyDigest
2573 this.ccndID = _ccndId;
2574 //Integer
2575 this.faceID = _faceID;
2576 //Integer
2577 this.flags = _flags;
2578 //Integer
2579 this.lifetime = _lifetime; // in seconds
2580
2581};
2582
2583ForwardingEntry.prototype.from_ccnb =function(
2584 //XMLDecoder
2585 decoder)
2586 //throws ContentDecodingException
2587 {
2588 decoder.readStartElement(this.getElementLabel());
2589 if (decoder.peekStartElement(CCNProtocolDTags.Action)) {
2590 this.action = decoder.readUTF8Element(CCNProtocolDTags.Action);
2591 }
2592 if (decoder.peekStartElement(CCNProtocolDTags.Name)) {
2593 this.prefixName = new Name();
2594 this.prefixName.from_ccnb(decoder) ;
2595 }
2596 if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
2597 this.CcndId = new PublisherPublicKeyDigest();
2598 this.CcndId.from_ccnb(decoder);
2599 }
2600 if (decoder.peekStartElement(CCNProtocolDTags.FaceID)) {
2601 this.faceID = decoder.readIntegerElement(CCNProtocolDTags.FaceID);
2602 }
2603 if (decoder.peekStartElement(CCNProtocolDTags.ForwardingFlags)) {
2604 this.flags = decoder.readIntegerElement(CCNProtocolDTags.ForwardingFlags);
2605 }
2606 if (decoder.peekStartElement(CCNProtocolDTags.FreshnessSeconds)) {
2607 this.lifetime = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
2608 }
2609 decoder.readEndElement();
2610 };
2611
2612 /**
2613 * Used by NetworkObject to encode the object to a network stream.
2614 */
2615ForwardingEntry.prototype.to_ccnb =function(
2616 //XMLEncoder
2617encoder)
2618{
2619
2620
2621 //if (!validate()) {
2622 //throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
2623 //}
2624 encoder.writeStartElement(this.getElementLabel());
2625 if (null != this.action && this.action.length != 0)
2626 encoder.writeElement(CCNProtocolDTags.Action, this.action);
2627 if (null != this.prefixName) {
2628 this.prefixName.to_ccnb(encoder);
2629 }
2630 if (null != this.CcndId) {
2631 this.CcndId.to_ccnb(encoder);
2632 }
2633 if (null != this.faceID) {
2634 encoder.writeElement(CCNProtocolDTags.FaceID, this.faceID);
2635 }
2636 if (null != this.flags) {
2637 encoder.writeElement(CCNProtocolDTags.ForwardingFlags, this.flags);
2638 }
2639 if (null != this.lifetime) {
2640 encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.lifetime);
2641 }
2642 encoder.writeEndElement();
2643 };
2644
2645ForwardingEntry.prototype.getElementLabel = function() { return CCNProtocolDTags.ForwardingEntry; }
Wentao Shangbd63e462012-12-03 16:19:33 -08002646/**
Jeff Thompson96978b42012-12-29 21:59:54 -08002647 * @author: Jeff Thompson
2648 * See COPYING for copyright and distribution information.
2649 * Encapsulate an Uint8Array and support dynamic reallocation.
2650 */
2651
2652/*
2653 * Create a DynamicUint8Array where this.array is a Uint8Array of size length.
2654 * If length is not supplied, use a default initial length.
2655 * The methods will update this.length.
2656 * To access the array, use this.array or call subarray.
2657 */
2658var DynamicUint8Array = function DynamicUint8Array(length) {
2659 if (!length)
2660 length = 16;
2661
2662 this.array = new Uint8Array(length);
2663 this.length = length;
2664};
2665
2666/*
2667 * Ensure that this.array has the length, reallocate and copy if necessary.
2668 * Update this.length which may be greater than length.
2669 */
2670DynamicUint8Array.prototype.ensureLength = function(length) {
2671 if (this.array.length >= length)
2672 return;
2673
2674 // See if double is enough.
2675 var newLength = this.array.length * 2;
2676 if (length > newLength)
2677 // The needed length is much greater, so use it.
2678 newLength = length;
2679
2680 var newArray = new Uint8Array(newLength);
2681 newArray.set(this.array);
2682 this.array = newArray;
2683 this.length = newLength;
2684};
2685
2686/*
2687 * Call this.array.set(value, offset), reallocating if necessary.
2688 */
2689DynamicUint8Array.prototype.set = function(value, offset) {
2690 this.ensureLength(value.length + offset);
2691 this.array.set(value, offset);
2692};
2693
2694/*
2695 * Return this.array.subarray(begin, end);
2696 */
2697DynamicUint8Array.prototype.subarray = function(begin, end) {
2698 return this.array.subarray(begin, end);
2699}
2700/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002701 * This class is used to encode ccnb binary elements (blob, type/value pairs).
2702 *
2703 * @author: Meki Cheraoui
2704 * See COPYING for copyright and distribution information.
2705 */
2706
2707var XML_EXT = 0x00;
2708
2709var XML_TAG = 0x01;
2710
2711var XML_DTAG = 0x02;
2712
2713var XML_ATTR = 0x03;
2714
2715var XML_DATTR = 0x04;
2716
2717var XML_BLOB = 0x05;
2718
2719var XML_UDATA = 0x06;
2720
2721var XML_CLOSE = 0x0;
2722
2723var XML_SUBTYPE_PROCESSING_INSTRUCTIONS = 16;
2724
2725
2726var XML_TT_BITS = 3;
2727var XML_TT_MASK = ((1 << XML_TT_BITS) - 1);
2728var XML_TT_VAL_BITS = XML_TT_BITS + 1;
2729var XML_TT_VAL_MASK = ((1 << (XML_TT_VAL_BITS)) - 1);
2730var XML_REG_VAL_BITS = 7;
2731var XML_REG_VAL_MASK = ((1 << XML_REG_VAL_BITS) - 1);
2732var XML_TT_NO_MORE = (1 << XML_REG_VAL_BITS); // 0x80
2733var BYTE_MASK = 0xFF;
2734var LONG_BYTES = 8;
2735var LONG_BITS = 64;
2736
2737var bits_11 = 0x0000007FF;
2738var bits_18 = 0x00003FFFF;
2739var bits_32 = 0x0FFFFFFFF;
2740
2741
2742var BinaryXMLEncoder = function BinaryXMLEncoder(){
Jeff Thompson96978b42012-12-29 21:59:54 -08002743 this.ostream = new DynamicUint8Array(100);
Wentao Shang0e291c82012-12-02 23:36:29 -08002744 this.offset =0;
2745 this.CODEC_NAME = "Binary";
2746};
2747
2748/*
2749 * Encode utf8Content as utf8.
2750 */
2751BinaryXMLEncoder.prototype.writeUString = function(/*String*/ utf8Content) {
2752 this.encodeUString(utf8Content, XML_UDATA);
2753};
2754
2755
2756BinaryXMLEncoder.prototype.writeBlob = function(
2757 /*Uint8Array*/ binaryContent
2758 ) {
2759
2760 if(LOG >3) console.log(binaryContent);
2761
2762 this.encodeBlob(binaryContent, binaryContent.length);
2763};
2764
2765
2766BinaryXMLEncoder.prototype.writeStartElement = function(
2767 /*String*/ tag,
2768 /*TreeMap<String,String>*/ attributes
2769 ) {
2770
2771 /*Long*/ var dictionaryVal = tag; //stringToTag(tag);
2772
2773 if (null == dictionaryVal) {
2774 this.encodeUString(tag, XML_TAG);
2775 } else {
2776 this.encodeTypeAndVal(XML_DTAG, dictionaryVal);
2777 }
2778
2779 if (null != attributes) {
2780 this.writeAttributes(attributes);
2781 }
2782};
2783
2784
2785BinaryXMLEncoder.prototype.writeEndElement = function() {
Jeff Thompson96978b42012-12-29 21:59:54 -08002786 this.ostream.ensureLength(this.offset + 1);
2787 this.ostream.array[this.offset] = XML_CLOSE;
Wentao Shang0e291c82012-12-02 23:36:29 -08002788 this.offset += 1;
2789}
2790
2791
2792BinaryXMLEncoder.prototype.writeAttributes = function(/*TreeMap<String,String>*/ attributes) {
2793 if (null == attributes) {
2794 return;
2795 }
2796
2797 // the keySet of a TreeMap is sorted.
2798
2799 for(var i=0; i<attributes.length;i++){
2800 var strAttr = attributes[i].k;
2801 var strValue = attributes[i].v;
2802
2803 var dictionaryAttr = stringToTag(strAttr);
2804 if (null == dictionaryAttr) {
2805 // not in dictionary, encode as attr
2806 // compressed format wants length of tag represented as length-1
2807 // to save that extra bit, as tag cannot be 0 length.
2808 // encodeUString knows to do that.
2809 this.encodeUString(strAttr, XML_ATTR);
2810 } else {
2811 this.encodeTypeAndVal(XML_DATTR, dictionaryAttr);
2812 }
2813 // Write value
2814 this.encodeUString(strValue);
2815
2816 }
2817}
2818
2819
2820//returns a string
2821stringToTag = function(/*long*/ tagVal) {
2822 if ((tagVal >= 0) && (tagVal < CCNProtocolDTagsStrings.length)) {
2823 return CCNProtocolDTagsStrings[tagVal];
2824 } else if (tagVal == CCNProtocolDTags.CCNProtocolDataUnit) {
2825 return CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT;
2826 }
2827 return null;
2828};
2829
2830//returns a Long
2831tagToString = function(/*String*/ tagName) {
2832 // the slow way, but right now we don't care.... want a static lookup for the forward direction
2833 for (var i=0; i < CCNProtocolDTagsStrings.length; ++i) {
2834 if ((null != CCNProtocolDTagsStrings[i]) && (CCNProtocolDTagsStrings[i] == tagName)) {
2835 return i;
2836 }
2837 }
2838 if (CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT == tagName) {
2839 return CCNProtocolDTags.CCNProtocolDataUnit;
2840 }
2841 return null;
2842};
2843
2844/*
2845 * If Content is a string, then encode as utf8 and write UDATA.
2846 */
2847BinaryXMLEncoder.prototype.writeElement = function(
2848 //long
2849 tag,
2850 //byte[]
2851 Content,
2852 //TreeMap<String, String>
2853 attributes
2854 ) {
2855 this.writeStartElement(tag, attributes);
2856 // Will omit if 0-length
2857
2858 if(typeof Content === 'number') {
2859 if(LOG>4) console.log('GOING TO WRITE THE NUMBER .charCodeAt(0) ' + Content.toString().charCodeAt(0) );
2860 if(LOG>4) console.log('GOING TO WRITE THE NUMBER ' + Content.toString() );
2861 if(LOG>4) console.log('type of number is ' + typeof Content.toString() );
2862
2863 this.writeUString(Content.toString());
2864 //whatever
2865 }
2866 else if(typeof Content === 'string'){
2867 if(LOG>4) console.log('GOING TO WRITE THE STRING ' + Content );
2868 if(LOG>4) console.log('type of STRING is ' + typeof Content );
2869
2870 this.writeUString(Content);
2871 }
2872 else{
2873 if(LOG>4) console.log('GOING TO WRITE A BLOB ' + Content );
2874
2875 this.writeBlob(Content);
2876 }
2877
2878 this.writeEndElement();
2879}
2880
2881
2882
2883var TypeAndVal = function TypeAndVal(_type,_val) {
2884 this.type = _type;
2885 this.val = _val;
2886
2887};
2888
2889
2890BinaryXMLEncoder.prototype.encodeTypeAndVal = function(
2891 //int
2892 type,
2893 //long
2894 val
2895 ) {
2896
2897 if(LOG>4) console.log('Encoding type '+ type+ ' and value '+ val);
2898
2899 if(LOG>4) console.log('OFFSET IS ' + this.offset);
2900
2901 if ((type > XML_UDATA) || (type < 0) || (val < 0)) {
2902 throw new Error("Tag and value must be positive, and tag valid.");
2903 }
2904
2905 // Encode backwards. Calculate how many bytes we need:
2906 var numEncodingBytes = this.numEncodingBytes(val);
Jeff Thompson96978b42012-12-29 21:59:54 -08002907 this.ostream.ensureLength(this.offset + numEncodingBytes);
Wentao Shang0e291c82012-12-02 23:36:29 -08002908
2909 // Bottom 4 bits of val go in last byte with tag.
Jeff Thompson96978b42012-12-29 21:59:54 -08002910 this.ostream.array[this.offset + numEncodingBytes - 1] =
Wentao Shang0e291c82012-12-02 23:36:29 -08002911 //(byte)
2912 (BYTE_MASK &
2913 (((XML_TT_MASK & type) |
2914 ((XML_TT_VAL_MASK & val) << XML_TT_BITS))) |
2915 XML_TT_NO_MORE); // set top bit for last byte
Jeff Thompson96978b42012-12-29 21:59:54 -08002916 val = val >>> XML_TT_VAL_BITS;
Wentao Shang0e291c82012-12-02 23:36:29 -08002917
2918 // Rest of val goes into preceding bytes, 7 bits per byte, top bit
2919 // is "more" flag.
2920 var i = this.offset + numEncodingBytes - 2;
2921 while ((0 != val) && (i >= this.offset)) {
Jeff Thompson96978b42012-12-29 21:59:54 -08002922 this.ostream.array[i] = //(byte)
Wentao Shang0e291c82012-12-02 23:36:29 -08002923 (BYTE_MASK & (val & XML_REG_VAL_MASK)); // leave top bit unset
2924 val = val >>> XML_REG_VAL_BITS;
2925 --i;
2926 }
2927 if (val != 0) {
2928 throw new Error( "This should not happen: miscalculated encoding");
2929 //Log.warning(Log.FAC_ENCODING, "This should not happen: miscalculated encoding length, have " + val + " left.");
2930 }
2931 this.offset+= numEncodingBytes;
2932
2933 return numEncodingBytes;
2934};
2935
2936/*
2937 * Encode ustring as utf8.
2938 */
2939BinaryXMLEncoder.prototype.encodeUString = function(
2940 //String
2941 ustring,
2942 //byte
2943 type) {
2944
2945 if (null == ustring)
2946 return;
2947 if (type == XML_TAG || type == XML_ATTR && ustring.length == 0)
2948 return;
2949
2950 if(LOG>3) console.log("The string to write is ");
2951 if(LOG>3) console.log(ustring);
2952
2953 var strBytes = DataUtils.stringToUtf8Array(ustring);
2954
2955 this.encodeTypeAndVal(type,
2956 (((type == XML_TAG) || (type == XML_ATTR)) ?
2957 (strBytes.length-1) :
2958 strBytes.length));
2959
2960 if(LOG>3) console.log("THE string to write is ");
2961
2962 if(LOG>3) console.log(strBytes);
2963
Jeff Thompson96978b42012-12-29 21:59:54 -08002964 this.writeString(strBytes);
Wentao Shang0e291c82012-12-02 23:36:29 -08002965 this.offset+= strBytes.length;
2966};
2967
2968
2969
2970BinaryXMLEncoder.prototype.encodeBlob = function(
2971 //Uint8Array
2972 blob,
2973 //int
2974 length) {
2975
2976
2977 if (null == blob)
2978 return;
2979
2980 if(LOG>4) console.log('LENGTH OF XML_BLOB IS '+length);
2981
2982 /*blobCopy = new Array(blob.Length);
2983
2984 for (i = 0; i < blob.length; i++) //in InStr.ToCharArray())
2985 {
2986 blobCopy[i] = blob[i];
2987 }*/
2988
2989 this.encodeTypeAndVal(XML_BLOB, length);
2990
Jeff Thompson96978b42012-12-29 21:59:54 -08002991 this.writeBlobArray(blob);
Wentao Shang0e291c82012-12-02 23:36:29 -08002992 this.offset += length;
2993};
2994
2995var ENCODING_LIMIT_1_BYTE = ((1 << (XML_TT_VAL_BITS)) - 1);
2996var ENCODING_LIMIT_2_BYTES = ((1 << (XML_TT_VAL_BITS + XML_REG_VAL_BITS)) - 1);
2997var ENCODING_LIMIT_3_BYTES = ((1 << (XML_TT_VAL_BITS + 2 * XML_REG_VAL_BITS)) - 1);
2998
2999BinaryXMLEncoder.prototype.numEncodingBytes = function(
3000 //long
3001 x) {
3002 if (x <= ENCODING_LIMIT_1_BYTE) return (1);
3003 if (x <= ENCODING_LIMIT_2_BYTES) return (2);
3004 if (x <= ENCODING_LIMIT_3_BYTES) return (3);
3005
3006 var numbytes = 1;
3007
3008 // Last byte gives you XML_TT_VAL_BITS
3009 // Remainder each give you XML_REG_VAL_BITS
3010 x = x >>> XML_TT_VAL_BITS;
3011 while (x != 0) {
3012 numbytes++;
3013 x = x >>> XML_REG_VAL_BITS;
3014 }
3015 return (numbytes);
3016};
3017
3018BinaryXMLEncoder.prototype.writeDateTime = function(
3019 //String
3020 tag,
3021 //CCNTime
3022 dateTime) {
3023
3024 if(LOG>4)console.log('ENCODING DATE with LONG VALUE');
3025 if(LOG>4)console.log(dateTime.msec);
3026
3027 //var binarydate = DataUtils.unsignedLongToByteArray( Math.round((dateTime.msec/1000) * 4096) );
3028
3029
3030 //parse to hex
3031 var binarydate = Math.round((dateTime.msec/1000) * 4096).toString(16) ;
3032
3033 //HACK
3034 var binarydate = DataUtils.toNumbers( '0'.concat(binarydate,'0')) ;
3035
3036
3037 if(LOG>4)console.log('ENCODING DATE with BINARY VALUE');
3038 if(LOG>4)console.log(binarydate);
3039 if(LOG>4)console.log('ENCODING DATE with BINARY VALUE(HEX)');
3040 if(LOG>4)console.log(DataUtils.toHex(binarydate));
3041
3042 this.writeElement(tag, binarydate);
3043};
3044
Jeff Thompson96978b42012-12-29 21:59:54 -08003045// This does not update this.offset.
3046BinaryXMLEncoder.prototype.writeString = function(input) {
Wentao Shang0e291c82012-12-02 23:36:29 -08003047
3048 if(typeof input === 'string'){
3049 //console.log('went here');
3050 if(LOG>4) console.log('GOING TO WRITE A STRING');
3051 if(LOG>4) console.log(input);
3052
Jeff Thompson96978b42012-12-29 21:59:54 -08003053 this.ostream.ensureLength(this.offset + input.length);
3054 for (var i = 0; i < input.length; i++) {
Wentao Shang0e291c82012-12-02 23:36:29 -08003055 if(LOG>4) console.log('input.charCodeAt(i)=' + input.charCodeAt(i));
Jeff Thompson96978b42012-12-29 21:59:54 -08003056 this.ostream.array[this.offset + i] = (input.charCodeAt(i));
Wentao Shang0e291c82012-12-02 23:36:29 -08003057 }
3058 }
3059 else{
3060 if(LOG>4) console.log('GOING TO WRITE A STRING IN BINARY FORM');
3061 if(LOG>4) console.log(input);
3062
3063 this.writeBlobArray(input);
3064 }
3065 /*
3066 else if(typeof input === 'object'){
3067
3068 }
3069 */
3070};
3071
3072
3073BinaryXMLEncoder.prototype.writeBlobArray = function(
3074 //Uint8Array
Jeff Thompson96978b42012-12-29 21:59:54 -08003075 blob) {
Wentao Shang0e291c82012-12-02 23:36:29 -08003076
3077 if(LOG>4) console.log('GOING TO WRITE A BLOB');
3078
Wentao Shang0e291c82012-12-02 23:36:29 -08003079 this.ostream.set(blob, this.offset);
3080};
3081
3082
3083BinaryXMLEncoder.prototype.getReducedOstream = function() {
3084 return this.ostream.subarray(0, this.offset);
3085};
3086
Wentao Shangbd63e462012-12-03 16:19:33 -08003087/**
Wentao Shang0e291c82012-12-02 23:36:29 -08003088 * This class is used to decode ccnb binary elements (blob, type/value pairs).
3089 *
3090 * @author: Meki Cheraoui
3091 * See COPYING for copyright and distribution information.
3092 */
3093
3094var XML_EXT = 0x00;
3095
3096var XML_TAG = 0x01;
3097
3098var XML_DTAG = 0x02;
3099
3100var XML_ATTR = 0x03;
3101
3102var XML_DATTR = 0x04;
3103
3104var XML_BLOB = 0x05;
3105
3106var XML_UDATA = 0x06;
3107
3108var XML_CLOSE = 0x0;
3109
3110var XML_SUBTYPE_PROCESSING_INSTRUCTIONS = 16;
3111
3112
3113var XML_TT_BITS = 3;
3114var XML_TT_MASK = ((1 << XML_TT_BITS) - 1);
3115var XML_TT_VAL_BITS = XML_TT_BITS + 1;
3116var XML_TT_VAL_MASK = ((1 << (XML_TT_VAL_BITS)) - 1);
3117var XML_REG_VAL_BITS = 7;
3118var XML_REG_VAL_MASK = ((1 << XML_REG_VAL_BITS) - 1);
3119var XML_TT_NO_MORE = (1 << XML_REG_VAL_BITS); // 0x80
3120var BYTE_MASK = 0xFF;
3121var LONG_BYTES = 8;
3122var LONG_BITS = 64;
3123
3124var bits_11 = 0x0000007FF;
3125var bits_18 = 0x00003FFFF;
3126var bits_32 = 0x0FFFFFFFF;
3127
3128
3129
3130//returns a string
3131tagToString = function(/*long*/ tagVal) {
3132 if ((tagVal >= 0) && (tagVal < CCNProtocolDTagsStrings.length)) {
3133 return CCNProtocolDTagsStrings[tagVal];
3134 } else if (tagVal == CCNProtocolDTags.CCNProtocolDataUnit) {
3135 return CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT;
3136 }
3137 return null;
3138};
3139
3140//returns a Long
3141stringToTag = function(/*String*/ tagName) {
3142 // the slow way, but right now we don't care.... want a static lookup for the forward direction
3143 for (var i=0; i < CCNProtocolDTagsStrings.length; ++i) {
3144 if ((null != CCNProtocolDTagsStrings[i]) && (CCNProtocolDTagsStrings[i] == tagName)) {
3145 return i;
3146 }
3147 }
3148 if (CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT == tagName) {
3149 return CCNProtocolDTags.CCNProtocolDataUnit;
3150 }
3151 return null;
3152};
3153
3154//console.log(stringToTag(64));
3155var BinaryXMLDecoder = function BinaryXMLDecoder(istream){
3156 var MARK_LEN=512;
3157 var DEBUG_MAX_LEN = 32768;
3158
3159 this.istream = istream;
3160 this.offset = 0;
3161};
3162
3163BinaryXMLDecoder.prototype.readAttributes = function(
3164 //TreeMap<String,String>
3165 attributes){
3166
3167 if (null == attributes) {
3168 return;
3169 }
3170
3171 try {
3172
3173 //this.TypeAndVal
3174 var nextTV = this.peekTypeAndVal();
3175
3176 while ((null != nextTV) && ((XML_ATTR == nextTV.type()) ||
3177 (XML_DATTR == nextTV.type()))) {
3178
3179 //this.TypeAndVal
3180 var thisTV = this.decodeTypeAndVal();
3181
3182 var attributeName = null;
3183 if (XML_ATTR == thisTV.type()) {
3184
3185 attributeName = this.decodeUString(thisTV.val()+1);
3186
3187 } else if (XML_DATTR == thisTV.type()) {
3188 // DKS TODO are attributes same or different dictionary?
3189 attributeName = tagToString(thisTV.val());
3190 if (null == attributeName) {
3191 throw new ContentDecodingException(new Error("Unknown DATTR value" + thisTV.val()));
3192 }
3193 }
3194
3195 var attributeValue = this.decodeUString();
3196
3197 attributes.put(attributeName, attributeValue);
3198
3199 nextTV = this.peekTypeAndVal();
3200 }
3201
3202 } catch ( e) {
3203
3204 throw new ContentDecodingException(new Error("readStartElement", e));
3205 }
3206};
3207
3208
3209BinaryXMLDecoder.prototype.initializeDecoding = function() {
3210 //if (!this.istream.markSupported()) {
3211 //throw new IllegalArgumentException(this.getClass().getName() + ": input stream must support marking!");
3212 //}
3213}
3214
3215BinaryXMLDecoder.prototype.readStartDocument = function(){
3216 // Currently no start document in binary encoding.
3217 }
3218
3219BinaryXMLDecoder.prototype.readEndDocument = function() {
3220 // Currently no end document in binary encoding.
3221 };
3222
3223BinaryXMLDecoder.prototype.readStartElement = function(
3224 //String
3225 startTag,
3226 //TreeMap<String, String>
3227 attributes) {
3228
3229
3230 //NOT SURE
3231 //if(typeof startTag == 'number')
3232 //startTag = tagToString(startTag);
3233
3234 //TypeAndVal
3235 tv = this.decodeTypeAndVal();
3236
3237 if (null == tv) {
3238 throw new ContentDecodingException(new Error("Expected start element: " + startTag + " got something not a tag."));
3239 }
3240
3241 //String
3242 var decodedTag = null;
3243 //console.log(tv);
3244 //console.log(typeof tv);
3245
3246 //console.log(XML_TAG);
3247 if (tv.type() == XML_TAG) {
3248 //console.log('got here');
3249 //Log.info(Log.FAC_ENCODING, "Unexpected: got tag in readStartElement; looking for tag " + startTag + " got length: " + (int)tv.val()+1);
3250 // Tag value represents length-1 as tags can never be empty.
3251 var valval ;
3252 if(typeof tv.val() == 'string'){
3253 valval = (parseInt(tv.val())) + 1;
3254 }
3255 else
3256 valval = (tv.val())+ 1;
3257
3258 //console.log('valval is ' +valval);
3259
3260 decodedTag = this.decodeUString(valval);
3261
3262 } else if (tv.type() == XML_DTAG) {
3263 //console.log('gothere');
3264 //console.log(tv.val());
3265 //decodedTag = tagToString(tv.val());
3266 //console.log()
3267 decodedTag = tv.val();
3268 }
3269
3270 //console.log(decodedTag);
3271 //console.log('startTag is '+startTag);
3272
3273
3274 if ((null == decodedTag) || decodedTag != startTag ) {
3275 console.log('expecting '+ startTag + ' but got '+ decodedTag);
3276 throw new ContentDecodingException(new Error("Expected start element: " + startTag + " got: " + decodedTag + "(" + tv.val() + ")"));
3277 }
3278
3279 // DKS: does not read attributes out of stream if caller doesn't
3280 // ask for them. Should possibly peek and skip over them regardless.
3281 // TODO: fix this
3282 if (null != attributes) {
3283 readAttributes(attributes);
3284 }
3285 }
3286
3287
3288BinaryXMLDecoder.prototype.readAttributes = function(
3289 //TreeMap<String,String>
3290 attributes) {
3291
3292 if (null == attributes) {
3293 return;
3294 }
3295
3296 try {
3297 // Now need to get attributes.
3298 //TypeAndVal
3299 var nextTV = this.peekTypeAndVal();
3300
3301 while ((null != nextTV) && ((XML_ATTR == nextTV.type()) ||
3302 (XML_DATTR == nextTV.type()))) {
3303
3304 // Decode this attribute. First, really read the type and value.
3305 //this.TypeAndVal
3306 var thisTV = this.decodeTypeAndVal();
3307
3308 //String
3309 var attributeName = null;
3310 if (XML_ATTR == thisTV.type()) {
3311 // Tag value represents length-1 as attribute names cannot be empty.
3312 var valval ;
3313 if(typeof tv.val() == 'string'){
3314 valval = (parseInt(tv.val())) + 1;
3315 }
3316 else
3317 valval = (tv.val())+ 1;
3318
3319 attributeName = this.decodeUString(valval);
3320
3321 } else if (XML_DATTR == thisTV.type()) {
3322 // DKS TODO are attributes same or different dictionary?
3323 attributeName = tagToString(thisTV.val());
3324 if (null == attributeName) {
3325 throw new ContentDecodingException(new Error("Unknown DATTR value" + thisTV.val()));
3326 }
3327 }
3328 // Attribute values are always UDATA
3329 //String
3330 var attributeValue = this.decodeUString();
3331
3332 //
3333 attributes.push([attributeName, attributeValue]);
3334
3335 nextTV = this.peekTypeAndVal();
3336 }
3337 } catch ( e) {
3338 throw new ContentDecodingException(new Error("readStartElement", e));
3339 }
3340};
3341
3342//returns a string
3343BinaryXMLDecoder.prototype.peekStartElementAsString = function() {
3344 //this.istream.mark(MARK_LEN);
3345
3346 //String
3347 var decodedTag = null;
3348 var previousOffset = this.offset;
3349 try {
3350 // Have to distinguish genuine errors from wrong tags. Could either use
3351 // a special exception subtype, or redo the work here.
3352 //this.TypeAndVal
3353 var tv = this.decodeTypeAndVal();
3354
3355 if (null != tv) {
3356
3357 if (tv.type() == XML_TAG) {
3358 /*if (tv.val()+1 > DEBUG_MAX_LEN) {
3359 throw new ContentDecodingException(new Error("Decoding error: length " + tv.val()+1 + " longer than expected maximum length!")(;
3360 }*/
3361
3362 // Tag value represents length-1 as tags can never be empty.
3363 var valval ;
3364 if(typeof tv.val() == 'string'){
3365 valval = (parseInt(tv.val())) + 1;
3366 }
3367 else
3368 valval = (tv.val())+ 1;
3369
3370 decodedTag = this.decodeUString(valval);
3371
3372 //Log.info(Log.FAC_ENCODING, "Unexpected: got text tag in peekStartElement; length: " + valval + " decoded tag = " + decodedTag);
3373
3374 } else if (tv.type() == XML_DTAG) {
3375 decodedTag = tagToString(tv.val());
3376 }
3377
3378 } // else, not a type and val, probably an end element. rewind and return false.
3379
3380 } catch ( e) {
3381
3382 } finally {
3383 try {
3384 this.offset = previousOffset;
3385 } catch ( e) {
3386 Log.logStackTrace(Log.FAC_ENCODING, Level.WARNING, e);
3387 throw new ContentDecodingException(new Error("Cannot reset stream! " + e.getMessage(), e));
3388 }
3389 }
3390 return decodedTag;
3391};
3392
3393BinaryXMLDecoder.prototype.peekStartElement = function(
3394 //String
3395 startTag) {
3396 //String
3397 if(typeof startTag == 'string'){
3398 var decodedTag = this.peekStartElementAsString();
3399
3400 if ((null != decodedTag) && decodedTag == startTag) {
3401 return true;
3402 }
3403 return false;
3404 }
3405 else if(typeof startTag == 'number'){
3406 var decodedTag = this.peekStartElementAsLong();
3407 if ((null != decodedTag) && decodedTag == startTag) {
3408 return true;
3409 }
3410 return false;
3411 }
3412 else{
3413 throw new ContentDecodingException(new Error("SHOULD BE STRING OR NUMBER"));
3414 }
3415}
3416//returns Long
3417BinaryXMLDecoder.prototype.peekStartElementAsLong = function() {
3418 //this.istream.mark(MARK_LEN);
3419
3420 //Long
3421 var decodedTag = null;
3422
3423 var previousOffset = this.offset;
3424
3425 try {
3426 // Have to distinguish genuine errors from wrong tags. Could either use
3427 // a special exception subtype, or redo the work here.
3428 //this.TypeAndVal
3429 var tv = this.decodeTypeAndVal();
3430
3431 if (null != tv) {
3432
3433 if (tv.type() == XML_TAG) {
3434 if (tv.val()+1 > DEBUG_MAX_LEN) {
3435 throw new ContentDecodingException(new Error("Decoding error: length " + tv.val()+1 + " longer than expected maximum length!"));
3436 }
3437
3438 var valval ;
3439 if(typeof tv.val() == 'string'){
3440 valval = (parseInt(tv.val())) + 1;
3441 }
3442 else
3443 valval = (tv.val())+ 1;
3444
3445 // Tag value represents length-1 as tags can never be empty.
3446 //String
3447 var strTag = this.decodeUString(valval);
3448
3449 decodedTag = stringToTag(strTag);
3450
3451 //Log.info(Log.FAC_ENCODING, "Unexpected: got text tag in peekStartElement; length: " + valval + " decoded tag = " + decodedTag);
3452
3453 } else if (tv.type() == XML_DTAG) {
3454 decodedTag = tv.val();
3455 }
3456
3457 } // else, not a type and val, probably an end element. rewind and return false.
3458
3459 } catch ( e) {
3460
3461 } finally {
3462 try {
3463 //this.istream.reset();
3464 this.offset = previousOffset;
3465 } catch ( e) {
3466 Log.logStackTrace(Log.FAC_ENCODING, Level.WARNING, e);
3467 throw new Error("Cannot reset stream! " + e.getMessage(), e);
3468 }
3469 }
3470 return decodedTag;
3471 };
3472
3473
3474// returns a byte[]
3475BinaryXMLDecoder.prototype.readBinaryElement = function(
3476 //long
3477 startTag,
3478 //TreeMap<String, String>
3479 attributes){
3480 //byte []
3481 var blob = null;
3482
3483 this.readStartElement(startTag, attributes);
3484 blob = this.readBlob();
3485
3486 return blob;
3487};
3488
3489
3490BinaryXMLDecoder.prototype.readEndElement = function(){
3491 if(LOG>4)console.log('this.offset is '+this.offset);
3492
3493 var next = this.istream[this.offset];
3494
3495 this.offset++;
3496 //read();
3497
3498 if(LOG>4)console.log('XML_CLOSE IS '+XML_CLOSE);
3499 if(LOG>4)console.log('next is '+next);
3500
3501 if (next != XML_CLOSE) {
3502 console.log("Expected end element, got: " + next);
3503 throw new ContentDecodingException(new Error("Expected end element, got: " + next));
3504 }
3505 };
3506
3507
3508//String
3509BinaryXMLDecoder.prototype.readUString = function(){
3510 //String
3511 var ustring = this.decodeUString();
3512 this.readEndElement();
3513 return ustring;
3514
3515 };
3516
3517
3518//returns a byte[]
3519BinaryXMLDecoder.prototype.readBlob = function() {
3520 //byte []
3521
3522 var blob = this.decodeBlob();
3523 this.readEndElement();
3524 return blob;
3525
3526 };
3527
3528
3529//CCNTime
3530BinaryXMLDecoder.prototype.readDateTime = function(
3531 //long
3532 startTag) {
3533 //byte []
3534
3535 var byteTimestamp = this.readBinaryElement(startTag);
3536
3537 //var lontimestamp = DataUtils.byteArrayToUnsignedLong(byteTimestamp);
3538
3539 byteTimestamp = DataUtils.toHex(byteTimestamp);
3540
3541
3542 byteTimestamp = parseInt(byteTimestamp, 16);
3543
3544 var lontimestamp = (byteTimestamp/ 4096) * 1000;
3545
3546 //if(lontimestamp<0) lontimestamp = - lontimestamp;
3547
3548 if(LOG>3) console.log('DECODED DATE WITH VALUE');
3549 if(LOG>3) console.log(lontimestamp);
3550
3551
3552 //CCNTime
3553 var timestamp = new CCNTime(lontimestamp);
3554 //timestamp.setDateBinary(byteTimestamp);
3555
3556 if (null == timestamp) {
3557 throw new ContentDecodingException(new Error("Cannot parse timestamp: " + DataUtils.printHexBytes(byteTimestamp)));
3558 }
3559 return timestamp;
3560};
3561
3562BinaryXMLDecoder.prototype.decodeTypeAndVal = function() {
3563
3564 /*int*/var type = -1;
3565 /*long*/var val = 0;
3566 /*boolean*/var more = true;
3567
3568 do {
3569
3570 var next = this.istream[this.offset ];
3571
3572
3573 if (next < 0) {
3574 return null;
3575 }
3576
3577 if ((0 == next) && (0 == val)) {
3578 return null;
3579 }
3580
3581 more = (0 == (next & XML_TT_NO_MORE));
3582
3583 if (more) {
3584 val = val << XML_REG_VAL_BITS;
3585 val |= (next & XML_REG_VAL_MASK);
3586 } else {
3587
3588 type = next & XML_TT_MASK;
3589 val = val << XML_TT_VAL_BITS;
3590 val |= ((next >>> XML_TT_BITS) & XML_TT_VAL_MASK);
3591 }
3592
3593 this.offset++;
3594
3595 } while (more);
3596
3597 if(LOG>3)console.log('TYPE is '+ type + ' VAL is '+ val);
3598
3599 return new TypeAndVal(type, val);
3600};
3601
3602
3603
3604//TypeAndVal
3605BinaryXMLDecoder.peekTypeAndVal = function() {
3606 //TypeAndVal
3607 var tv = null;
3608
3609 //this.istream.mark(LONG_BYTES*2);
3610
3611 var previousOffset = this.offset;
3612
3613 try {
3614 tv = this.decodeTypeAndVal();
3615 } finally {
3616 //this.istream.reset();
3617 this.offset = previousOffset;
3618 }
3619
3620 return tv;
3621};
3622
3623
3624//Uint8Array
3625BinaryXMLDecoder.prototype.decodeBlob = function(
3626 //int
3627 blobLength) {
3628
3629 if(null == blobLength){
3630 //TypeAndVal
3631 var tv = this.decodeTypeAndVal();
3632
3633 var valval ;
3634
3635 if(typeof tv.val() == 'string'){
3636 valval = (parseInt(tv.val()));
3637 }
3638 else
3639 valval = (tv.val());
3640
3641 //console.log('valval here is ' + valval);
3642 return this.decodeBlob(valval);
3643 }
3644
3645 //
3646 //Uint8Array
3647 var bytes = this.istream.subarray(this.offset, this.offset+ blobLength);
3648 this.offset += blobLength;
3649
3650 return bytes;
3651};
3652
3653var count =0;
3654
3655//String
3656BinaryXMLDecoder.prototype.decodeUString = function(
3657 //int
3658 byteLength) {
3659
3660 /*
3661 console.log('COUNT IS '+count);
3662 console.log('INPUT BYTELENGTH IS '+byteLength);
3663 count++;
3664 if(null == byteLength|| undefined == byteLength){
3665 console.log("!!!!");
3666 tv = this.decodeTypeAndVal();
3667 var valval ;
3668 if(typeof tv.val() == 'string'){
3669 valval = (parseInt(tv.val()));
3670 }
3671 else
3672 valval = (tv.val());
3673
3674 if(LOG>4) console.log('valval is ' + valval);
3675 byteLength= this.decodeUString(valval);
3676
3677 //if(LOG>4) console.log('byte Length found in type val is '+ byteLength.charCodeAt(0));
3678 byteLength = parseInt(byteLength);
3679
3680
3681 //byteLength = byteLength.charCodeAt(0);
3682 //if(LOG>4) console.log('byte Length found in type val is '+ byteLength);
3683 }
3684 if(LOG>4)console.log('byteLength is '+byteLength);
3685 if(LOG>4)console.log('type of byteLength is '+typeof byteLength);
3686
3687 stringBytes = this.decodeBlob(byteLength);
3688
3689 //console.log('String bytes are '+ stringBytes);
3690 //console.log('stringBytes);
3691
3692 if(LOG>4)console.log('byteLength is '+byteLength);
3693 if(LOG>4)console.log('this.offset is '+this.offset);
3694
3695 tempBuffer = this.istream.slice(this.offset, this.offset+byteLength);
3696 if(LOG>4)console.log('TEMPBUFFER IS' + tempBuffer);
3697 if(LOG>4)console.log( tempBuffer);
3698
3699 if(LOG>4)console.log('ADDING to offset value' + byteLength);
3700 this.offset+= byteLength;
3701 //if(LOG>3)console.log('read the String' + tempBuffer.toString('ascii'));
3702 //return tempBuffer.toString('ascii');//
3703
3704
3705 //if(LOG>3)console.log( 'STRING READ IS '+ DataUtils.getUTF8StringFromBytes(stringBytes) ) ;
3706 //if(LOG>3)console.log( 'STRING READ IS '+ DataUtils.getUTF8StringFromBytes(tempBuffer) ) ;
3707 //if(LOG>3)console.log(DataUtils.getUTF8StringFromBytes(tempBuffer) ) ;
3708 //return DataUtils.getUTF8StringFromBytes(tempBuffer);
3709
3710 if(LOG>3)console.log( 'STRING READ IS '+ DataUtils.toString(stringBytes) ) ;
3711 if(LOG>3)console.log( 'TYPE OF STRING READ IS '+ typeof DataUtils.toString(stringBytes) ) ;
3712
3713 return DataUtils.toString(stringBytes);*/
3714
3715 if(null == byteLength ){
3716 var tempStreamPosition = this.offset;
3717
3718 //TypeAndVal
3719 var tv = this.decodeTypeAndVal();
3720
3721 if(LOG>3)console.log('TV is '+tv);
3722 if(LOG>3)console.log(tv);
3723
3724 if(LOG>3)console.log('Type of TV is '+typeof tv);
3725
3726 if ((null == tv) || (XML_UDATA != tv.type())) { // if we just have closers left, will get back null
3727 //if (Log.isLoggable(Log.FAC_ENCODING, Level.FINEST))
3728 //Log.finest(Log.FAC_ENCODING, "Expected UDATA, got " + ((null == tv) ? " not a tag " : tv.type()) + ", assuming elided 0-length blob.");
3729
3730 this.offset = tempStreamPosition;
3731
3732 return "";
3733 }
3734
3735 return this.decodeUString(tv.val());
3736 }
3737 else{
3738 //byte []
3739 var stringBytes = this.decodeBlob(byteLength);
3740
3741 //return DataUtils.getUTF8StringFromBytes(stringBytes);
3742 return DataUtils.toString(stringBytes);
3743
3744 }
3745};
3746
3747
3748
3749
3750//OBject containg a pair of type and value
3751var TypeAndVal = function TypeAndVal(_type,_val) {
3752 this.t = _type;
3753 this.v = _val;
3754};
3755
3756TypeAndVal.prototype.type = function(){
3757 return this.t;
3758};
3759
3760TypeAndVal.prototype.val = function(){
3761 return this.v;
3762};
3763
3764
3765
3766
3767BinaryXMLDecoder.prototype.readIntegerElement =function(
3768 //String
3769 startTag) {
3770
3771 //String
3772 if(LOG>4) console.log('READING INTEGER '+ startTag);
3773 if(LOG>4) console.log('TYPE OF '+ typeof startTag);
3774
3775 var strVal = this.readUTF8Element(startTag);
3776
3777 return parseInt(strVal);
3778};
3779
3780
3781BinaryXMLDecoder.prototype.readUTF8Element =function(
3782 //String
3783 startTag,
3784 //TreeMap<String, String>
3785 attributes) {
3786 //throws Error where name == "ContentDecodingException"
3787
3788 this.readStartElement(startTag, attributes); // can't use getElementText, can't get attributes
3789 //String
3790 var strElementText = this.readUString();
3791 return strElementText;
3792};
3793
3794
3795/*
3796 * Set the offset into the input, used for the next read.
3797 */
3798BinaryXMLDecoder.prototype.seek = function(
3799 //int
3800 offset) {
3801 this.offset = offset;
3802}
3803
3804/*
3805 * Call with: throw new ContentDecodingException(new Error("message")).
3806 */
3807function ContentDecodingException(error) {
3808 this.message = error.message;
3809 // Copy lineNumber, etc. from where new Error was called.
3810 for (var prop in error)
3811 this[prop] = error[prop];
3812}
3813ContentDecodingException.prototype = new Error();
3814ContentDecodingException.prototype.name = "ContentDecodingException";
3815
Wentao Shangbd63e462012-12-03 16:19:33 -08003816/**
Wentao Shang0e291c82012-12-02 23:36:29 -08003817 * This class uses BinaryXMLDecoder to follow the structure of a ccnb binary element to
3818 * determine its end.
3819 *
3820 * @author: Jeff Thompson
3821 * See COPYING for copyright and distribution information.
3822 */
3823
3824var BinaryXMLStructureDecoder = function BinaryXMLDecoder() {
3825 this.gotElementEnd = false;
3826 this.offset = 0;
3827 this.level = 0;
3828 this.state = BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE;
3829 this.headerLength = 0;
3830 this.useHeaderBuffer = false;
Jeff Thompson96978b42012-12-29 21:59:54 -08003831 this.headerBuffer = new DynamicUint8Array(5);
Wentao Shang0e291c82012-12-02 23:36:29 -08003832 this.nBytesToRead = 0;
3833};
3834
3835BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE = 0;
3836BinaryXMLStructureDecoder.READ_BYTES = 1;
3837
3838/*
3839 * Continue scanning input starting from this.offset. If found the end of the element
3840 * which started at offset 0 then return true, else false.
3841 * If this returns false, you should read more into input and call again.
3842 * You have to pass in input each time because the array could be reallocated.
3843 * This throws an exception for badly formed ccnb.
3844 */
3845BinaryXMLStructureDecoder.prototype.findElementEnd = function(
3846 // Uint8Array
3847 input)
3848{
3849 if (this.gotElementEnd)
3850 // Someone is calling when we already got the end.
3851 return true;
3852
3853 var decoder = new BinaryXMLDecoder(input);
3854
3855 while (true) {
3856 if (this.offset >= input.length)
3857 // All the cases assume we have some input.
3858 return false;
Wentao Shang2b740e62012-12-07 00:02:53 -08003859
Wentao Shang0e291c82012-12-02 23:36:29 -08003860 switch (this.state) {
3861 case BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE:
3862 // First check for XML_CLOSE.
3863 if (this.headerLength == 0 && input[this.offset] == XML_CLOSE) {
3864 ++this.offset;
3865 // Close the level.
3866 --this.level;
3867 if (this.level == 0)
3868 // Finished.
3869 return true;
3870 if (this.level < 0)
3871 throw new Error("BinaryXMLStructureDecoder: Unexepected close tag at offset " +
3872 (this.offset - 1));
3873
3874 // Get ready for the next header.
3875 this.startHeader();
3876 break;
3877 }
3878
3879 var startingHeaderLength = this.headerLength;
3880 while (true) {
3881 if (this.offset >= input.length) {
3882 // We can't get all of the header bytes from this input. Save in headerBuffer.
3883 this.useHeaderBuffer = true;
3884 var nNewBytes = this.headerLength - startingHeaderLength;
Jeff Thompson96978b42012-12-29 21:59:54 -08003885 this.headerBuffer.set
Wentao Shang0e291c82012-12-02 23:36:29 -08003886 (input.subarray(this.offset - nNewBytes, nNewBytes), startingHeaderLength);
3887
3888 return false;
3889 }
3890 var headerByte = input[this.offset++];
3891 ++this.headerLength;
3892 if (headerByte & XML_TT_NO_MORE)
3893 // Break and read the header.
3894 break;
3895 }
3896
3897 var typeAndVal;
3898 if (this.useHeaderBuffer) {
3899 // Copy the remaining bytes into headerBuffer.
3900 nNewBytes = this.headerLength - startingHeaderLength;
Jeff Thompson96978b42012-12-29 21:59:54 -08003901 this.headerBuffer.set
Wentao Shang0e291c82012-12-02 23:36:29 -08003902 (input.subarray(this.offset - nNewBytes, nNewBytes), startingHeaderLength);
3903
Jeff Thompson96978b42012-12-29 21:59:54 -08003904 typeAndVal = new BinaryXMLDecoder(this.headerBuffer.array).decodeTypeAndVal();
Wentao Shang0e291c82012-12-02 23:36:29 -08003905 }
3906 else {
3907 // We didn't have to use the headerBuffer.
3908 decoder.seek(this.offset - this.headerLength);
3909 typeAndVal = decoder.decodeTypeAndVal();
3910 }
3911
3912 if (typeAndVal == null)
3913 throw new Error("BinaryXMLStructureDecoder: Can't read header starting at offset " +
3914 (this.offset - this.headerLength));
3915
3916 // Set the next state based on the type.
3917 var type = typeAndVal.t;
3918 if (type == XML_DATTR)
3919 // We already consumed the item. READ_HEADER_OR_CLOSE again.
3920 // ccnb has rules about what must follow an attribute, but we are just scanning.
3921 this.startHeader();
3922 else if (type == XML_DTAG || type == XML_EXT) {
3923 // Start a new level and READ_HEADER_OR_CLOSE again.
3924 ++this.level;
3925 this.startHeader();
3926 }
3927 else if (type == XML_TAG || type == XML_ATTR) {
3928 if (type == XML_TAG)
3929 // Start a new level and read the tag.
3930 ++this.level;
3931 // Minimum tag or attribute length is 1.
3932 this.nBytesToRead = typeAndVal.v + 1;
3933 this.state = BinaryXMLStructureDecoder.READ_BYTES;
3934 // ccnb has rules about what must follow an attribute, but we are just scanning.
3935 }
3936 else if (type == XML_BLOB || type == XML_UDATA) {
3937 this.nBytesToRead = typeAndVal.v;
3938 this.state = BinaryXMLStructureDecoder.READ_BYTES;
3939 }
3940 else
3941 throw new Error("BinaryXMLStructureDecoder: Unrecognized header type " + type);
3942 break;
3943
3944 case BinaryXMLStructureDecoder.READ_BYTES:
3945 var nRemainingBytes = input.length - this.offset;
3946 if (nRemainingBytes < this.nBytesToRead) {
3947 // Need more.
3948 this.offset += nRemainingBytes;
3949 this.nBytesToRead -= nRemainingBytes;
3950 return false;
3951 }
3952 // Got the bytes. Read a new header or close.
3953 this.offset += this.nBytesToRead;
3954 this.startHeader();
3955 break;
3956
3957 default:
3958 // We don't expect this to happen.
3959 throw new Error("BinaryXMLStructureDecoder: Unrecognized state " + this.state);
3960 }
3961 }
3962};
3963
3964/*
3965 * Set the state to READ_HEADER_OR_CLOSE and set up to start reading the header
3966 */
3967BinaryXMLStructureDecoder.prototype.startHeader = function() {
3968 this.headerLength = 0;
3969 this.useHeaderBuffer = false;
3970 this.state = BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE;
3971}
3972
3973/*
3974 * Set the offset into the input, used for the next read.
3975 */
3976BinaryXMLStructureDecoder.prototype.seek = function(
3977 //int
3978 offset) {
3979 this.offset = offset;
3980}
Jeff Thompson96978b42012-12-29 21:59:54 -08003981/**
Wentao Shang0e291c82012-12-02 23:36:29 -08003982 * This class contains utilities to help parse the data
3983 * author: Meki Cheraoui, Jeff Thompson
3984 * See COPYING for copyright and distribution information.
3985 */
3986
3987var DataUtils = function DataUtils(){
3988
3989
3990};
3991
3992
3993/*
3994 * NOTE THIS IS CURRENTLY NOT BEHING USED
3995 *
3996 */
3997
3998DataUtils.keyStr = "ABCDEFGHIJKLMNOP" +
3999 "QRSTUVWXYZabcdef" +
4000 "ghijklmnopqrstuv" +
4001 "wxyz0123456789+/" +
4002 "=";
4003
4004
4005/**
4006 * Raw String to Base 64
4007 */
4008DataUtils.stringtoBase64=function stringtoBase64(input) {
4009 input = escape(input);
4010 var output = "";
4011 var chr1, chr2, chr3 = "";
4012 var enc1, enc2, enc3, enc4 = "";
4013 var i = 0;
4014
4015 do {
4016 chr1 = input.charCodeAt(i++);
4017 chr2 = input.charCodeAt(i++);
4018 chr3 = input.charCodeAt(i++);
4019
4020 enc1 = chr1 >> 2;
4021 enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
4022 enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
4023 enc4 = chr3 & 63;
4024
4025 if (isNaN(chr2)) {
4026 enc3 = enc4 = 64;
4027 } else if (isNaN(chr3)) {
4028 enc4 = 64;
4029 }
4030
4031 output = output +
4032 DataUtils.keyStr.charAt(enc1) +
4033 DataUtils.keyStr.charAt(enc2) +
4034 DataUtils.keyStr.charAt(enc3) +
4035 DataUtils.keyStr.charAt(enc4);
4036 chr1 = chr2 = chr3 = "";
4037 enc1 = enc2 = enc3 = enc4 = "";
4038 } while (i < input.length);
4039
4040 return output;
4041 }
4042
4043/**
4044 * Base 64 to Raw String
4045 */
4046DataUtils.base64toString = function base64toString(input) {
4047 var output = "";
4048 var chr1, chr2, chr3 = "";
4049 var enc1, enc2, enc3, enc4 = "";
4050 var i = 0;
4051
4052 // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
4053 var base64test = /[^A-Za-z0-9\+\/\=]/g;
4054 /* Test for invalid characters. */
4055 if (base64test.exec(input)) {
4056 alert("There were invalid base64 characters in the input text.\n" +
4057 "Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\n" +
4058 "Expect errors in decoding.");
4059 }
4060
4061 input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
4062
4063 do {
4064 enc1 = DataUtils.keyStr.indexOf(input.charAt(i++));
4065 enc2 = DataUtils.keyStr.indexOf(input.charAt(i++));
4066 enc3 = DataUtils.keyStr.indexOf(input.charAt(i++));
4067 enc4 = DataUtils.keyStr.indexOf(input.charAt(i++));
4068
4069 chr1 = (enc1 << 2) | (enc2 >> 4);
4070 chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
4071 chr3 = ((enc3 & 3) << 6) | enc4;
4072
4073 output = output + String.fromCharCode(chr1);
4074
4075 if (enc3 != 64) {
4076 output = output + String.fromCharCode(chr2);
4077 }
4078 if (enc4 != 64) {
4079 output = output + String.fromCharCode(chr3);
4080 }
4081
4082 chr1 = chr2 = chr3 = "";
4083 enc1 = enc2 = enc3 = enc4 = "";
4084
4085 } while (i < input.length);
4086
4087 return unescape(output);
4088 };
4089
4090//byte []
4091
4092/**
4093 * NOT WORKING!!!!!
4094 *
4095 * Unsiged Long Number to Byte Array
4096 */
4097
4098 /*
4099DataUtils.unsignedLongToByteArray= function( value) {
4100
4101 if(LOG>4)console.log('INPUT IS '+value);
4102
4103 if( 0 == value )
4104 return [0];
4105
4106 if( 0 <= value && value <= 0x00FF ) {
4107 //byte []
4108 var bb = new Array(1);
4109 bb[0] = (value & 0x00FF);
4110 return bb;
4111 }
4112
4113 if(LOG>4) console.log('type of value is '+typeof value);
4114 if(LOG>4) console.log('value is '+value);
4115 //byte []
4116 var out = null;
4117 //int
4118 var offset = -1;
4119 for(var i = 7; i >=0; --i) {
4120 //byte
4121 console.log(i);
4122 console.log('value is '+value);
4123 console.log('(value >> (i * 8)) '+ (value >> (i * 8)) );
4124 console.log(' ((value >> (i * 8)) & 0xFF) '+ ((value >> (i * 8)) & 0xFF) );
4125
4126 var b = ((value >> (i * 8)) & 0xFF) ;
4127
4128 if(LOG>4) console.log('b is '+b);
4129
4130 if( out == null && b != 0 ) {
4131 //out = new byte[i+1];
4132 out = new Array(i+1);
4133 offset = i;
4134 }
4135
4136 if( out != null )
4137 out[ offset - i ] = b;
4138 }
4139 if(LOG>4)console.log('OUTPUT IS ');
4140 if(LOG>4)console.log(out);
4141 return out;
4142}
4143*/
4144
4145/**
4146 * NOT WORKING!!!!!
4147 *
4148 * Unsiged Long Number to Byte Array
4149 *//*
4150DataUtils.byteArrayToUnsignedLong = function(//final byte []
4151 src) {
4152 if(LOG>4) console.log('INPUT IS ');
4153 if(LOG>4) console.log(src);
4154
4155 var value = 0;
4156 for(var i = 0; i < src.length; i++) {
4157 value = value << 8;
4158 // Java will assume the byte is signed, so extend it and trim it.
4159
4160
4161 var b = ((src[i]) & 0xFF );
4162 value |= b;
4163 }
4164
4165 if(LOG>4) console.log('OUTPUT IS ');
4166
4167 if(LOG>4) console.log(value);
4168
4169 return value;
4170 }*/
4171
4172
4173/**
4174 * Hex String to Byte Array
4175 */
4176 //THIS IS NOT WORKING
4177/*
4178DataUtils.HexStringtoByteArray = function(str) {
4179 var byteArray = [];
4180 for (var i = 0; i < str.length; i++)
4181 if (str.charCodeAt(i) <= 0x7F)
4182 byteArray.push(str.charCodeAt(i));
4183 else {
4184 var h = encodeURIComponent(str.charAt(i)).substr(1).split('%');
4185 for (var j = 0; j < h.length; j++)
4186 byteArray.push(parseInt(h[j], 16));
4187 }
4188 return byteArray;
4189};
4190*/
4191
4192/**
4193 * Uint8Array to Hex String
4194 */
4195//http://ejohn.org/blog/numbers-hex-and-colors/
4196DataUtils.toHex = function(args){
4197 if (LOG>4) console.log('ABOUT TO CONVERT '+ args);
4198 //console.log(args);
4199 var ret = "";
4200 for ( var i = 0; i < args.length; i++ )
4201 ret += (args[i] < 16 ? "0" : "") + args[i].toString(16);
4202 if (LOG>4) console.log('Converted to: ' + ret);
4203 return ret; //.toUpperCase();
4204}
4205
4206/**
4207 * Raw string to hex string.
4208 */
4209DataUtils.stringToHex = function(args){
4210 var ret = "";
4211 for (var i = 0; i < args.length; ++i) {
4212 var value = args.charCodeAt(i);
4213 ret += (value < 16 ? "0" : "") + value.toString(16);
4214 }
4215 return ret;
4216}
4217
4218/**
4219 * Uint8Array to raw string.
4220 */
4221DataUtils.toString = function(args){
4222 //console.log(arguments);
4223 var ret = "";
4224 for ( var i = 0; i < args.length; i++ )
4225 ret += String.fromCharCode(args[i]);
4226 return ret;
4227}
4228
4229/**
4230 * Hex String to Uint8Array.
4231 */
4232DataUtils.toNumbers = function(str) {
4233 if (typeof str == 'string') {
4234 var ret = new Uint8Array(Math.floor(str.length / 2));
4235 var i = 0;
4236 str.replace(/(..)/g, function(str) {
4237 ret[i++] = parseInt(str, 16);
4238 });
4239 return ret;
4240 }
4241}
4242
4243/**
4244 * Hex String to raw string.
4245 */
4246DataUtils.hexToRawString = function(str) {
4247 if(typeof str =='string') {
4248 var ret = "";
4249 str.replace(/(..)/g, function(s) {
4250 ret += String.fromCharCode(parseInt(s, 16));
4251 });
4252 return ret;
4253 }
4254}
4255
4256/**
4257 * Raw String to Uint8Array.
4258 */
Wentao Shangf8b4a7d2012-12-25 12:52:07 -08004259DataUtils.toNumbersFromString = function(str) {
Wentao Shang0e291c82012-12-02 23:36:29 -08004260 var bytes = new Uint8Array(str.length);
4261 for(var i=0;i<str.length;i++)
4262 bytes[i] = str.charCodeAt(i);
4263 return bytes;
4264}
4265
4266/*
4267 * Encode str as utf8 and return as Uint8Array.
4268 * TODO: Use TextEncoder when available.
4269 */
4270DataUtils.stringToUtf8Array = function(str) {
4271 return DataUtils.toNumbersFromString(str2rstr_utf8(str));
4272}
4273
4274/*
4275 * arrays is an array of Uint8Array. Return a new Uint8Array which is the concatenation of all.
4276 */
4277DataUtils.concatArrays = function(arrays) {
4278 var totalLength = 0;
4279 for (var i = 0; i < arrays.length; ++i)
4280 totalLength += arrays[i].length;
4281
4282 var result = new Uint8Array(totalLength);
4283 var offset = 0;
4284 for (var i = 0; i < arrays.length; ++i) {
4285 result.set(arrays[i], offset);
4286 offset += arrays[i].length;
4287 }
4288 return result;
4289
4290}
4291
4292// TODO: Take Uint8Array and use TextDecoder when available.
4293DataUtils.decodeUtf8 = function (utftext) {
4294 var string = "";
4295 var i = 0;
4296 var c = 0;
4297 var c1 = 0;
4298 var c2 = 0;
4299
4300 while ( i < utftext.length ) {
4301
4302 c = utftext.charCodeAt(i);
4303
4304 if (c < 128) {
4305 string += String.fromCharCode(c);
4306 i++;
4307 }
4308 else if((c > 191) && (c < 224)) {
4309 c2 = utftext.charCodeAt(i+1);
4310 string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
4311 i += 2;
4312 }
4313 else {
4314 c2 = utftext.charCodeAt(i+1);
4315 var c3 = utftext.charCodeAt(i+2);
4316 string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
4317 i += 3;
4318 }
4319
4320 }
4321
4322 return string;
4323 };
4324
4325//NOT WORKING
4326/*
4327DataUtils.getUTF8StringFromBytes = function(bytes) {
4328
4329 bytes = toString(bytes);
4330
4331 var ix = 0;
4332
4333 if( bytes.slice(0,3) == "\xEF\xBB\xBF") {
4334 ix = 3;
4335 }
4336
4337 var string = "";
4338 for( ; ix < bytes.length; ix++ ) {
4339 var byte1 = bytes[ix].charCodeAt(0);
4340 if( byte1 < 0x80 ) {
4341 string += String.fromCharCode(byte1);
4342 } else if( byte1 >= 0xC2 && byte1 < 0xE0 ) {
4343 var byte2 = bytes[++ix].charCodeAt(0);
4344 string += String.fromCharCode(((byte1&0x1F)<<6) + (byte2&0x3F));
4345 } else if( byte1 >= 0xE0 && byte1 < 0xF0 ) {
4346 var byte2 = bytes[++ix].charCodeAt(0);
4347 var byte3 = bytes[++ix].charCodeAt(0);
4348 string += String.fromCharCode(((byte1&0xFF)<<12) + ((byte2&0x3F)<<6) + (byte3&0x3F));
4349 } else if( byte1 >= 0xF0 && byte1 < 0xF5) {
4350 var byte2 = bytes[++ix].charCodeAt(0);
4351 var byte3 = bytes[++ix].charCodeAt(0);
4352 var byte4 = bytes[++ix].charCodeAt(0);
4353 var codepoint = ((byte1&0x07)<<18) + ((byte2&0x3F)<<12)+ ((byte3&0x3F)<<6) + (byte4&0x3F);
4354 codepoint -= 0x10000;
4355 string += String.fromCharCode(
4356 (codepoint>>10) + 0xD800,
4357 (codepoint&0x3FF) + 0xDC00
4358 );
4359 }
4360 }
4361
4362 return string;
4363}*/
4364
4365/**
4366 * Return true if a1 and a2 are the same length with equal elements.
4367 */
4368DataUtils.arraysEqual = function(a1, a2){
4369 if (a1.length != a2.length)
4370 return false;
4371
4372 for (var i = 0; i < a1.length; ++i) {
4373 if (a1[i] != a2[i])
4374 return false;
4375 }
4376
4377 return true;
4378};
4379
4380/*
4381 * Convert the big endian Uint8Array to an unsigned int.
4382 * Don't check for overflow.
4383 */
4384DataUtils.bigEndianToUnsignedInt = function(bytes) {
4385 var result = 0;
4386 for (var i = 0; i < bytes.length; ++i) {
4387 result <<= 8;
4388 result += bytes[i];
4389 }
4390 return result;
4391};
4392
4393/*
4394 * Convert the int value to a new big endian Uint8Array and return.
4395 * If value is 0 or negative, return Uint8Array(0).
4396 */
4397DataUtils.nonNegativeIntToBigEndian = function(value) {
4398 value = Math.round(value);
4399 if (value <= 0)
4400 return new Uint8Array(0);
4401
4402 // Assume value is not over 64 bits.
4403 var size = 8;
4404 var result = new Uint8Array(size);
4405 var i = 0;
4406 while (value != 0) {
4407 ++i;
4408 result[size - i] = value & 0xff;
4409 value >>= 8;
4410 }
4411 return result.subarray(size - i, size);
4412};
Jeff Thompson3dfddaa2012-12-16 17:55:47 -08004413
4414/*
4415 * Modify array to randomly shuffle the elements.
4416 */
4417DataUtils.shuffle = function(array) {
4418 for (var i = array.length - 1; i >= 1; --i) {
4419 // j is from 0 to i.
4420 var j = Math.floor(Math.random() * (i + 1));
4421 var temp = array[i];
4422 array[i] = array[j];
4423 array[j] = temp;
4424 }
4425}
Wentao Shangbd63e462012-12-03 16:19:33 -08004426/**
Wentao Shang0e291c82012-12-02 23:36:29 -08004427 * This file contains utilities to help encode and decode NDN objects.
4428 * author: Meki Cheraoui
4429 * See COPYING for copyright and distribution information.
4430 */
4431
4432function encodeToHexInterest(interest){
4433 return DataUtils.toHex(encodeToBinaryInterest(interest));
4434}
4435
4436
4437function encodeToBinaryInterest(interest) {
4438 var enc = new BinaryXMLEncoder();
4439 interest.to_ccnb(enc);
4440
4441 return enc.getReducedOstream();
4442}
4443
4444
4445function encodeToHexContentObject(co){
4446 return DataUtils.toHex(encodeToBinaryContentObject(co));
4447}
4448
4449function encodeToBinaryContentObject(co){
4450 var enc = new BinaryXMLEncoder();
4451 co.to_ccnb(enc);
4452
4453 return enc.getReducedOstream();
4454}
4455
4456function encodeForwardingEntry(co){
4457 var enc = new BinaryXMLEncoder();
4458
4459 co.to_ccnb(enc);
4460
4461 var bytes = enc.getReducedOstream();
4462
4463 return bytes;
4464
4465
4466}
4467
4468
4469
4470function decodeHexFaceInstance(result){
4471
4472 var numbers = DataUtils.toNumbers(result);
4473
4474
4475 decoder = new BinaryXMLDecoder(numbers);
4476
4477 if(LOG>3)console.log('DECODING HEX FACE INSTANCE \n'+numbers);
4478
4479 var faceInstance = new FaceInstance();
4480
4481 faceInstance.from_ccnb(decoder);
4482
4483 return faceInstance;
4484
4485}
4486
4487
4488
4489function decodeHexInterest(result){
4490 var numbers = DataUtils.toNumbers(result);
4491
4492 decoder = new BinaryXMLDecoder(numbers);
4493
4494 if(LOG>3)console.log('DECODING HEX INTERST \n'+numbers);
4495
4496 var interest = new Interest();
4497
4498 interest.from_ccnb(decoder);
4499
4500 return interest;
4501
4502}
4503
4504
4505
4506function decodeHexContentObject(result){
4507 var numbers = DataUtils.toNumbers(result);
4508
4509 decoder = new BinaryXMLDecoder(numbers);
4510
4511 if(LOG>3)console.log('DECODED HEX CONTENT OBJECT \n'+numbers);
4512
4513 co = new ContentObject();
4514
4515 co.from_ccnb(decoder);
4516
4517 return co;
4518
4519}
4520
4521
4522
4523function decodeHexForwardingEntry(result){
4524 var numbers = DataUtils.toNumbers(result);
4525
4526 decoder = new BinaryXMLDecoder(numbers);
4527
4528 if(LOG>3)console.log('DECODED HEX FORWARDING ENTRY \n'+numbers);
4529
4530 forwardingEntry = new ForwardingEntry();
4531
4532 forwardingEntry.from_ccnb(decoder);
4533
4534 return forwardingEntry;
4535
4536}
4537
Jeff Thompson68fccd62012-12-29 17:38:23 -08004538/*
4539 * Decode the Uint8Array which holds SubjectPublicKeyInfo and return an RSAKey.
4540 */
4541function decodeSubjectPublicKeyInfo(array) {
4542 var hex = DataUtils.toHex(array).toLowerCase();
4543 var a = _x509_getPublicKeyHexArrayFromCertHex(hex, _x509_getSubjectPublicKeyPosFromCertHex(hex, 0));
4544 var rsaKey = new RSAKey();
4545 rsaKey.setPublic(a[0], a[1]);
4546 return rsaKey;
4547}
4548
Wentao Shang0e291c82012-12-02 23:36:29 -08004549/* Return a user friendly HTML string with the contents of co.
4550 This also outputs to console.log.
4551 */
4552function contentObjectToHtml(/* ContentObject */ co) {
4553 var output ="";
4554
4555 if(co==-1)
4556 output+= "NO CONTENT FOUND"
4557 else if (co==-2)
4558 output+= "CONTENT NAME IS EMPTY"
4559 else{
4560 if(co.name!=null && co.name.components!=null){
4561 output+= "NAME: " + co.name.to_uri();
4562
4563 output+= "<br />";
4564 output+= "<br />";
4565 }
4566
4567 if(co.content !=null){
4568 output += "CONTENT(ASCII): "+ DataUtils.toString(co.content);
4569
4570 output+= "<br />";
4571 output+= "<br />";
4572 }
4573 if(co.content !=null){
4574 output += "CONTENT(hex): "+ DataUtils.toHex(co.content);
4575
4576 output+= "<br />";
4577 output+= "<br />";
4578 }
4579 if(co.signature !=null && co.signature.signature!=null){
4580 output += "SIGNATURE(hex): "+ DataUtils.toHex(co.signature.signature);
4581
4582 output+= "<br />";
4583 output+= "<br />";
4584 }
4585 if(co.signedInfo !=null && co.signedInfo.publisher!=null && co.signedInfo.publisher.publisherPublicKeyDigest!=null){
4586 output += "Publisher Public Key Digest(hex): "+ DataUtils.toHex(co.signedInfo.publisher.publisherPublicKeyDigest);
4587
4588 output+= "<br />";
4589 output+= "<br />";
4590 }
4591 if(co.signedInfo !=null && co.signedInfo.timestamp!=null){
4592 var d = new Date();
4593 d.setTime( co.signedInfo.timestamp.msec );
4594
4595 var bytes = [217, 185, 12, 225, 217, 185, 12, 225];
4596
4597 output += "TimeStamp: "+d;
4598 output+= "<br />";
4599 output += "TimeStamp(number): "+ co.signedInfo.timestamp.msec;
4600
4601 output+= "<br />";
4602 }
4603 if(co.signedInfo !=null && co.signedInfo.finalBlockID!=null){
4604 output += "FinalBlockID: "+ DataUtils.toHex(co.signedInfo.finalBlockID);
4605 output+= "<br />";
4606 }
4607 if(co.signedInfo!=null && co.signedInfo.locator!=null && co.signedInfo.locator.certificate!=null){
Jeff Thompson68fccd62012-12-29 17:38:23 -08004608 var certificateHex = DataUtils.toHex(co.signedInfo.locator.certificate).toLowerCase();
Wentao Shang0e291c82012-12-02 23:36:29 -08004609 var signature = DataUtils.toHex(co.signature.signature).toLowerCase();
4610 var input = DataUtils.toString(co.rawSignatureData);
4611
Jeff Thompson68fccd62012-12-29 17:38:23 -08004612 output += "Hex Certificate: "+ certificateHex ;
Wentao Shang0e291c82012-12-02 23:36:29 -08004613
4614 output+= "<br />";
4615 output+= "<br />";
4616
Wentao Shang0e291c82012-12-02 23:36:29 -08004617 var x509 = new X509();
Jeff Thompson68fccd62012-12-29 17:38:23 -08004618 x509.readCertHex(certificateHex);
Jeff Thompson253cab42012-12-29 17:48:40 -08004619 output += "Public key (hex) modulus: " + x509.subjectPublicKeyRSA.n.toString(16) + "<br/>";
4620 output += "exponent: " + x509.subjectPublicKeyRSA.e.toString(16) + "<br/>";
4621 output += "<br/>";
Wentao Shang0e291c82012-12-02 23:36:29 -08004622
Wentao Shang0e291c82012-12-02 23:36:29 -08004623 var result = x509.subjectPublicKeyRSA.verifyByteArray(co.rawSignatureData, signature);
4624 if(LOG>2) console.log('result is '+result);
4625
4626 var n = x509.subjectPublicKeyRSA.n;
4627 var e = x509.subjectPublicKeyRSA.e;
4628
4629 if(LOG>2) console.log('PUBLIC KEY n after is ');
4630 if(LOG>2) console.log(n);
4631
4632 if(LOG>2) console.log('EXPONENT e after is ');
4633 if(LOG>2) console.log(e);
4634
Wentao Shang0e291c82012-12-02 23:36:29 -08004635 if(result)
Jeff Thompson68fccd62012-12-29 17:38:23 -08004636 output += 'SIGNATURE VALID';
Wentao Shang0e291c82012-12-02 23:36:29 -08004637 else
Jeff Thompson68fccd62012-12-29 17:38:23 -08004638 output += 'SIGNATURE INVALID';
Wentao Shang0e291c82012-12-02 23:36:29 -08004639
4640 //output += "VALID: "+ toHex(co.signedInfo.locator.publicKey);
4641
4642 output+= "<br />";
4643 output+= "<br />";
4644
4645 //if(LOG>4) console.log('str'[1]);
4646 }
4647 if(co.signedInfo!=null && co.signedInfo.locator!=null && co.signedInfo.locator.publicKey!=null){
Wentao Shang0e291c82012-12-02 23:36:29 -08004648 var publickeyHex = DataUtils.toHex(co.signedInfo.locator.publicKey).toLowerCase();
4649 var publickeyString = DataUtils.toString(co.signedInfo.locator.publicKey);
4650 var signature = DataUtils.toHex(co.signature.signature).toLowerCase();
4651 var input = DataUtils.toString(co.rawSignatureData);
4652
Jeff Thompson68fccd62012-12-29 17:38:23 -08004653 output += "Public key: " + publickeyHex;
Wentao Shang0e291c82012-12-02 23:36:29 -08004654
4655 output+= "<br />";
4656 output+= "<br />";
4657
4658 if(LOG>2) console.log(" ContentName + SignedInfo + Content = "+input);
Wentao Shang0e291c82012-12-02 23:36:29 -08004659 if(LOG>2) console.log(" PublicKeyHex = "+publickeyHex );
4660 if(LOG>2) console.log(" PublicKeyString = "+publickeyString );
4661
4662 if(LOG>2) console.log(" Signature "+signature );
4663
4664 if(LOG>2) console.log(" Signature NOW IS" );
4665
4666 if(LOG>2) console.log(co.signature.signature);
Jeff Thompson68fccd62012-12-29 17:38:23 -08004667
4668 var rsakey = decodeSubjectPublicKeyInfo(co.signedInfo.locator.publicKey);
Wentao Shang0e291c82012-12-02 23:36:29 -08004669
Jeff Thompson68fccd62012-12-29 17:38:23 -08004670 output += "Public key (hex) modulus: " + rsakey.n.toString(16) + "<br/>";
4671 output += "exponent: " + rsakey.e.toString(16) + "<br/>";
4672 output += "<br/>";
4673
Wentao Shang0e291c82012-12-02 23:36:29 -08004674 var result = rsakey.verifyByteArray(co.rawSignatureData,signature);
4675 // var result = rsakey.verifyString(input, signature);
4676
Wentao Shang2b740e62012-12-07 00:02:53 -08004677 if(LOG>2) console.log('PUBLIC KEY n after is ');
4678 if(LOG>2) console.log(rsakey.n);
Wentao Shang0e291c82012-12-02 23:36:29 -08004679
Wentao Shang2b740e62012-12-07 00:02:53 -08004680 if(LOG>2) console.log('EXPONENT e after is ');
4681 if(LOG>2) console.log(rsakey.e);
Wentao Shang0e291c82012-12-02 23:36:29 -08004682
4683 if(result)
4684 output += 'SIGNATURE VALID';
4685 else
4686 output += 'SIGNATURE INVALID';
4687
4688 //output += "VALID: "+ toHex(co.signedInfo.locator.publicKey);
4689
4690 output+= "<br />";
4691 output+= "<br />";
4692
4693 //if(LOG>4) console.log('str'[1]);
4694 }
4695 }
4696
4697 return output;
4698}
Jeff Thompson1a338f82012-12-29 17:07:04 -08004699
4700
Wentao Shangbd63e462012-12-03 16:19:33 -08004701/**
Wentao Shang0e291c82012-12-02 23:36:29 -08004702 * @author: Meki Cheraoui
4703 * See COPYING for copyright and distribution information.
4704 */
4705
4706var KeyManager = function KeyManager(){
4707
4708
4709//Certificate
4710
4711this.certificate = 'MIIBmzCCAQQCCQC32FyQa61S7jANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwd'+
4712
4713'heGVsY2R2MB4XDTEyMDQyODIzNDQzN1oXDTEyMDUyODIzNDQzN1owEjEQMA4GA1'+
4714
4715'UEAxMHYXhlbGNkdjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4X0wp9goq'+
4716
4717'xuECxdULcr2IHr9Ih4Iaypg0Wy39URIup8/CLzQmdsh3RYqd55hqonu5VTTpH3i'+
4718
4719'MLx6xZDVJAZ8OJi7pvXcQ2C4Re2kjL2c8SanI0RfDhlS1zJadfr1VhRPmpivcYa'+
4720
4721'wJ4aFuOLAi+qHFxtN7lhcGCgpW1OV60oXd58CAwEAATANBgkqhkiG9w0BAQUFAA'+
4722
4723'OBgQDLOrA1fXzSrpftUB5Ro6DigX1Bjkf7F5Bkd69hSVp+jYeJFBBlsILQAfSxU'+
4724
4725'ZPQtD+2Yc3iCmSYNyxqu9PcufDRJlnvB7PG29+L3y9lR37tetzUV9eTscJ7rdp8'+
4726
4727'Wt6AzpW32IJ/54yKNfP7S6ZIoIG+LP6EIxq6s8K1MXRt8uBJKw==';
4728
4729
4730//this.publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhfTCn2CirG4QLF1QtyvYgev0iHghrKmDRbLf1REi6nz8IvNCZ2yHdFip3nmGqie7lVNOkfeIwvHrFkNUkBnw4mLum9dxDYLhF7aSMvZzxJqcjRF8OGVLXMlp1+vVWFE+amK9xhrAnhoW44sCL6ocXG03uWFwYKClbU5XrShd3nwIDAQAB';
4731this.publicKey ='30819F300D06092A864886F70D010101050003818D0030818902818100E17D30A7D828AB1B840B17542DCAF6207AFD221E086B2A60D16CB7F54448BA9F3F08BCD099DB21DD162A779E61AA89EEE554D3A47DE230BC7AC590D524067C3898BBA6F5DC4360B845EDA48CBD9CF126A723445F0E1952D7325A75FAF556144F9A98AF7186B0278685B8E2C08BEA87171B4DEE585C1828295B5395EB4A17779F0203010001';
4732//Private Key
4733
4734this.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';
4735
4736
4737/*
4738 this.certificate =
4739 'MIIBvTCCASYCCQD55fNzc0WF7TANBgkqhkiG9w0BAQUFADAjMQswCQYDVQQGEwJK'+
4740 'UDEUMBIGA1UEChMLMDAtVEVTVC1SU0EwHhcNMTAwNTI4MDIwODUxWhcNMjAwNTI1'+
4741 'MDIwODUxWjAjMQswCQYDVQQGEwJKUDEUMBIGA1UEChMLMDAtVEVTVC1SU0EwgZ8w'+
4742 'DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANGEYXtfgDRlWUSDn3haY4NVVQiKI9Cz'+
4743 'Thoua9+DxJuiseyzmBBe7Roh1RPqdvmtOHmEPbJ+kXZYhbozzPRbFGHCJyBfCLzQ'+
4744 'fVos9/qUQ88u83b0SFA2MGmQWQAlRtLy66EkR4rDRwTj2DzR4EEXgEKpIvo8VBs/'+
4745 '3+sHLF3ESgAhAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAEZ6mXFFq3AzfaqWHmCy1'+
4746 'ARjlauYAa8ZmUFnLm0emg9dkVBJ63aEqARhtok6bDQDzSJxiLpCEF6G4b/Nv/M/M'+
4747 'LyhP+OoOTmETMegAVQMq71choVJyOFE5BtQa6M/lCHEOya5QUfoRF2HF9EjRF44K'+
4748 '3OK+u3ivTSj3zwjtpudY5Xo=';
4749
4750 this.privateKey =
4751 'MIICWwIBAAKBgQDRhGF7X4A0ZVlEg594WmODVVUIiiPQs04aLmvfg8SborHss5gQ'+
4752 'Xu0aIdUT6nb5rTh5hD2yfpF2WIW6M8z0WxRhwicgXwi80H1aLPf6lEPPLvN29EhQ'+
4753 'NjBpkFkAJUbS8uuhJEeKw0cE49g80eBBF4BCqSL6PFQbP9/rByxdxEoAIQIDAQAB'+
4754 'AoGAA9/q3Zk6ib2GFRpKDLO/O2KMnAfR+b4XJ6zMGeoZ7Lbpi3MW0Nawk9ckVaX0'+
4755 'ZVGqxbSIX5Cvp/yjHHpww+QbUFrw/gCjLiiYjM9E8C3uAF5AKJ0r4GBPl4u8K4bp'+
4756 'bXeSxSB60/wPQFiQAJVcA5xhZVzqNuF3EjuKdHsw+dk+dPECQQDubX/lVGFgD/xY'+
4757 'uchz56Yc7VHX+58BUkNSewSzwJRbcueqknXRWwj97SXqpnYfKqZq78dnEF10SWsr'+
4758 '/NMKi+7XAkEA4PVqDv/OZAbWr4syXZNv/Mpl4r5suzYMMUD9U8B2JIRnrhmGZPzL'+
4759 'x23N9J4hEJ+Xh8tSKVc80jOkrvGlSv+BxwJAaTOtjA3YTV+gU7Hdza53sCnSw/8F'+
4760 'YLrgc6NOJtYhX9xqdevbyn1lkU0zPr8mPYg/F84m6MXixm2iuSz8HZoyzwJARi2p'+
4761 'aYZ5/5B2lwroqnKdZBJMGKFpUDn7Mb5hiSgocxnvMkv6NjT66Xsi3iYakJII9q8C'+
4762 'Ma1qZvT/cigmdbAh7wJAQNXyoizuGEltiSaBXx4H29EdXNYWDJ9SS5f070BRbAIl'+
4763 'dqRh3rcNvpY6BKJqFapda1DjdcncZECMizT/GMrc1w==';
4764
4765 */
4766};
4767
4768
4769KeyManager.prototype.verify = function verify(message,signature){
4770
4771 var input = message;
4772
4773 var _PEM_X509CERT_STRING_ = this.certificate;
4774
4775 var x509 = new X509();
4776
4777 x509.readCertPEM(_PEM_X509CERT_STRING_);
4778
4779 var result = x509.subjectPublicKeyRSA.verifyString(input, signature);
4780
4781 return result;
4782};
4783
4784KeyManager.prototype.sign= function sign(message){
4785
4786 var input = message;
4787
4788 var _PEM_PRIVATE_KEY_STRING_ = this.privateKey;
4789
4790 var rsa = new RSAKey();
4791
4792 rsa.readPrivateKeyFromPEMString(_PEM_PRIVATE_KEY_STRING_);
4793
4794 var hSig = rsa.signString(input, "sha256");
4795
4796 return hSig;
4797
4798};
4799
4800
4801
4802var globalKeyManager = new KeyManager();
4803//var KeyPair = { "public" : "PUBLIC KEY" , "private" : "PRIVATE KEY" };
4804
4805
4806/*
4807 * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined
4808 * in FIPS 180-2
4809 * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
4810 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
4811 * Distributed under the BSD License
4812 * See http://pajhome.org.uk/crypt/md5 for details.
4813 * Also http://anmar.eu.org/projects/jssha2/
4814 */
4815
4816/*
4817 * Configurable variables. You may need to tweak these to be compatible with
4818 * the server-side, but the defaults work in most cases.
4819 */
4820var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
4821var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
4822
4823/*
4824 * These are the functions you'll usually want to call
4825 * They take string arguments and return either hex or base-64 encoded strings
4826 */
4827
4828//@author axelcdv
4829/**
4830 * Computes the Sha-256 hash of the given byte array
4831 * @param {byte[]}
4832 * @return the hex string corresponding to the Sha-256 hash of the byte array
4833 */
4834function hex_sha256_from_bytes(byteArray){
4835 return rstr2hex(binb2rstr(binb_sha256( byteArray2binb(byteArray), byteArray.length * 8)));
4836}
4837
4838function hex_sha256(s) { return rstr2hex(rstr_sha256(str2rstr_utf8(s))); }
4839function b64_sha256(s) { return rstr2b64(rstr_sha256(str2rstr_utf8(s))); }
4840function any_sha256(s, e) { return rstr2any(rstr_sha256(str2rstr_utf8(s)), e); }
4841function hex_hmac_sha256(k, d)
4842 { return rstr2hex(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d))); }
4843function b64_hmac_sha256(k, d)
4844 { return rstr2b64(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d))); }
4845function any_hmac_sha256(k, d, e)
4846 { return rstr2any(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
4847
4848
4849/*
4850 function hex_sha256(s) { return rstr2hex(rstr_sha256(s)); }
4851function b64_sha256(s) { return rstr2b64(rstr_sha256(s)); }
4852function any_sha256(s, e) { return rstr2any(rstr_sha256(s), e); }
4853function hex_hmac_sha256(k, d)
4854 { return rstr2hex(rstr_hmac_sha256(str2rstr_utf8(k), d)); }
4855function b64_hmac_sha256(k, d)
4856 { return rstr2b64(rstr_hmac_sha256(str2rstr_utf8(k), d)); }
4857function any_hmac_sha256(k, d, e)
4858 { return rstr2any(rstr_hmac_sha256(str2rstr_utf8(k), d), e); }
4859*/
4860
4861/*
4862 * Perform a simple self-test to see if the VM is working
4863 */
4864function sha256_vm_test()
4865{
4866 return hex_sha256("abc").toLowerCase() ==
4867 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad";
4868}
4869
4870/**
4871 * Calculate the sha256 of a raw string
4872 * @param s: the raw string
4873 */
4874function rstr_sha256(s)
4875{
4876 return binb2rstr(binb_sha256(rstr2binb(s), s.length * 8));
4877}
4878
4879/**
4880 * Calculate the HMAC-sha256 of a key and some data (raw strings)
4881 */
4882function rstr_hmac_sha256(key, data)
4883{
4884 var bkey = rstr2binb(key);
4885 if(bkey.length > 16) bkey = binb_sha256(bkey, key.length * 8);
4886
4887 var ipad = Array(16), opad = Array(16);
4888 for(var i = 0; i < 16; i++)
4889 {
4890 ipad[i] = bkey[i] ^ 0x36363636;
4891 opad[i] = bkey[i] ^ 0x5C5C5C5C;
4892 }
4893
4894 var hash = binb_sha256(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
4895 return binb2rstr(binb_sha256(opad.concat(hash), 512 + 256));
4896}
4897
4898/**
4899 * Convert a raw string to a hex string
4900 */
4901function rstr2hex(input)
4902{
4903 try { hexcase } catch(e) { hexcase=0; }
4904 var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
4905 var output = "";
4906 var x;
4907 for(var i = 0; i < input.length; i++)
4908 {
4909 x = input.charCodeAt(i);
4910 output += hex_tab.charAt((x >>> 4) & 0x0F)
4911 + hex_tab.charAt( x & 0x0F);
4912 }
4913 return output;
4914}
4915
4916/*
4917 * Convert a raw string to a base-64 string
4918 */
4919function rstr2b64(input)
4920{
4921 try { b64pad } catch(e) { b64pad=''; }
4922 var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4923 var output = "";
4924 var len = input.length;
4925 for(var i = 0; i < len; i += 3)
4926 {
4927 var triplet = (input.charCodeAt(i) << 16)
4928 | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
4929 | (i + 2 < len ? input.charCodeAt(i+2) : 0);
4930 for(var j = 0; j < 4; j++)
4931 {
4932 if(i * 8 + j * 6 > input.length * 8) output += b64pad;
4933 else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
4934 }
4935 }
4936 return output;
4937}
4938
4939/*
4940 * Convert a raw string to an arbitrary string encoding
4941 */
4942function rstr2any(input, encoding)
4943{
4944 var divisor = encoding.length;
4945 var remainders = Array();
4946 var i, q, x, quotient;
4947
4948 /* Convert to an array of 16-bit big-endian values, forming the dividend */
4949 var dividend = Array(Math.ceil(input.length / 2));
4950 for(i = 0; i < dividend.length; i++)
4951 {
4952 dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
4953 }
4954
4955 /*
4956 * Repeatedly perform a long division. The binary array forms the dividend,
4957 * the length of the encoding is the divisor. Once computed, the quotient
4958 * forms the dividend for the next step. We stop when the dividend is zero.
4959 * All remainders are stored for later use.
4960 */
4961 while(dividend.length > 0)
4962 {
4963 quotient = Array();
4964 x = 0;
4965 for(i = 0; i < dividend.length; i++)
4966 {
4967 x = (x << 16) + dividend[i];
4968 q = Math.floor(x / divisor);
4969 x -= q * divisor;
4970 if(quotient.length > 0 || q > 0)
4971 quotient[quotient.length] = q;
4972 }
4973 remainders[remainders.length] = x;
4974 dividend = quotient;
4975 }
4976
4977 /* Convert the remainders to the output string */
4978 var output = "";
4979 for(i = remainders.length - 1; i >= 0; i--)
4980 output += encoding.charAt(remainders[i]);
4981
4982 /* Append leading zero equivalents */
4983 var full_length = Math.ceil(input.length * 8 /
4984 (Math.log(encoding.length) / Math.log(2)))
4985 for(i = output.length; i < full_length; i++)
4986 output = encoding[0] + output;
4987
4988 return output;
4989}
4990
4991/*
4992 * Encode a string as utf-8.
4993 * For efficiency, this assumes the input is valid utf-16.
4994 */
4995function str2rstr_utf8(input)
4996{
4997 var output = "";
4998 var i = -1;
4999 var x, y;
5000
5001 while(++i < input.length)
5002 {
5003 /* Decode utf-16 surrogate pairs */
5004 x = input.charCodeAt(i);
5005 y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
5006 if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
5007 {
5008 x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
5009 i++;
5010 }
5011
5012 /* Encode output as utf-8 */
5013 if(x <= 0x7F)
5014 output += String.fromCharCode(x);
5015 else if(x <= 0x7FF)
5016 output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
5017 0x80 | ( x & 0x3F));
5018 else if(x <= 0xFFFF)
5019 output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
5020 0x80 | ((x >>> 6 ) & 0x3F),
5021 0x80 | ( x & 0x3F));
5022 else if(x <= 0x1FFFFF)
5023 output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
5024 0x80 | ((x >>> 12) & 0x3F),
5025 0x80 | ((x >>> 6 ) & 0x3F),
5026 0x80 | ( x & 0x3F));
5027 }
5028 return output;
5029}
5030
5031/*
5032 * Encode a string as utf-16
5033 */
5034function str2rstr_utf16le(input)
5035{
5036 var output = "";
5037 for(var i = 0; i < input.length; i++)
5038 output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
5039 (input.charCodeAt(i) >>> 8) & 0xFF);
5040 return output;
5041}
5042
5043function str2rstr_utf16be(input)
5044{
5045 var output = "";
5046 for(var i = 0; i < input.length; i++)
5047 output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
5048 input.charCodeAt(i) & 0xFF);
5049 return output;
5050}
5051
5052/**
5053 * Convert a raw string to an array of big-endian words
5054 * Characters >255 have their high-byte silently ignored.
5055 */
5056function rstr2binb(input)
5057{
5058 //console.log('Raw string comming is '+input);
5059 var output = Array(input.length >> 2);
Wentao Shangc0311e52012-12-03 10:38:23 -08005060 /* JavaScript automatically zeroizes a new array.
Wentao Shang0e291c82012-12-02 23:36:29 -08005061 for(var i = 0; i < output.length; i++)
5062 output[i] = 0;
Wentao Shangc0311e52012-12-03 10:38:23 -08005063 */
Wentao Shang0e291c82012-12-02 23:36:29 -08005064 for(var i = 0; i < input.length * 8; i += 8)
5065 output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
5066 return output;
5067}
5068
5069/**
5070 * @author axelcdv
5071 * Convert a byte array to an array of big-endian words
5072 * @param {byte[]} input
5073 * @return the array of big-endian words
5074 */
5075function byteArray2binb(input){
5076 //console.log("Byte array coming is " + input);
5077 var output = Array(input.length >> 2);
Wentao Shangc0311e52012-12-03 10:38:23 -08005078 /* JavaScript automatically zeroizes a new array.
Wentao Shang0e291c82012-12-02 23:36:29 -08005079 for(var i = 0; i < output.length; i++)
5080 output[i] = 0;
Wentao Shangc0311e52012-12-03 10:38:23 -08005081 */
Wentao Shang0e291c82012-12-02 23:36:29 -08005082 for(var i = 0; i < input.length * 8; i += 8)
5083 output[i>>5] |= (input[i / 8] & 0xFF) << (24 - i % 32);
5084 return output;
5085}
5086
5087/*
5088 * Convert an array of big-endian words to a string
5089 */
5090function binb2rstr(input)
5091{
5092 var output = "";
5093 for(var i = 0; i < input.length * 32; i += 8)
5094 output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
5095 return output;
5096}
5097
5098/*
5099 * Main sha256 function, with its support functions
5100 */
5101function sha256_S (X, n) {return ( X >>> n ) | (X << (32 - n));}
5102function sha256_R (X, n) {return ( X >>> n );}
5103function sha256_Ch(x, y, z) {return ((x & y) ^ ((~x) & z));}
5104function sha256_Maj(x, y, z) {return ((x & y) ^ (x & z) ^ (y & z));}
5105function sha256_Sigma0256(x) {return (sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22));}
5106function sha256_Sigma1256(x) {return (sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25));}
5107function sha256_Gamma0256(x) {return (sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3));}
5108function sha256_Gamma1256(x) {return (sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10));}
5109function sha256_Sigma0512(x) {return (sha256_S(x, 28) ^ sha256_S(x, 34) ^ sha256_S(x, 39));}
5110function sha256_Sigma1512(x) {return (sha256_S(x, 14) ^ sha256_S(x, 18) ^ sha256_S(x, 41));}
5111function sha256_Gamma0512(x) {return (sha256_S(x, 1) ^ sha256_S(x, 8) ^ sha256_R(x, 7));}
5112function sha256_Gamma1512(x) {return (sha256_S(x, 19) ^ sha256_S(x, 61) ^ sha256_R(x, 6));}
5113
5114var sha256_K = new Array
5115(
5116 1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993,
5117 -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987,
5118 1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522,
5119 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986,
5120 -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585,
5121 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291,
5122 1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885,
5123 -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344,
5124 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218,
5125 1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872,
5126 -1866530822, -1538233109, -1090935817, -965641998
5127);
5128
5129function binb_sha256(m, l)
5130{
5131 var HASH = new Array(1779033703, -1150833019, 1013904242, -1521486534,
5132 1359893119, -1694144372, 528734635, 1541459225);
5133 var W = new Array(64);
Wentao Shang0e291c82012-12-02 23:36:29 -08005134
5135 /* append padding */
5136 m[l >> 5] |= 0x80 << (24 - l % 32);
5137 m[((l + 64 >> 9) << 4) + 15] = l;
Wentao Shangc0311e52012-12-03 10:38:23 -08005138
5139 for(var offset = 0; offset < m.length; offset += 16)
5140 processBlock_sha256(m, offset, HASH, W);
Wentao Shang0e291c82012-12-02 23:36:29 -08005141
Wentao Shangc0311e52012-12-03 10:38:23 -08005142 return HASH;
5143}
5144
5145/*
5146 * Process a block of 16 4-byte words in m starting at offset and update HASH.
5147 * offset must be a multiple of 16 and less than m.length. W is a scratchpad Array(64).
5148 */
5149function processBlock_sha256(m, offset, HASH, W) {
5150 var a, b, c, d, e, f, g, h;
5151 var j, T1, T2;
5152
Wentao Shang0e291c82012-12-02 23:36:29 -08005153 a = HASH[0];
5154 b = HASH[1];
5155 c = HASH[2];
5156 d = HASH[3];
5157 e = HASH[4];
5158 f = HASH[5];
5159 g = HASH[6];
5160 h = HASH[7];
5161
5162 for(j = 0; j < 64; j++)
5163 {
Wentao Shangc0311e52012-12-03 10:38:23 -08005164 if (j < 16) W[j] = m[j + offset];
Wentao Shang0e291c82012-12-02 23:36:29 -08005165 else W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]),
5166 sha256_Gamma0256(W[j - 15])), W[j - 16]);
5167
5168 T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)),
5169 sha256_K[j]), W[j]);
5170 T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
5171 h = g;
5172 g = f;
5173 f = e;
5174 e = safe_add(d, T1);
5175 d = c;
5176 c = b;
5177 b = a;
5178 a = safe_add(T1, T2);
5179 }
5180
5181 HASH[0] = safe_add(a, HASH[0]);
5182 HASH[1] = safe_add(b, HASH[1]);
5183 HASH[2] = safe_add(c, HASH[2]);
5184 HASH[3] = safe_add(d, HASH[3]);
5185 HASH[4] = safe_add(e, HASH[4]);
5186 HASH[5] = safe_add(f, HASH[5]);
5187 HASH[6] = safe_add(g, HASH[6]);
5188 HASH[7] = safe_add(h, HASH[7]);
Wentao Shang0e291c82012-12-02 23:36:29 -08005189}
5190
5191function safe_add (x, y)
5192{
5193 var lsw = (x & 0xFFFF) + (y & 0xFFFF);
5194 var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
5195 return (msw << 16) | (lsw & 0xFFFF);
5196}
Wentao Shangc0311e52012-12-03 10:38:23 -08005197
5198/*
5199 * Create a Sha256, call update(data) multiple times, then call finalize().
5200 */
5201var Sha256 = function Sha256() {
5202 this.W = new Array(64);
5203 this.hash = new Array(1779033703, -1150833019, 1013904242, -1521486534,
5204 1359893119, -1694144372, 528734635, 1541459225);
5205 this.nTotalBytes = 0;
5206 this.buffer = new Uint8Array(16 * 4);
5207 this.nBufferBytes = 0;
5208}
5209
5210/*
5211 * Update the hash with data, which is Uint8Array.
5212 */
5213Sha256.prototype.update = function(data) {
5214 this.nTotalBytes += data.length;
5215
5216 if (this.nBufferBytes > 0) {
5217 // Fill up the buffer and process it first.
5218 var bytesNeeded = this.buffer.length - this.nBufferBytes;
5219 if (data.length < bytesNeeded) {
5220 this.buffer.set(data, this.nBufferBytes);
5221 this.nBufferBytes += data.length;
5222 return;
5223 }
5224 else {
5225 this.buffer.set(data.subarray(0, bytesNeeded), this.nBufferBytes);
5226 processBlock_sha256(byteArray2binb(this.buffer), 0, this.hash, this.W);
5227 this.nBufferBytes = 0;
5228 // Consume the bytes from data.
5229 data = data.subarray(bytesNeeded, data.length);
5230 if (data.length == 0)
5231 return;
5232 }
5233 }
5234
5235 // 2^6 is 16 * 4.
5236 var nBlocks = data.length >> 6;
5237 if (nBlocks > 0) {
5238 var nBytes = nBlocks * 16 * 4;
5239 var m = byteArray2binb(data.subarray(0, nBytes));
5240 for(var offset = 0; offset < m.length; offset += 16)
5241 processBlock_sha256(m, offset, this.hash, this.W);
5242
5243 data = data.subarray(nBytes, data.length);
5244 }
5245
5246 if (data.length > 0) {
5247 // Save the remainder in the buffer.
5248 this.buffer.set(data);
5249 this.nBufferBytes = data.length;
5250 }
5251}
5252
5253/*
5254 * Finalize the hash and return the result as Uint8Array.
5255 * Only call this once. Return values on subsequent calls are undefined.
5256 */
5257Sha256.prototype.finalize = function() {
5258 var m = byteArray2binb(this.buffer.subarray(0, this.nBufferBytes));
5259 /* append padding */
5260 var l = this.nBufferBytes * 8;
5261 m[l >> 5] |= 0x80 << (24 - l % 32);
5262 m[((l + 64 >> 9) << 4) + 15] = this.nTotalBytes * 8;
5263
5264 for(var offset = 0; offset < m.length; offset += 16)
5265 processBlock_sha256(m, offset, this.hash, this.W);
5266
5267 return Sha256.binb2Uint8Array(this.hash);
5268}
5269
5270/*
5271 * Convert an array of big-endian words to Uint8Array.
5272 */
5273Sha256.binb2Uint8Array = function(input)
5274{
5275 var output = new Uint8Array(input.length * 4);
5276 var iOutput = 0;
5277 for (var i = 0; i < input.length * 32; i += 8)
5278 output[iOutput++] = (input[i>>5] >>> (24 - i % 32)) & 0xFF;
5279 return output;
5280}
Wentao Shang0e291c82012-12-02 23:36:29 -08005281var b64map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
5282var b64pad="=";
5283
5284function hex2b64(h) {
5285 var i;
5286 var c;
5287 var ret = "";
5288 for(i = 0; i+3 <= h.length; i+=3) {
5289 c = parseInt(h.substring(i,i+3),16);
5290 ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63);
5291 }
5292 if(i+1 == h.length) {
5293 c = parseInt(h.substring(i,i+1),16);
5294 ret += b64map.charAt(c << 2);
5295 }
5296 else if(i+2 == h.length) {
5297 c = parseInt(h.substring(i,i+2),16);
5298 ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4);
5299 }
5300 while((ret.length & 3) > 0) ret += b64pad;
5301 return ret;
5302}
5303
5304// convert a base64 string to hex
5305function b64tohex(s) {
5306 var ret = ""
5307 var i;
5308 var k = 0; // b64 state, 0-3
5309 var slop;
5310 for(i = 0; i < s.length; ++i) {
5311 if(s.charAt(i) == b64pad) break;
5312 v = b64map.indexOf(s.charAt(i));
5313 if(v < 0) continue;
5314 if(k == 0) {
5315 ret += int2char(v >> 2);
5316 slop = v & 3;
5317 k = 1;
5318 }
5319 else if(k == 1) {
5320 ret += int2char((slop << 2) | (v >> 4));
5321 slop = v & 0xf;
5322 k = 2;
5323 }
5324 else if(k == 2) {
5325 ret += int2char(slop);
5326 ret += int2char(v >> 2);
5327 slop = v & 3;
5328 k = 3;
5329 }
5330 else {
5331 ret += int2char((slop << 2) | (v >> 4));
5332 ret += int2char(v & 0xf);
5333 k = 0;
5334 }
5335 }
5336 if(k == 1)
5337 ret += int2char(slop << 2);
5338 return ret;
5339}
5340
5341// convert a base64 string to a byte/number array
5342function b64toBA(s) {
5343 //piggyback on b64tohex for now, optimize later
5344 var h = b64tohex(s);
5345 var i;
5346 var a = new Array();
5347 for(i = 0; 2*i < h.length; ++i) {
5348 a[i] = parseInt(h.substring(2*i,2*i+2),16);
5349 }
5350 return a;
5351}
5352// Depends on jsbn.js and rng.js
5353
5354// Version 1.1: support utf-8 encoding in pkcs1pad2
5355
5356// convert a (hex) string to a bignum object
5357function parseBigInt(str,r) {
5358 return new BigInteger(str,r);
5359}
5360
5361function linebrk(s,n) {
5362 var ret = "";
5363 var i = 0;
5364 while(i + n < s.length) {
5365 ret += s.substring(i,i+n) + "\n";
5366 i += n;
5367 }
5368 return ret + s.substring(i,s.length);
5369}
5370
5371function byte2Hex(b) {
5372 if(b < 0x10)
5373 return "0" + b.toString(16);
5374 else
5375 return b.toString(16);
5376}
5377
5378/**
5379 * PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint
5380 * @param s: the string to encode
5381 * @param n: the size in byte
5382 */
5383function pkcs1pad2(s,n) {
5384 if(n < s.length + 11) { // TODO: fix for utf-8
5385 alert("Message too long for RSA");
5386 return null;
5387 }
5388 var ba = new Array();
5389 var i = s.length - 1;
5390 while(i >= 0 && n > 0) {
5391 var c = s.charCodeAt(i--);
5392 if(c < 128) { // encode using utf-8
5393 ba[--n] = c;
5394 }
5395 else if((c > 127) && (c < 2048)) {
5396 ba[--n] = (c & 63) | 128;
5397 ba[--n] = (c >> 6) | 192;
5398 }
5399 else {
5400 ba[--n] = (c & 63) | 128;
5401 ba[--n] = ((c >> 6) & 63) | 128;
5402 ba[--n] = (c >> 12) | 224;
5403 }
5404 }
5405 ba[--n] = 0;
5406 var rng = new SecureRandom();
5407 var x = new Array();
5408 while(n > 2) { // random non-zero pad
5409 x[0] = 0;
5410 while(x[0] == 0) rng.nextBytes(x);
5411 ba[--n] = x[0];
5412 }
5413 ba[--n] = 2;
5414 ba[--n] = 0;
5415 return new BigInteger(ba);
5416}
5417
5418/**
5419 * "empty" RSA key constructor
5420 * @returns {RSAKey}
5421 */
5422function RSAKey() {
5423 this.n = null;
5424 this.e = 0;
5425 this.d = null;
5426 this.p = null;
5427 this.q = null;
5428 this.dmp1 = null;
5429 this.dmq1 = null;
5430 this.coeff = null;
5431}
5432
5433/**
5434 * Set the public key fields N and e from hex strings
5435 * @param N
5436 * @param E
5437 * @returns {RSASetPublic}
5438 */
5439function RSASetPublic(N,E) {
5440 if(N != null && E != null && N.length > 0 && E.length > 0) {
5441 this.n = parseBigInt(N,16);
5442 this.e = parseInt(E,16);
5443 }
5444 else
5445 alert("Invalid RSA public key");
5446}
5447
5448/**
5449 * Perform raw public operation on "x": return x^e (mod n)
5450 * @param x
5451 * @returns x^e (mod n)
5452 */
5453function RSADoPublic(x) {
5454 return x.modPowInt(this.e, this.n);
5455}
5456
5457/**
5458 * Return the PKCS#1 RSA encryption of "text" as an even-length hex string
5459 */
5460function RSAEncrypt(text) {
5461 var m = pkcs1pad2(text,(this.n.bitLength()+7)>>3);
5462 if(m == null) return null;
5463 var c = this.doPublic(m);
5464 if(c == null) return null;
5465 var h = c.toString(16);
5466 if((h.length & 1) == 0) return h; else return "0" + h;
5467}
5468
5469// Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string
5470//function RSAEncryptB64(text) {
5471// var h = this.encrypt(text);
5472// if(h) return hex2b64(h); else return null;
5473//}
5474
5475// protected
5476RSAKey.prototype.doPublic = RSADoPublic;
5477
5478// public
5479RSAKey.prototype.setPublic = RSASetPublic;
5480RSAKey.prototype.encrypt = RSAEncrypt;
5481//RSAKey.prototype.encrypt_b64 = RSAEncryptB64;
5482// Depends on rsa.js and jsbn2.js
5483
5484// Version 1.1: support utf-8 decoding in pkcs1unpad2
5485
5486// Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext
5487function pkcs1unpad2(d,n) {
5488 var b = d.toByteArray();
5489 var i = 0;
5490 while(i < b.length && b[i] == 0) ++i;
5491 if(b.length-i != n-1 || b[i] != 2)
5492 return null;
5493 ++i;
5494 while(b[i] != 0)
5495 if(++i >= b.length) return null;
5496 var ret = "";
5497 while(++i < b.length) {
5498 var c = b[i] & 255;
5499 if(c < 128) { // utf-8 decode
5500 ret += String.fromCharCode(c);
5501 }
5502 else if((c > 191) && (c < 224)) {
5503 ret += String.fromCharCode(((c & 31) << 6) | (b[i+1] & 63));
5504 ++i;
5505 }
5506 else {
5507 ret += String.fromCharCode(((c & 15) << 12) | ((b[i+1] & 63) << 6) | (b[i+2] & 63));
5508 i += 2;
5509 }
5510 }
5511 return ret;
5512}
5513
5514// Set the private key fields N, e, and d from hex strings
5515function RSASetPrivate(N,E,D) {
5516 if(N != null && E != null && N.length > 0 && E.length > 0) {
5517 this.n = parseBigInt(N,16);
5518 this.e = parseInt(E,16);
5519 this.d = parseBigInt(D,16);
5520 }
5521 else
5522 alert("Invalid RSA private key");
5523}
5524
5525// Set the private key fields N, e, d and CRT params from hex strings
5526function RSASetPrivateEx(N,E,D,P,Q,DP,DQ,C) {
5527 if(N != null && E != null && N.length > 0 && E.length > 0) {
5528 this.n = parseBigInt(N,16);
5529 this.e = parseInt(E,16);
5530 this.d = parseBigInt(D,16);
5531 this.p = parseBigInt(P,16);
5532 this.q = parseBigInt(Q,16);
5533 this.dmp1 = parseBigInt(DP,16);
5534 this.dmq1 = parseBigInt(DQ,16);
5535 this.coeff = parseBigInt(C,16);
5536 }
5537 else
5538 alert("Invalid RSA private key");
5539}
5540
5541/**
5542 * Generate a new random private key B bits long, using public expt E
5543 */
5544function RSAGenerate(B,E) {
5545 var rng = new SecureRandom();
5546 var qs = B>>1;
5547 this.e = parseInt(E,16);
5548 var ee = new BigInteger(E,16);
5549 for(;;) {
5550 for(;;) {
5551 this.p = new BigInteger(B-qs,1,rng);
5552 if(this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.p.isProbablePrime(10)) break;
5553 }
5554 for(;;) {
5555 this.q = new BigInteger(qs,1,rng);
5556 if(this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.q.isProbablePrime(10)) break;
5557 }
5558 if(this.p.compareTo(this.q) <= 0) {
5559 var t = this.p;
5560 this.p = this.q;
5561 this.q = t;
5562 }
5563 var p1 = this.p.subtract(BigInteger.ONE); // p1 = p - 1
5564 var q1 = this.q.subtract(BigInteger.ONE); // q1 = q - 1
5565 var phi = p1.multiply(q1);
5566 if(phi.gcd(ee).compareTo(BigInteger.ONE) == 0) {
5567 this.n = this.p.multiply(this.q); // this.n = p * q
5568 this.d = ee.modInverse(phi); // this.d =
5569 this.dmp1 = this.d.mod(p1); // this.dmp1 = d mod (p - 1)
5570 this.dmq1 = this.d.mod(q1); // this.dmq1 = d mod (q - 1)
5571 this.coeff = this.q.modInverse(this.p); // this.coeff = (q ^ -1) mod p
5572 break;
5573 }
5574 }
5575}
5576
5577/**
5578 * Perform raw private operation on "x": return x^d (mod n)
5579 * @return x^d (mod n)
5580 */
5581function RSADoPrivate(x) {
5582 if(this.p == null || this.q == null)
5583 return x.modPow(this.d, this.n);
5584
5585 // TODO: re-calculate any missing CRT params
5586 var xp = x.mod(this.p).modPow(this.dmp1, this.p); // xp=cp?
5587 var xq = x.mod(this.q).modPow(this.dmq1, this.q); // xq=cq?
5588
5589 while(xp.compareTo(xq) < 0)
5590 xp = xp.add(this.p);
5591 // NOTE:
5592 // xp.subtract(xq) => cp -cq
5593 // xp.subtract(xq).multiply(this.coeff).mod(this.p) => (cp - cq) * u mod p = h
5594 // xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq) => cq + (h * q) = M
5595 return xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq);
5596}
5597
5598// Return the PKCS#1 RSA decryption of "ctext".
5599// "ctext" is an even-length hex string and the output is a plain string.
5600function RSADecrypt(ctext) {
5601 var c = parseBigInt(ctext, 16);
5602 var m = this.doPrivate(c);
5603 if(m == null) return null;
5604 return pkcs1unpad2(m, (this.n.bitLength()+7)>>3);
5605}
5606
5607// Return the PKCS#1 RSA decryption of "ctext".
5608// "ctext" is a Base64-encoded string and the output is a plain string.
5609//function RSAB64Decrypt(ctext) {
5610// var h = b64tohex(ctext);
5611// if(h) return this.decrypt(h); else return null;
5612//}
5613
5614// protected
5615RSAKey.prototype.doPrivate = RSADoPrivate;
5616
5617// public
5618RSAKey.prototype.setPrivate = RSASetPrivate;
5619RSAKey.prototype.setPrivateEx = RSASetPrivateEx;
5620RSAKey.prototype.generate = RSAGenerate;
5621RSAKey.prototype.decrypt = RSADecrypt;
5622//RSAKey.prototype.b64_decrypt = RSAB64Decrypt;
5623/*! rsapem-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
5624 */
5625//
5626// rsa-pem.js - adding function for reading/writing PKCS#1 PEM private key
5627// to RSAKey class.
5628//
5629// version: 1.1 (2012-May-10)
5630//
5631// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
5632//
5633// This software is licensed under the terms of the MIT License.
5634// http://kjur.github.com/jsrsasign/license/
5635//
5636// The above copyright and license notice shall be
5637// included in all copies or substantial portions of the Software.
5638//
5639//
5640// Depends on:
5641//
5642//
5643//
5644// _RSApem_pemToBase64(sPEM)
5645//
5646// removing PEM header, PEM footer and space characters including
5647// new lines from PEM formatted RSA private key string.
5648//
5649
5650function _rsapem_pemToBase64(sPEMPrivateKey) {
5651 var s = sPEMPrivateKey;
5652 s = s.replace("-----BEGIN RSA PRIVATE KEY-----", "");
5653 s = s.replace("-----END RSA PRIVATE KEY-----", "");
5654 s = s.replace(/[ \n]+/g, "");
5655 return s;
5656}
5657
5658function _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey) {
5659 var a = new Array();
5660 var v1 = ASN1HEX.getStartPosOfV_AtObj(hPrivateKey, 0);
5661 var n1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, v1);
5662 var e1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, n1);
5663 var d1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, e1);
5664 var p1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, d1);
5665 var q1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, p1);
5666 var dp1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, q1);
5667 var dq1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dp1);
5668 var co1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dq1);
5669 a.push(v1, n1, e1, d1, p1, q1, dp1, dq1, co1);
5670 return a;
5671}
5672
5673function _rsapem_getHexValueArrayOfChildrenFromHex(hPrivateKey) {
5674 var posArray = _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey);
5675 var v = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[0]);
5676 var n = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[1]);
5677 var e = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[2]);
5678 var d = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[3]);
5679 var p = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[4]);
5680 var q = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[5]);
5681 var dp = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[6]);
5682 var dq = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[7]);
5683 var co = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[8]);
5684 var a = new Array();
5685 a.push(v, n, e, d, p, q, dp, dq, co);
5686 return a;
5687}
5688
5689/**
5690 * read PKCS#1 private key from a string
5691 * @name readPrivateKeyFromPEMString
5692 * @memberOf RSAKey#
5693 * @function
5694 * @param {String} keyPEM string of PKCS#1 private key.
5695 */
5696function _rsapem_readPrivateKeyFromPEMString(keyPEM) {
5697 var keyB64 = _rsapem_pemToBase64(keyPEM);
5698 var keyHex = b64tohex(keyB64) // depends base64.js
5699 var a = _rsapem_getHexValueArrayOfChildrenFromHex(keyHex);
5700 this.setPrivateEx(a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]);
5701}
5702
5703RSAKey.prototype.readPrivateKeyFromPEMString = _rsapem_readPrivateKeyFromPEMString;
5704/*! rsasign-1.2.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
5705 */
5706//
5707// rsa-sign.js - adding signing functions to RSAKey class.
5708//
5709//
5710// version: 1.2.1 (08 May 2012)
5711//
5712// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
5713//
5714// This software is licensed under the terms of the MIT License.
5715// http://kjur.github.com/jsrsasign/license/
5716//
5717// The above copyright and license notice shall be
5718// included in all copies or substantial portions of the Software.
5719
5720//
5721// Depends on:
5722// function sha1.hex(s) of sha1.js
5723// jsbn.js
5724// jsbn2.js
5725// rsa.js
5726// rsa2.js
5727//
5728
5729// keysize / pmstrlen
5730// 512 / 128
5731// 1024 / 256
5732// 2048 / 512
5733// 4096 / 1024
5734
5735/**
5736 * @property {Dictionary} _RSASIGN_DIHEAD
5737 * @description Array of head part of hexadecimal DigestInfo value for hash algorithms.
5738 * You can add any DigestInfo hash algorith for signing.
5739 * See PKCS#1 v2.1 spec (p38).
5740 */
5741var _RSASIGN_DIHEAD = [];
5742_RSASIGN_DIHEAD['sha1'] = "3021300906052b0e03021a05000414";
5743_RSASIGN_DIHEAD['sha256'] = "3031300d060960864801650304020105000420";
5744_RSASIGN_DIHEAD['sha384'] = "3041300d060960864801650304020205000430";
5745_RSASIGN_DIHEAD['sha512'] = "3051300d060960864801650304020305000440";
5746_RSASIGN_DIHEAD['md2'] = "3020300c06082a864886f70d020205000410";
5747_RSASIGN_DIHEAD['md5'] = "3020300c06082a864886f70d020505000410";
5748_RSASIGN_DIHEAD['ripemd160'] = "3021300906052b2403020105000414";
5749
5750/**
5751 * @property {Dictionary} _RSASIGN_HASHHEXFUNC
5752 * @description Array of functions which calculate hash and returns it as hexadecimal.
5753 * You can add any hash algorithm implementations.
5754 */
5755var _RSASIGN_HASHHEXFUNC = [];
5756_RSASIGN_HASHHEXFUNC['sha1'] = function(s){return hex_sha1(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
5757_RSASIGN_HASHHEXFUNC['sha256'] = function(s){return hex_sha256(s);} // http://pajhome.org.uk/crypt/md5/md5.html
5758_RSASIGN_HASHHEXFUNC['sha512'] = function(s){return hex_sha512(s);} // http://pajhome.org.uk/crypt/md5/md5.html
5759_RSASIGN_HASHHEXFUNC['md5'] = function(s){return hex_md5(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
5760_RSASIGN_HASHHEXFUNC['ripemd160'] = function(s){return hex_rmd160(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
5761
5762//@author axelcdv
5763var _RSASIGN_HASHBYTEFUNC = [];
5764_RSASIGN_HASHBYTEFUNC['sha256'] = function(byteArray){return hex_sha256_from_bytes(byteArray);};
5765
5766//_RSASIGN_HASHHEXFUNC['sha1'] = function(s){return sha1.hex(s);} // http://user1.matsumoto.ne.jp/~goma/js/hash.html
5767//_RSASIGN_HASHHEXFUNC['sha256'] = function(s){return sha256.hex;} // http://user1.matsumoto.ne.jp/~goma/js/hash.html
5768
5769var _RE_HEXDECONLY = new RegExp("");
5770_RE_HEXDECONLY.compile("[^0-9a-f]", "gi");
5771
5772// ========================================================================
5773// Signature Generation
5774// ========================================================================
5775
5776function _rsasign_getHexPaddedDigestInfoForString(s, keySize, hashAlg) {
5777 var pmStrLen = keySize / 4;
5778 var hashFunc = _RSASIGN_HASHHEXFUNC[hashAlg];
5779 var sHashHex = hashFunc(s);
5780
5781 var sHead = "0001";
5782 var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex;
5783 var sMid = "";
5784 var fLen = pmStrLen - sHead.length - sTail.length;
5785 for (var i = 0; i < fLen; i += 2) {
5786 sMid += "ff";
5787 }
5788 sPaddedMessageHex = sHead + sMid + sTail;
5789 return sPaddedMessageHex;
5790}
5791
5792
5793//@author: Meki Cheraoui
5794function _rsasign_getHexPaddedDigestInfoForStringHEX(s, keySize, hashAlg) {
5795 var pmStrLen = keySize / 4;
5796 var hashFunc = _RSASIGN_HASHHEXFUNC[hashAlg];
5797 var sHashHex = hashFunc(s);
5798
5799 var sHead = "0001";
5800 var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex;
5801 var sMid = "";
5802 var fLen = pmStrLen - sHead.length - sTail.length;
5803 for (var i = 0; i < fLen; i += 2) {
5804 sMid += "ff";
5805 }
5806 sPaddedMessageHex = sHead + sMid + sTail;
5807 return sPaddedMessageHex;
5808}
5809
5810/**
5811 * Apply padding, then computes the hash of the given byte array, according to the key size and with the hash algorithm
5812 * @param byteArray (byte[])
5813 * @param keySize (int)
5814 * @param hashAlg the hash algorithm to apply (string)
5815 * @return the hash of byteArray
5816 */
5817function _rsasign_getHexPaddedDigestInfoForByteArray(byteArray, keySize, hashAlg){
5818 var pmStrLen = keySize / 4;
5819 var hashFunc = _RSASIGN_HASHBYTEFUNC[hashAlg];
5820 var sHashHex = hashFunc(byteArray); //returns hex hash
5821
5822 var sHead = "0001";
5823 var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex;
5824 var sMid = "";
5825 var fLen = pmStrLen - sHead.length - sTail.length;
5826 for (var i = 0; i < fLen; i += 2) {
5827 sMid += "ff";
5828 }
5829 sPaddedMessageHex = sHead + sMid + sTail;
5830 return sPaddedMessageHex;
5831}
5832
5833function _zeroPaddingOfSignature(hex, bitLength) {
5834 var s = "";
5835 var nZero = bitLength / 4 - hex.length;
5836 for (var i = 0; i < nZero; i++) {
5837 s = s + "0";
5838 }
5839 return s + hex;
5840}
5841
5842/**
5843 * sign for a message string with RSA private key.<br/>
5844 * @name signString
5845 * @memberOf RSAKey#
5846 * @function
5847 * @param {String} s message string to be signed.
5848 * @param {String} hashAlg hash algorithm name for signing.<br/>
5849 * @return returns hexadecimal string of signature value.
5850 */
5851function _rsasign_signString(s, hashAlg) {
5852 //alert("this.n.bitLength() = " + this.n.bitLength());
5853 var hPM = _rsasign_getHexPaddedDigestInfoForString(s, this.n.bitLength(), hashAlg);
5854 var biPaddedMessage = parseBigInt(hPM, 16);
5855 var biSign = this.doPrivate(biPaddedMessage);
5856 var hexSign = biSign.toString(16);
5857 return _zeroPaddingOfSignature(hexSign, this.n.bitLength());
5858}
5859
5860//@author: ucla-cs
5861function _rsasign_signStringHEX(s, hashAlg) {
5862 //alert("this.n.bitLength() = " + this.n.bitLength());
5863 var hPM = _rsasign_getHexPaddedDigestInfoForString(s, this.n.bitLength(), hashAlg);
5864 var biPaddedMessage = parseBigInt(hPM, 16);
5865 var biSign = this.doPrivate(biPaddedMessage);
5866 var hexSign = biSign.toString(16);
5867 return _zeroPaddingOfSignature(hexSign, this.n.bitLength());
5868}
5869
5870
5871/**
5872 * Sign a message byteArray with an RSA private key
5873 * @name signByteArray
5874 * @memberOf RSAKey#
5875 * @function
5876 * @param {byte[]} byteArray
5877 * @param {Sring} hashAlg the hash algorithm to apply
5878 * @param {RSAKey} rsa key to sign with: hack because the context is lost here
5879 * @return hexadecimal string of signature value
5880 */
5881function _rsasign_signByteArray(byteArray, hashAlg, rsaKey) {
5882 var hPM = _rsasign_getHexPaddedDigestInfoForByteArray(byteArray, rsaKey.n.bitLength(), hashAlg); ///hack because the context is lost here
5883 var biPaddedMessage = parseBigInt(hPM, 16);
5884 var biSign = rsaKey.doPrivate(biPaddedMessage); //hack because the context is lost here
5885 var hexSign = biSign.toString(16);
5886 return _zeroPaddingOfSignature(hexSign, rsaKey.n.bitLength()); //hack because the context is lost here
5887}
5888
5889/**
5890 * Sign a byte array with the Sha-256 algorithm
5891 * @param {byte[]} byteArray
5892 * @return hexadecimal string of signature value
5893 */
5894function _rsasign_signByteArrayWithSHA256(byteArray){
5895 return _rsasign_signByteArray(byteArray, 'sha256', this); //Hack because the context is lost in the next function
5896}
5897
5898
5899function _rsasign_signStringWithSHA1(s) {
5900 return _rsasign_signString(s, 'sha1');
5901}
5902
5903function _rsasign_signStringWithSHA256(s) {
5904 return _rsasign_signString(s, 'sha256');
5905}
5906
5907// ========================================================================
5908// Signature Verification
5909// ========================================================================
5910
5911function _rsasign_getDecryptSignatureBI(biSig, hN, hE) {
5912 var rsa = new RSAKey();
5913 rsa.setPublic(hN, hE);
5914 var biDecryptedSig = rsa.doPublic(biSig);
5915 return biDecryptedSig;
5916}
5917
5918function _rsasign_getHexDigestInfoFromSig(biSig, hN, hE) {
5919 var biDecryptedSig = _rsasign_getDecryptSignatureBI(biSig, hN, hE);
5920 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
5921 return hDigestInfo;
5922}
5923
5924function _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo) {
5925 for (var algName in _RSASIGN_DIHEAD) {
5926 var head = _RSASIGN_DIHEAD[algName];
5927 var len = head.length;
5928 if (hDigestInfo.substring(0, len) == head) {
5929 var a = [algName, hDigestInfo.substring(len)];
5930 return a;
5931 }
5932 }
5933 return [];
5934}
5935
5936function _rsasign_verifySignatureWithArgs(sMsg, biSig, hN, hE) {
5937 var hDigestInfo = _rsasign_getHexDigestInfoFromSig(biSig, hN, hE);
5938 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
5939 if (digestInfoAry.length == 0) return false;
5940 var algName = digestInfoAry[0];
5941 var diHashValue = digestInfoAry[1];
5942 var ff = _RSASIGN_HASHHEXFUNC[algName];
5943 var msgHashValue = ff(sMsg);
5944 return (diHashValue == msgHashValue);
5945}
5946
5947function _rsasign_verifyHexSignatureForMessage(hSig, sMsg) {
5948 var biSig = parseBigInt(hSig, 16);
5949 var result = _rsasign_verifySignatureWithArgs(sMsg, biSig,
5950 this.n.toString(16),
5951 this.e.toString(16));
5952 return result;
5953}
5954
5955/**
5956 * verifies a sigature for a message string with RSA public key.<br/>
5957 * @name verifyString
5958 * @memberOf RSAKey#
5959 * @function
5960 * @param {String} sMsg message string to be verified.
5961 * @param {String} hSig hexadecimal string of siganture.<br/>
5962 * non-hexadecimal charactors including new lines will be ignored.
5963 * @return returns 1 if valid, otherwise 0
5964 */
5965function _rsasign_verifyString(sMsg, hSig) {
5966 hSig = hSig.replace(_RE_HEXDECONLY, '');
5967
5968 if(LOG>3)console.log('n is '+this.n);
5969 if(LOG>3)console.log('e is '+this.e);
5970
5971 if (hSig.length != this.n.bitLength() / 4) return 0;
5972 hSig = hSig.replace(/[ \n]+/g, "");
5973 var biSig = parseBigInt(hSig, 16);
5974 var biDecryptedSig = this.doPublic(biSig);
5975 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
5976 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
5977
5978 if (digestInfoAry.length == 0) return false;
5979 var algName = digestInfoAry[0];
5980 var diHashValue = digestInfoAry[1];
5981 var ff = _RSASIGN_HASHHEXFUNC[algName];
5982 var msgHashValue = ff(sMsg);
5983 return (diHashValue == msgHashValue);
5984}
5985
5986/**
5987 * verifies a sigature for a message byte array with RSA public key.<br/>
5988 * @name verifyByteArray
5989 * @memberOf RSAKey#
5990 * @function
5991 * @param {byte[]} byteArray message byte array to be verified.
5992 * @param {String} hSig hexadecimal string of signature.<br/>
5993 * non-hexadecimal charactors including new lines will be ignored.
5994 * @return returns 1 if valid, otherwise 0
5995 */
5996function _rsasign_verifyByteArray(byteArray, hSig) {
5997 hSig = hSig.replace(_RE_HEXDECONLY, '');
5998
5999 if(LOG>3)console.log('n is '+this.n);
6000 if(LOG>3)console.log('e is '+this.e);
6001
6002 if (hSig.length != this.n.bitLength() / 4) return 0;
6003 hSig = hSig.replace(/[ \n]+/g, "");
6004 var biSig = parseBigInt(hSig, 16);
6005 var biDecryptedSig = this.doPublic(biSig);
6006 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
6007 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
6008
6009 if (digestInfoAry.length == 0) return false;
6010 var algName = digestInfoAry[0];
6011 var diHashValue = digestInfoAry[1];
6012 var ff = _RSASIGN_HASHBYTEFUNC[algName];
6013 var msgHashValue = ff(byteArray);
6014 return (diHashValue == msgHashValue);
6015}
6016
6017RSAKey.prototype.signString = _rsasign_signString;
6018
6019RSAKey.prototype.signByteArray = _rsasign_signByteArray; //@author axelcdv
6020RSAKey.prototype.signByteArrayWithSHA256 = _rsasign_signByteArrayWithSHA256; //@author axelcdv
6021
6022RSAKey.prototype.signStringWithSHA1 = _rsasign_signStringWithSHA1;
6023RSAKey.prototype.signStringWithSHA256 = _rsasign_signStringWithSHA256;
6024RSAKey.prototype.sign = _rsasign_signString;
6025RSAKey.prototype.signWithSHA1 = _rsasign_signStringWithSHA1;
6026RSAKey.prototype.signWithSHA256 = _rsasign_signStringWithSHA256;
6027
6028
6029/*RSAKey.prototype.signStringHEX = _rsasign_signStringHEX;
6030RSAKey.prototype.signStringWithSHA1HEX = _rsasign_signStringWithSHA1HEX;
6031RSAKey.prototype.signStringWithSHA256HEX = _rsasign_signStringWithSHA256HEX;
6032RSAKey.prototype.signHEX = _rsasign_signStringHEX;
6033RSAKey.prototype.signWithSHA1HEX = _rsasign_signStringWithSHA1HEX;
6034RSAKey.prototype.signWithSHA256HEX = _rsasign_signStringWithSHA256HEX;
6035*/
6036
6037RSAKey.prototype.verifyByteArray = _rsasign_verifyByteArray;
6038RSAKey.prototype.verifyString = _rsasign_verifyString;
6039RSAKey.prototype.verifyHexSignatureForMessage = _rsasign_verifyHexSignatureForMessage;
6040RSAKey.prototype.verify = _rsasign_verifyString;
6041RSAKey.prototype.verifyHexSignatureForByteArrayMessage = _rsasign_verifyHexSignatureForMessage;
6042
6043/*
6044RSAKey.prototype.verifyStringHEX = _rsasign_verifyStringHEX;
6045RSAKey.prototype.verifyHexSignatureForMessageHEX = _rsasign_verifyHexSignatureForMessageHEX;
6046RSAKey.prototype.verifyHEX = _rsasign_verifyStringHEX;
6047RSAKey.prototype.verifyHexSignatureForByteArrayMessageHEX = _rsasign_verifyHexSignatureForMessageHEX;
6048*/
6049
6050
6051/**
6052 * @name RSAKey
6053 * @class
6054 * @description Tom Wu's RSA Key class and extension
6055 */
6056/*! asn1hex-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
6057 */
6058//
6059// asn1hex.js - Hexadecimal represented ASN.1 string library
6060//
6061// version: 1.1 (09-May-2012)
6062//
6063// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
6064//
6065// This software is licensed under the terms of the MIT License.
6066// http://kjur.github.com/jsrsasign/license/
6067//
6068// The above copyright and license notice shall be
6069// included in all copies or substantial portions of the Software.
6070//
6071// Depends on:
6072//
6073
6074// MEMO:
6075// f('3082025b02...', 2) ... 82025b ... 3bytes
6076// f('020100', 2) ... 01 ... 1byte
6077// f('0203001...', 2) ... 03 ... 1byte
6078// f('02818003...', 2) ... 8180 ... 2bytes
6079// f('3080....0000', 2) ... 80 ... -1
6080//
6081// Requirements:
6082// - ASN.1 type octet length MUST be 1.
6083// (i.e. ASN.1 primitives like SET, SEQUENCE, INTEGER, OCTETSTRING ...)
6084// -
6085/**
6086 * get byte length for ASN.1 L(length) bytes
6087 * @name getByteLengthOfL_AtObj
6088 * @memberOf ASN1HEX
6089 * @function
6090 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6091 * @param {Number} pos string index
6092 * @return byte length for ASN.1 L(length) bytes
6093 */
6094function _asnhex_getByteLengthOfL_AtObj(s, pos) {
6095 if (s.substring(pos + 2, pos + 3) != '8') return 1;
6096 var i = parseInt(s.substring(pos + 3, pos + 4));
6097 if (i == 0) return -1; // length octet '80' indefinite length
6098 if (0 < i && i < 10) return i + 1; // including '8?' octet;
6099 return -2; // malformed format
6100}
6101
6102
6103/**
6104 * get hexadecimal string for ASN.1 L(length) bytes
6105 * @name getHexOfL_AtObj
6106 * @memberOf ASN1HEX
6107 * @function
6108 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6109 * @param {Number} pos string index
6110 * @return {String} hexadecimal string for ASN.1 L(length) bytes
6111 */
6112function _asnhex_getHexOfL_AtObj(s, pos) {
6113 var len = _asnhex_getByteLengthOfL_AtObj(s, pos);
6114 if (len < 1) return '';
6115 return s.substring(pos + 2, pos + 2 + len * 2);
6116}
6117
6118//
6119// getting ASN.1 length value at the position 'idx' of
6120// hexa decimal string 's'.
6121//
6122// f('3082025b02...', 0) ... 82025b ... ???
6123// f('020100', 0) ... 01 ... 1
6124// f('0203001...', 0) ... 03 ... 3
6125// f('02818003...', 0) ... 8180 ... 128
6126/**
6127 * get integer value of ASN.1 length for ASN.1 data
6128 * @name getIntOfL_AtObj
6129 * @memberOf ASN1HEX
6130 * @function
6131 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6132 * @param {Number} pos string index
6133 * @return ASN.1 L(length) integer value
6134 */
6135function _asnhex_getIntOfL_AtObj(s, pos) {
6136 var hLength = _asnhex_getHexOfL_AtObj(s, pos);
6137 if (hLength == '') return -1;
6138 var bi;
6139 if (parseInt(hLength.substring(0, 1)) < 8) {
6140 bi = parseBigInt(hLength, 16);
6141 } else {
6142 bi = parseBigInt(hLength.substring(2), 16);
6143 }
6144 return bi.intValue();
6145}
6146
6147/**
6148 * get ASN.1 value starting string position for ASN.1 object refered by index 'idx'.
6149 * @name getStartPosOfV_AtObj
6150 * @memberOf ASN1HEX
6151 * @function
6152 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6153 * @param {Number} pos string index
6154 */
6155function _asnhex_getStartPosOfV_AtObj(s, pos) {
6156 var l_len = _asnhex_getByteLengthOfL_AtObj(s, pos);
6157 if (l_len < 0) return l_len;
6158 return pos + (l_len + 1) * 2;
6159}
6160
6161/**
6162 * get hexadecimal string of ASN.1 V(value)
6163 * @name getHexOfV_AtObj
6164 * @memberOf ASN1HEX
6165 * @function
6166 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6167 * @param {Number} pos string index
6168 * @return {String} hexadecimal string of ASN.1 value.
6169 */
6170function _asnhex_getHexOfV_AtObj(s, pos) {
6171 var pos1 = _asnhex_getStartPosOfV_AtObj(s, pos);
6172 var len = _asnhex_getIntOfL_AtObj(s, pos);
6173 return s.substring(pos1, pos1 + len * 2);
6174}
6175
6176/**
6177 * get hexadecimal string of ASN.1 TLV at
6178 * @name getHexOfTLV_AtObj
6179 * @memberOf ASN1HEX
6180 * @function
6181 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6182 * @param {Number} pos string index
6183 * @return {String} hexadecimal string of ASN.1 TLV.
6184 * @since 1.1
6185 */
6186function _asnhex_getHexOfTLV_AtObj(s, pos) {
6187 var hT = s.substr(pos, 2);
6188 var hL = _asnhex_getHexOfL_AtObj(s, pos);
6189 var hV = _asnhex_getHexOfV_AtObj(s, pos);
6190 return hT + hL + hV;
6191}
6192
6193/**
6194 * get next sibling starting index for ASN.1 object string
6195 * @name getPosOfNextSibling_AtObj
6196 * @memberOf ASN1HEX
6197 * @function
6198 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6199 * @param {Number} pos string index
6200 * @return next sibling starting index for ASN.1 object string
6201 */
6202function _asnhex_getPosOfNextSibling_AtObj(s, pos) {
6203 var pos1 = _asnhex_getStartPosOfV_AtObj(s, pos);
6204 var len = _asnhex_getIntOfL_AtObj(s, pos);
6205 return pos1 + len * 2;
6206}
6207
6208/**
6209 * get array of indexes of child ASN.1 objects
6210 * @name getPosArrayOfChildren_AtObj
6211 * @memberOf ASN1HEX
6212 * @function
6213 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6214 * @param {Number} start string index of ASN.1 object
6215 * @return {Array of Number} array of indexes for childen of ASN.1 objects
6216 */
6217function _asnhex_getPosArrayOfChildren_AtObj(h, pos) {
6218 var a = new Array();
6219 var p0 = _asnhex_getStartPosOfV_AtObj(h, pos);
6220 a.push(p0);
6221
6222 var len = _asnhex_getIntOfL_AtObj(h, pos);
6223 var p = p0;
6224 var k = 0;
6225 while (1) {
6226 var pNext = _asnhex_getPosOfNextSibling_AtObj(h, p);
6227 if (pNext == null || (pNext - p0 >= (len * 2))) break;
6228 if (k >= 200) break;
6229
6230 a.push(pNext);
6231 p = pNext;
6232
6233 k++;
6234 }
6235
6236 return a;
6237}
6238
6239/**
6240 * get string index of nth child object of ASN.1 object refered by h, idx
6241 * @name getNthChildIndex_AtObj
6242 * @memberOf ASN1HEX
6243 * @function
6244 * @param {String} h hexadecimal string of ASN.1 DER encoded data
6245 * @param {Number} idx start string index of ASN.1 object
6246 * @param {Number} nth for child
6247 * @return {Number} string index of nth child.
6248 * @since 1.1
6249 */
6250function _asnhex_getNthChildIndex_AtObj(h, idx, nth) {
6251 var a = _asnhex_getPosArrayOfChildren_AtObj(h, idx);
6252 return a[nth];
6253}
6254
6255// ========== decendant methods ==============================
6256
6257/**
6258 * get string index of nth child object of ASN.1 object refered by h, idx
6259 * @name getDecendantIndexByNthList
6260 * @memberOf ASN1HEX
6261 * @function
6262 * @param {String} h hexadecimal string of ASN.1 DER encoded data
6263 * @param {Number} currentIndex start string index of ASN.1 object
6264 * @param {Array of Number} nthList array list of nth
6265 * @return {Number} string index refered by nthList
6266 * @since 1.1
6267 */
6268function _asnhex_getDecendantIndexByNthList(h, currentIndex, nthList) {
6269 if (nthList.length == 0) {
6270 return currentIndex;
6271 }
6272 var firstNth = nthList.shift();
6273 var a = _asnhex_getPosArrayOfChildren_AtObj(h, currentIndex);
6274 return _asnhex_getDecendantIndexByNthList(h, a[firstNth], nthList);
6275}
6276
6277/**
6278 * get hexadecimal string of ASN.1 TLV refered by current index and nth index list.
6279 * @name getDecendantHexTLVByNthList
6280 * @memberOf ASN1HEX
6281 * @function
6282 * @param {String} h hexadecimal string of ASN.1 DER encoded data
6283 * @param {Number} currentIndex start string index of ASN.1 object
6284 * @param {Array of Number} nthList array list of nth
6285 * @return {Number} hexadecimal string of ASN.1 TLV refered by nthList
6286 * @since 1.1
6287 */
6288function _asnhex_getDecendantHexTLVByNthList(h, currentIndex, nthList) {
6289 var idx = _asnhex_getDecendantIndexByNthList(h, currentIndex, nthList);
6290 return _asnhex_getHexOfTLV_AtObj(h, idx);
6291}
6292
6293/**
6294 * get hexadecimal string of ASN.1 V refered by current index and nth index list.
6295 * @name getDecendantHexVByNthList
6296 * @memberOf ASN1HEX
6297 * @function
6298 * @param {String} h hexadecimal string of ASN.1 DER encoded data
6299 * @param {Number} currentIndex start string index of ASN.1 object
6300 * @param {Array of Number} nthList array list of nth
6301 * @return {Number} hexadecimal string of ASN.1 V refered by nthList
6302 * @since 1.1
6303 */
6304function _asnhex_getDecendantHexVByNthList(h, currentIndex, nthList) {
6305 var idx = _asnhex_getDecendantIndexByNthList(h, currentIndex, nthList);
6306 return _asnhex_getHexOfV_AtObj(h, idx);
6307}
6308
6309// ========== class definition ==============================
6310
6311/**
6312 * ASN.1 DER encoded hexadecimal string utility class
6313 * @class ASN.1 DER encoded hexadecimal string utility class
6314 * @author Kenji Urushima
6315 * @version 1.1 (09 May 2012)
6316 * @see <a href="http://kjur.github.com/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a>
6317 * @since 1.1
6318 */
6319function ASN1HEX() {
6320 return ASN1HEX;
6321}
6322
6323ASN1HEX.getByteLengthOfL_AtObj = _asnhex_getByteLengthOfL_AtObj;
6324ASN1HEX.getHexOfL_AtObj = _asnhex_getHexOfL_AtObj;
6325ASN1HEX.getIntOfL_AtObj = _asnhex_getIntOfL_AtObj;
6326ASN1HEX.getStartPosOfV_AtObj = _asnhex_getStartPosOfV_AtObj;
6327ASN1HEX.getHexOfV_AtObj = _asnhex_getHexOfV_AtObj;
6328ASN1HEX.getHexOfTLV_AtObj = _asnhex_getHexOfTLV_AtObj;
6329ASN1HEX.getPosOfNextSibling_AtObj = _asnhex_getPosOfNextSibling_AtObj;
6330ASN1HEX.getPosArrayOfChildren_AtObj = _asnhex_getPosArrayOfChildren_AtObj;
6331ASN1HEX.getNthChildIndex_AtObj = _asnhex_getNthChildIndex_AtObj;
6332ASN1HEX.getDecendantIndexByNthList = _asnhex_getDecendantIndexByNthList;
6333ASN1HEX.getDecendantHexVByNthList = _asnhex_getDecendantHexVByNthList;
6334ASN1HEX.getDecendantHexTLVByNthList = _asnhex_getDecendantHexTLVByNthList;
Jeff Thompson1a338f82012-12-29 17:07:04 -08006335/*! x509-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
6336 */
6337//
6338// x509.js - X509 class to read subject public key from certificate.
6339//
6340// version: 1.1 (10-May-2012)
6341//
6342// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
6343//
6344// This software is licensed under the terms of the MIT License.
6345// http://kjur.github.com/jsrsasign/license
6346//
6347// The above copyright and license notice shall be
6348// included in all copies or substantial portions of the Software.
6349//
6350
6351// Depends:
6352// base64.js
6353// rsa.js
6354// asn1hex.js
6355
6356function _x509_pemToBase64(sCertPEM) {
6357 var s = sCertPEM;
6358 s = s.replace("-----BEGIN CERTIFICATE-----", "");
6359 s = s.replace("-----END CERTIFICATE-----", "");
6360 s = s.replace(/[ \n]+/g, "");
6361 return s;
6362}
6363
6364function _x509_pemToHex(sCertPEM) {
6365 var b64Cert = _x509_pemToBase64(sCertPEM);
6366 var hCert = b64tohex(b64Cert);
6367 return hCert;
6368}
6369
6370function _x509_getHexTbsCertificateFromCert(hCert) {
6371 var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0);
6372 return pTbsCert;
6373}
6374
6375// NOTE: privateKeyUsagePeriod field of X509v2 not supported.
6376// NOTE: v1 and v3 supported
6377function _x509_getSubjectPublicKeyInfoPosFromCertHex(hCert) {
6378 var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0);
6379 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pTbsCert);
6380 if (a.length < 1) return -1;
6381 if (hCert.substring(a[0], a[0] + 10) == "a003020102") { // v3
6382 if (a.length < 6) return -1;
6383 return a[6];
6384 } else {
6385 if (a.length < 5) return -1;
6386 return a[5];
6387 }
6388}
6389
6390// NOTE: Without BITSTRING encapsulation.
6391// If pInfo is supplied, it is the position in hCert of the SubjectPublicKeyInfo.
6392function _x509_getSubjectPublicKeyPosFromCertHex(hCert, pInfo) {
6393 if (pInfo == null)
6394 pInfo = _x509_getSubjectPublicKeyInfoPosFromCertHex(hCert);
6395 if (pInfo == -1) return -1;
6396 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pInfo);
6397
6398 if (a.length != 2) return -1;
6399 var pBitString = a[1];
6400 if (hCert.substring(pBitString, pBitString + 2) != '03') return -1;
6401 var pBitStringV = ASN1HEX.getStartPosOfV_AtObj(hCert, pBitString);
6402
6403 if (hCert.substring(pBitStringV, pBitStringV + 2) != '00') return -1;
6404 return pBitStringV + 2;
6405}
6406
6407// If p is supplied, it is the public key position in hCert.
6408function _x509_getPublicKeyHexArrayFromCertHex(hCert, p) {
6409 if (p == null)
6410 p = _x509_getSubjectPublicKeyPosFromCertHex(hCert);
6411 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, p);
6412 //var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a[3]);
6413 if(LOG>4){
6414 console.log('a is now');
6415 console.log(a);
6416 }
6417
6418 //if (a.length != 2) return [];
6419 if (a.length < 2) return [];
6420
6421 var hN = ASN1HEX.getHexOfV_AtObj(hCert, a[0]);
6422 var hE = ASN1HEX.getHexOfV_AtObj(hCert, a[1]);
6423 if (hN != null && hE != null) {
6424 return [hN, hE];
6425 } else {
6426 return [];
6427 }
6428}
6429
6430function _x509_getPublicKeyHexArrayFromCertPEM(sCertPEM) {
6431 var hCert = _x509_pemToHex(sCertPEM);
6432 var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
6433 return a;
6434}
6435
6436// ===== get basic fields from hex =====================================
6437/**
6438 * get hexadecimal string of serialNumber field of certificate.<br/>
6439 * @name getSerialNumberHex
6440 * @memberOf X509#
6441 * @function
6442 */
6443function _x509_getSerialNumberHex() {
6444 return ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 1]);
6445}
6446
6447/**
6448 * get hexadecimal string of issuer field of certificate.<br/>
6449 * @name getIssuerHex
6450 * @memberOf X509#
6451 * @function
6452 */
6453function _x509_getIssuerHex() {
6454 return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]);
6455}
6456
6457/**
6458 * get string of issuer field of certificate.<br/>
6459 * @name getIssuerString
6460 * @memberOf X509#
6461 * @function
6462 */
6463function _x509_getIssuerString() {
6464 return _x509_hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]));
6465}
6466
6467/**
6468 * get hexadecimal string of subject field of certificate.<br/>
6469 * @name getSubjectHex
6470 * @memberOf X509#
6471 * @function
6472 */
6473function _x509_getSubjectHex() {
6474 return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]);
6475}
6476
6477/**
6478 * get string of subject field of certificate.<br/>
6479 * @name getSubjectString
6480 * @memberOf X509#
6481 * @function
6482 */
6483function _x509_getSubjectString() {
6484 return _x509_hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]));
6485}
6486
6487/**
6488 * get notBefore field string of certificate.<br/>
6489 * @name getNotBefore
6490 * @memberOf X509#
6491 * @function
6492 */
6493function _x509_getNotBefore() {
6494 var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 0]);
6495 s = s.replace(/(..)/g, "%$1");
6496 s = decodeURIComponent(s);
6497 return s;
6498}
6499
6500/**
6501 * get notAfter field string of certificate.<br/>
6502 * @name getNotAfter
6503 * @memberOf X509#
6504 * @function
6505 */
6506function _x509_getNotAfter() {
6507 var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 1]);
6508 s = s.replace(/(..)/g, "%$1");
6509 s = decodeURIComponent(s);
6510 return s;
6511}
6512
6513// ===== read certificate =====================================
6514
6515_x509_DN_ATTRHEX = {
6516 "0603550406": "C",
6517 "060355040a": "O",
6518 "060355040b": "OU",
6519 "0603550403": "CN",
6520 "0603550405": "SN",
6521 "0603550408": "ST",
6522 "0603550407": "L" };
6523
6524function _x509_hex2dn(hDN) {
6525 var s = "";
6526 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hDN, 0);
6527 for (var i = 0; i < a.length; i++) {
6528 var hRDN = ASN1HEX.getHexOfTLV_AtObj(hDN, a[i]);
6529 s = s + "/" + _x509_hex2rdn(hRDN);
6530 }
6531 return s;
6532}
6533
6534function _x509_hex2rdn(hRDN) {
6535 var hType = ASN1HEX.getDecendantHexTLVByNthList(hRDN, 0, [0, 0]);
6536 var hValue = ASN1HEX.getDecendantHexVByNthList(hRDN, 0, [0, 1]);
6537 var type = "";
6538 try { type = _x509_DN_ATTRHEX[hType]; } catch (ex) { type = hType; }
6539 hValue = hValue.replace(/(..)/g, "%$1");
6540 var value = decodeURIComponent(hValue);
6541 return type + "=" + value;
6542}
6543
6544// ===== read certificate =====================================
6545
6546
6547/**
6548 * read PEM formatted X.509 certificate from string.<br/>
6549 * @name readCertPEM
6550 * @memberOf X509#
6551 * @function
6552 * @param {String} sCertPEM string for PEM formatted X.509 certificate
6553 */
6554function _x509_readCertPEM(sCertPEM) {
6555 var hCert = _x509_pemToHex(sCertPEM);
6556 var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
6557 if(LOG>4){
6558 console.log('HEX VALUE IS ' + hCert);
6559 console.log('type of a' + typeof a);
6560 console.log('a VALUE IS ');
6561 console.log(a);
6562 console.log('a[0] VALUE IS ' + a[0]);
6563 console.log('a[1] VALUE IS ' + a[1]);
6564 }
6565 var rsa = new RSAKey();
6566 rsa.setPublic(a[0], a[1]);
6567 this.subjectPublicKeyRSA = rsa;
6568 this.subjectPublicKeyRSA_hN = a[0];
6569 this.subjectPublicKeyRSA_hE = a[1];
6570 this.hex = hCert;
6571}
6572
6573/**
6574 * read hex formatted X.509 certificate from string.
6575 * @name readCertHex
6576 * @memberOf X509#
6577 * @function
6578 * @param {String} hCert string for hex formatted X.509 certificate
6579 */
6580function _x509_readCertHex(hCert) {
6581 hCert = hCert.toLowerCase();
6582 var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
6583 var rsa = new RSAKey();
6584 rsa.setPublic(a[0], a[1]);
6585 this.subjectPublicKeyRSA = rsa;
6586 this.subjectPublicKeyRSA_hN = a[0];
6587 this.subjectPublicKeyRSA_hE = a[1];
6588 this.hex = hCert;
6589}
6590
6591function _x509_readCertPEMWithoutRSAInit(sCertPEM) {
6592 var hCert = _x509_pemToHex(sCertPEM);
6593 var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
6594 this.subjectPublicKeyRSA.setPublic(a[0], a[1]);
6595 this.subjectPublicKeyRSA_hN = a[0];
6596 this.subjectPublicKeyRSA_hE = a[1];
6597 this.hex = hCert;
6598}
6599
6600/**
6601 * X.509 certificate class.<br/>
6602 * @class X.509 certificate class
6603 * @property {RSAKey} subjectPublicKeyRSA Tom Wu's RSAKey object
6604 * @property {String} subjectPublicKeyRSA_hN hexadecimal string for modulus of RSA public key
6605 * @property {String} subjectPublicKeyRSA_hE hexadecimal string for public exponent of RSA public key
6606 * @property {String} hex hexacedimal string for X.509 certificate.
6607 * @author Kenji Urushima
6608 * @version 1.0.1 (08 May 2012)
6609 * @see <a href="http://kjur.github.com/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a>
6610 */
6611function X509() {
6612 this.subjectPublicKeyRSA = null;
6613 this.subjectPublicKeyRSA_hN = null;
6614 this.subjectPublicKeyRSA_hE = null;
6615 this.hex = null;
6616}
6617
6618X509.prototype.readCertPEM = _x509_readCertPEM;
6619X509.prototype.readCertHex = _x509_readCertHex;
6620X509.prototype.readCertPEMWithoutRSAInit = _x509_readCertPEMWithoutRSAInit;
6621X509.prototype.getSerialNumberHex = _x509_getSerialNumberHex;
6622X509.prototype.getIssuerHex = _x509_getIssuerHex;
6623X509.prototype.getSubjectHex = _x509_getSubjectHex;
6624X509.prototype.getIssuerString = _x509_getIssuerString;
6625X509.prototype.getSubjectString = _x509_getSubjectString;
6626X509.prototype.getNotBefore = _x509_getNotBefore;
6627X509.prototype.getNotAfter = _x509_getNotAfter;
6628
Wentao Shang0e291c82012-12-02 23:36:29 -08006629// Copyright (c) 2005 Tom Wu
6630// All Rights Reserved.
6631// See "LICENSE" for details.
6632
6633// Basic JavaScript BN library - subset useful for RSA encryption.
6634
6635// Bits per digit
6636var dbits;
6637
6638// JavaScript engine analysis
6639var canary = 0xdeadbeefcafe;
6640var j_lm = ((canary&0xffffff)==0xefcafe);
6641
6642// (public) Constructor
6643function BigInteger(a,b,c) {
6644 if(a != null)
6645 if("number" == typeof a) this.fromNumber(a,b,c);
6646 else if(b == null && "string" != typeof a) this.fromString(a,256);
6647 else this.fromString(a,b);
6648}
6649
6650// return new, unset BigInteger
6651function nbi() { return new BigInteger(null); }
6652
6653// am: Compute w_j += (x*this_i), propagate carries,
6654// c is initial carry, returns final carry.
6655// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
6656// We need to select the fastest one that works in this environment.
6657
6658// am1: use a single mult and divide to get the high bits,
6659// max digit bits should be 26 because
6660// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
6661function am1(i,x,w,j,c,n) {
6662 while(--n >= 0) {
6663 var v = x*this[i++]+w[j]+c;
6664 c = Math.floor(v/0x4000000);
6665 w[j++] = v&0x3ffffff;
6666 }
6667 return c;
6668}
6669// am2 avoids a big mult-and-extract completely.
6670// Max digit bits should be <= 30 because we do bitwise ops
6671// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
6672function am2(i,x,w,j,c,n) {
6673 var xl = x&0x7fff, xh = x>>15;
6674 while(--n >= 0) {
6675 var l = this[i]&0x7fff;
6676 var h = this[i++]>>15;
6677 var m = xh*l+h*xl;
6678 l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff);
6679 c = (l>>>30)+(m>>>15)+xh*h+(c>>>30);
6680 w[j++] = l&0x3fffffff;
6681 }
6682 return c;
6683}
6684// Alternately, set max digit bits to 28 since some
6685// browsers slow down when dealing with 32-bit numbers.
6686function am3(i,x,w,j,c,n) {
6687 var xl = x&0x3fff, xh = x>>14;
6688 while(--n >= 0) {
6689 var l = this[i]&0x3fff;
6690 var h = this[i++]>>14;
6691 var m = xh*l+h*xl;
6692 l = xl*l+((m&0x3fff)<<14)+w[j]+c;
6693 c = (l>>28)+(m>>14)+xh*h;
6694 w[j++] = l&0xfffffff;
6695 }
6696 return c;
6697}
6698if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
6699 BigInteger.prototype.am = am2;
6700 dbits = 30;
6701}
6702else if(j_lm && (navigator.appName != "Netscape")) {
6703 BigInteger.prototype.am = am1;
6704 dbits = 26;
6705}
6706else { // Mozilla/Netscape seems to prefer am3
6707 BigInteger.prototype.am = am3;
6708 dbits = 28;
6709}
6710
6711BigInteger.prototype.DB = dbits;
6712BigInteger.prototype.DM = ((1<<dbits)-1);
6713BigInteger.prototype.DV = (1<<dbits);
6714
6715var BI_FP = 52;
6716BigInteger.prototype.FV = Math.pow(2,BI_FP);
6717BigInteger.prototype.F1 = BI_FP-dbits;
6718BigInteger.prototype.F2 = 2*dbits-BI_FP;
6719
6720// Digit conversions
6721var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
6722var BI_RC = new Array();
6723var rr,vv;
6724rr = "0".charCodeAt(0);
6725for(vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
6726rr = "a".charCodeAt(0);
6727for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
6728rr = "A".charCodeAt(0);
6729for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
6730
6731function int2char(n) { return BI_RM.charAt(n); }
6732function intAt(s,i) {
6733 var c = BI_RC[s.charCodeAt(i)];
6734 return (c==null)?-1:c;
6735}
6736
6737// (protected) copy this to r
6738function bnpCopyTo(r) {
6739 for(var i = this.t-1; i >= 0; --i) r[i] = this[i];
6740 r.t = this.t;
6741 r.s = this.s;
6742}
6743
6744// (protected) set from integer value x, -DV <= x < DV
6745function bnpFromInt(x) {
6746 this.t = 1;
6747 this.s = (x<0)?-1:0;
6748 if(x > 0) this[0] = x;
6749 else if(x < -1) this[0] = x+DV;
6750 else this.t = 0;
6751}
6752
6753// return bigint initialized to value
6754function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
6755
6756// (protected) set from string and radix
6757function bnpFromString(s,b) {
6758 var k;
6759 if(b == 16) k = 4;
6760 else if(b == 8) k = 3;
6761 else if(b == 256) k = 8; // byte array
6762 else if(b == 2) k = 1;
6763 else if(b == 32) k = 5;
6764 else if(b == 4) k = 2;
6765 else { this.fromRadix(s,b); return; }
6766 this.t = 0;
6767 this.s = 0;
6768 var i = s.length, mi = false, sh = 0;
6769 while(--i >= 0) {
6770 var x = (k==8)?s[i]&0xff:intAt(s,i);
6771 if(x < 0) {
6772 if(s.charAt(i) == "-") mi = true;
6773 continue;
6774 }
6775 mi = false;
6776 if(sh == 0)
6777 this[this.t++] = x;
6778 else if(sh+k > this.DB) {
6779 this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<<sh;
6780 this[this.t++] = (x>>(this.DB-sh));
6781 }
6782 else
6783 this[this.t-1] |= x<<sh;
6784 sh += k;
6785 if(sh >= this.DB) sh -= this.DB;
6786 }
6787 if(k == 8 && (s[0]&0x80) != 0) {
6788 this.s = -1;
6789 if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh;
6790 }
6791 this.clamp();
6792 if(mi) BigInteger.ZERO.subTo(this,this);
6793}
6794
6795// (protected) clamp off excess high words
6796function bnpClamp() {
6797 var c = this.s&this.DM;
6798 while(this.t > 0 && this[this.t-1] == c) --this.t;
6799}
6800
6801// (public) return string representation in given radix
6802function bnToString(b) {
6803 if(this.s < 0) return "-"+this.negate().toString(b);
6804 var k;
6805 if(b == 16) k = 4;
6806 else if(b == 8) k = 3;
6807 else if(b == 2) k = 1;
6808 else if(b == 32) k = 5;
6809 else if(b == 4) k = 2;
6810 else return this.toRadix(b);
6811 var km = (1<<k)-1, d, m = false, r = "", i = this.t;
6812 var p = this.DB-(i*this.DB)%k;
6813 if(i-- > 0) {
6814 if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); }
6815 while(i >= 0) {
6816 if(p < k) {
6817 d = (this[i]&((1<<p)-1))<<(k-p);
6818 d |= this[--i]>>(p+=this.DB-k);
6819 }
6820 else {
6821 d = (this[i]>>(p-=k))&km;
6822 if(p <= 0) { p += this.DB; --i; }
6823 }
6824 if(d > 0) m = true;
6825 if(m) r += int2char(d);
6826 }
6827 }
6828 return m?r:"0";
6829}
6830
6831// (public) -this
6832function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }
6833
6834// (public) |this|
6835function bnAbs() { return (this.s<0)?this.negate():this; }
6836
6837// (public) return + if this > a, - if this < a, 0 if equal
6838function bnCompareTo(a) {
6839 var r = this.s-a.s;
6840 if(r != 0) return r;
6841 var i = this.t;
6842 r = i-a.t;
6843 if(r != 0) return r;
6844 while(--i >= 0) if((r=this[i]-a[i]) != 0) return r;
6845 return 0;
6846}
6847
6848// returns bit length of the integer x
6849function nbits(x) {
6850 var r = 1, t;
6851 if((t=x>>>16) != 0) { x = t; r += 16; }
6852 if((t=x>>8) != 0) { x = t; r += 8; }
6853 if((t=x>>4) != 0) { x = t; r += 4; }
6854 if((t=x>>2) != 0) { x = t; r += 2; }
6855 if((t=x>>1) != 0) { x = t; r += 1; }
6856 return r;
6857}
6858
6859// (public) return the number of bits in "this"
6860function bnBitLength() {
6861 if(this.t <= 0) return 0;
6862 return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM));
6863}
6864
6865// (protected) r = this << n*DB
6866function bnpDLShiftTo(n,r) {
6867 var i;
6868 for(i = this.t-1; i >= 0; --i) r[i+n] = this[i];
6869 for(i = n-1; i >= 0; --i) r[i] = 0;
6870 r.t = this.t+n;
6871 r.s = this.s;
6872}
6873
6874// (protected) r = this >> n*DB
6875function bnpDRShiftTo(n,r) {
6876 for(var i = n; i < this.t; ++i) r[i-n] = this[i];
6877 r.t = Math.max(this.t-n,0);
6878 r.s = this.s;
6879}
6880
6881// (protected) r = this << n
6882function bnpLShiftTo(n,r) {
6883 var bs = n%this.DB;
6884 var cbs = this.DB-bs;
6885 var bm = (1<<cbs)-1;
6886 var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i;
6887 for(i = this.t-1; i >= 0; --i) {
6888 r[i+ds+1] = (this[i]>>cbs)|c;
6889 c = (this[i]&bm)<<bs;
6890 }
6891 for(i = ds-1; i >= 0; --i) r[i] = 0;
6892 r[ds] = c;
6893 r.t = this.t+ds+1;
6894 r.s = this.s;
6895 r.clamp();
6896}
6897
6898// (protected) r = this >> n
6899function bnpRShiftTo(n,r) {
6900 r.s = this.s;
6901 var ds = Math.floor(n/this.DB);
6902 if(ds >= this.t) { r.t = 0; return; }
6903 var bs = n%this.DB;
6904 var cbs = this.DB-bs;
6905 var bm = (1<<bs)-1;
6906 r[0] = this[ds]>>bs;
6907 for(var i = ds+1; i < this.t; ++i) {
6908 r[i-ds-1] |= (this[i]&bm)<<cbs;
6909 r[i-ds] = this[i]>>bs;
6910 }
6911 if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs;
6912 r.t = this.t-ds;
6913 r.clamp();
6914}
6915
6916// (protected) r = this - a
6917function bnpSubTo(a,r) {
6918 var i = 0, c = 0, m = Math.min(a.t,this.t);
6919 while(i < m) {
6920 c += this[i]-a[i];
6921 r[i++] = c&this.DM;
6922 c >>= this.DB;
6923 }
6924 if(a.t < this.t) {
6925 c -= a.s;
6926 while(i < this.t) {
6927 c += this[i];
6928 r[i++] = c&this.DM;
6929 c >>= this.DB;
6930 }
6931 c += this.s;
6932 }
6933 else {
6934 c += this.s;
6935 while(i < a.t) {
6936 c -= a[i];
6937 r[i++] = c&this.DM;
6938 c >>= this.DB;
6939 }
6940 c -= a.s;
6941 }
6942 r.s = (c<0)?-1:0;
6943 if(c < -1) r[i++] = this.DV+c;
6944 else if(c > 0) r[i++] = c;
6945 r.t = i;
6946 r.clamp();
6947}
6948
6949// (protected) r = this * a, r != this,a (HAC 14.12)
6950// "this" should be the larger one if appropriate.
6951function bnpMultiplyTo(a,r) {
6952 var x = this.abs(), y = a.abs();
6953 var i = x.t;
6954 r.t = i+y.t;
6955 while(--i >= 0) r[i] = 0;
6956 for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t);
6957 r.s = 0;
6958 r.clamp();
6959 if(this.s != a.s) BigInteger.ZERO.subTo(r,r);
6960}
6961
6962// (protected) r = this^2, r != this (HAC 14.16)
6963function bnpSquareTo(r) {
6964 var x = this.abs();
6965 var i = r.t = 2*x.t;
6966 while(--i >= 0) r[i] = 0;
6967 for(i = 0; i < x.t-1; ++i) {
6968 var c = x.am(i,x[i],r,2*i,0,1);
6969 if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) {
6970 r[i+x.t] -= x.DV;
6971 r[i+x.t+1] = 1;
6972 }
6973 }
6974 if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1);
6975 r.s = 0;
6976 r.clamp();
6977}
6978
6979// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
6980// r != q, this != m. q or r may be null.
6981function bnpDivRemTo(m,q,r) {
6982 var pm = m.abs();
6983 if(pm.t <= 0) return;
6984 var pt = this.abs();
6985 if(pt.t < pm.t) {
6986 if(q != null) q.fromInt(0);
6987 if(r != null) this.copyTo(r);
6988 return;
6989 }
6990 if(r == null) r = nbi();
6991 var y = nbi(), ts = this.s, ms = m.s;
6992 var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus
6993 if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); }
6994 else { pm.copyTo(y); pt.copyTo(r); }
6995 var ys = y.t;
6996 var y0 = y[ys-1];
6997 if(y0 == 0) return;
6998 var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0);
6999 var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
7000 var i = r.t, j = i-ys, t = (q==null)?nbi():q;
7001 y.dlShiftTo(j,t);
7002 if(r.compareTo(t) >= 0) {
7003 r[r.t++] = 1;
7004 r.subTo(t,r);
7005 }
7006 BigInteger.ONE.dlShiftTo(ys,t);
7007 t.subTo(y,y); // "negative" y so we can replace sub with am later
7008 while(y.t < ys) y[y.t++] = 0;
7009 while(--j >= 0) {
7010 // Estimate quotient digit
7011 var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);
7012 if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out
7013 y.dlShiftTo(j,t);
7014 r.subTo(t,r);
7015 while(r[i] < --qd) r.subTo(t,r);
7016 }
7017 }
7018 if(q != null) {
7019 r.drShiftTo(ys,q);
7020 if(ts != ms) BigInteger.ZERO.subTo(q,q);
7021 }
7022 r.t = ys;
7023 r.clamp();
7024 if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder
7025 if(ts < 0) BigInteger.ZERO.subTo(r,r);
7026}
7027
7028// (public) this mod a
7029function bnMod(a) {
7030 var r = nbi();
7031 this.abs().divRemTo(a,null,r);
7032 if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r);
7033 return r;
7034}
7035
7036// Modular reduction using "classic" algorithm
7037function Classic(m) { this.m = m; }
7038function cConvert(x) {
7039 if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
7040 else return x;
7041}
7042function cRevert(x) { return x; }
7043function cReduce(x) { x.divRemTo(this.m,null,x); }
7044function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
7045function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
7046
7047Classic.prototype.convert = cConvert;
7048Classic.prototype.revert = cRevert;
7049Classic.prototype.reduce = cReduce;
7050Classic.prototype.mulTo = cMulTo;
7051Classic.prototype.sqrTo = cSqrTo;
7052
7053// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
7054// justification:
7055// xy == 1 (mod m)
7056// xy = 1+km
7057// xy(2-xy) = (1+km)(1-km)
7058// x[y(2-xy)] = 1-k^2m^2
7059// x[y(2-xy)] == 1 (mod m^2)
7060// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
7061// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
7062// JS multiply "overflows" differently from C/C++, so care is needed here.
7063function bnpInvDigit() {
7064 if(this.t < 1) return 0;
7065 var x = this[0];
7066 if((x&1) == 0) return 0;
7067 var y = x&3; // y == 1/x mod 2^2
7068 y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4
7069 y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8
7070 y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16
7071 // last step - calculate inverse mod DV directly;
7072 // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
7073 y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits
7074 // we really want the negative inverse, and -DV < y < DV
7075 return (y>0)?this.DV-y:-y;
7076}
7077
7078// Montgomery reduction
7079function Montgomery(m) {
7080 this.m = m;
7081 this.mp = m.invDigit();
7082 this.mpl = this.mp&0x7fff;
7083 this.mph = this.mp>>15;
7084 this.um = (1<<(m.DB-15))-1;
7085 this.mt2 = 2*m.t;
7086}
7087
7088// xR mod m
7089function montConvert(x) {
7090 var r = nbi();
7091 x.abs().dlShiftTo(this.m.t,r);
7092 r.divRemTo(this.m,null,r);
7093 if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r);
7094 return r;
7095}
7096
7097// x/R mod m
7098function montRevert(x) {
7099 var r = nbi();
7100 x.copyTo(r);
7101 this.reduce(r);
7102 return r;
7103}
7104
7105// x = x/R mod m (HAC 14.32)
7106function montReduce(x) {
7107 while(x.t <= this.mt2) // pad x so am has enough room later
7108 x[x.t++] = 0;
7109 for(var i = 0; i < this.m.t; ++i) {
7110 // faster way of calculating u0 = x[i]*mp mod DV
7111 var j = x[i]&0x7fff;
7112 var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM;
7113 // use am to combine the multiply-shift-add into one call
7114 j = i+this.m.t;
7115 x[j] += this.m.am(0,u0,x,i,0,this.m.t);
7116 // propagate carry
7117 while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; }
7118 }
7119 x.clamp();
7120 x.drShiftTo(this.m.t,x);
7121 if(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
7122}
7123
7124// r = "x^2/R mod m"; x != r
7125function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
7126
7127// r = "xy/R mod m"; x,y != r
7128function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
7129
7130Montgomery.prototype.convert = montConvert;
7131Montgomery.prototype.revert = montRevert;
7132Montgomery.prototype.reduce = montReduce;
7133Montgomery.prototype.mulTo = montMulTo;
7134Montgomery.prototype.sqrTo = montSqrTo;
7135
7136// (protected) true iff this is even
7137function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; }
7138
7139// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
7140function bnpExp(e,z) {
7141 if(e > 0xffffffff || e < 1) return BigInteger.ONE;
7142 var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1;
7143 g.copyTo(r);
7144 while(--i >= 0) {
7145 z.sqrTo(r,r2);
7146 if((e&(1<<i)) > 0) z.mulTo(r2,g,r);
7147 else { var t = r; r = r2; r2 = t; }
7148 }
7149 return z.revert(r);
7150}
7151
7152// (public) this^e % m, 0 <= e < 2^32
7153function bnModPowInt(e,m) {
7154 var z;
7155 if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
7156 return this.exp(e,z);
7157}
7158
7159// protected
7160BigInteger.prototype.copyTo = bnpCopyTo;
7161BigInteger.prototype.fromInt = bnpFromInt;
7162BigInteger.prototype.fromString = bnpFromString;
7163BigInteger.prototype.clamp = bnpClamp;
7164BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
7165BigInteger.prototype.drShiftTo = bnpDRShiftTo;
7166BigInteger.prototype.lShiftTo = bnpLShiftTo;
7167BigInteger.prototype.rShiftTo = bnpRShiftTo;
7168BigInteger.prototype.subTo = bnpSubTo;
7169BigInteger.prototype.multiplyTo = bnpMultiplyTo;
7170BigInteger.prototype.squareTo = bnpSquareTo;
7171BigInteger.prototype.divRemTo = bnpDivRemTo;
7172BigInteger.prototype.invDigit = bnpInvDigit;
7173BigInteger.prototype.isEven = bnpIsEven;
7174BigInteger.prototype.exp = bnpExp;
7175
7176// public
7177BigInteger.prototype.toString = bnToString;
7178BigInteger.prototype.negate = bnNegate;
7179BigInteger.prototype.abs = bnAbs;
7180BigInteger.prototype.compareTo = bnCompareTo;
7181BigInteger.prototype.bitLength = bnBitLength;
7182BigInteger.prototype.mod = bnMod;
7183BigInteger.prototype.modPowInt = bnModPowInt;
7184
7185// "constants"
7186BigInteger.ZERO = nbv(0);
7187BigInteger.ONE = nbv(1);
7188// Copyright (c) 2005-2009 Tom Wu
7189// All Rights Reserved.
7190// See "LICENSE" for details.
7191
7192// Extended JavaScript BN functions, required for RSA private ops.
7193
7194// Version 1.1: new BigInteger("0", 10) returns "proper" zero
7195
7196// (public)
7197function bnClone() { var r = nbi(); this.copyTo(r); return r; }
7198
7199// (public) return value as integer
7200function bnIntValue() {
7201 if(this.s < 0) {
7202 if(this.t == 1) return this[0]-this.DV;
7203 else if(this.t == 0) return -1;
7204 }
7205 else if(this.t == 1) return this[0];
7206 else if(this.t == 0) return 0;
7207 // assumes 16 < DB < 32
7208 return ((this[1]&((1<<(32-this.DB))-1))<<this.DB)|this[0];
7209}
7210
7211// (public) return value as byte
7212function bnByteValue() { return (this.t==0)?this.s:(this[0]<<24)>>24; }
7213
7214// (public) return value as short (assumes DB>=16)
7215function bnShortValue() { return (this.t==0)?this.s:(this[0]<<16)>>16; }
7216
7217// (protected) return x s.t. r^x < DV
7218function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); }
7219
7220// (public) 0 if this == 0, 1 if this > 0
7221function bnSigNum() {
7222 if(this.s < 0) return -1;
7223 else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
7224 else return 1;
7225}
7226
7227// (protected) convert to radix string
7228function bnpToRadix(b) {
7229 if(b == null) b = 10;
7230 if(this.signum() == 0 || b < 2 || b > 36) return "0";
7231 var cs = this.chunkSize(b);
7232 var a = Math.pow(b,cs);
7233 var d = nbv(a), y = nbi(), z = nbi(), r = "";
7234 this.divRemTo(d,y,z);
7235 while(y.signum() > 0) {
7236 r = (a+z.intValue()).toString(b).substr(1) + r;
7237 y.divRemTo(d,y,z);
7238 }
7239 return z.intValue().toString(b) + r;
7240}
7241
7242// (protected) convert from radix string
7243function bnpFromRadix(s,b) {
7244 this.fromInt(0);
7245 if(b == null) b = 10;
7246 var cs = this.chunkSize(b);
7247 var d = Math.pow(b,cs), mi = false, j = 0, w = 0;
7248 for(var i = 0; i < s.length; ++i) {
7249 var x = intAt(s,i);
7250 if(x < 0) {
7251 if(s.charAt(i) == "-" && this.signum() == 0) mi = true;
7252 continue;
7253 }
7254 w = b*w+x;
7255 if(++j >= cs) {
7256 this.dMultiply(d);
7257 this.dAddOffset(w,0);
7258 j = 0;
7259 w = 0;
7260 }
7261 }
7262 if(j > 0) {
7263 this.dMultiply(Math.pow(b,j));
7264 this.dAddOffset(w,0);
7265 }
7266 if(mi) BigInteger.ZERO.subTo(this,this);
7267}
7268
7269// (protected) alternate constructor
7270function bnpFromNumber(a,b,c) {
7271 if("number" == typeof b) {
7272 // new BigInteger(int,int,RNG)
7273 if(a < 2) this.fromInt(1);
7274 else {
7275 this.fromNumber(a,c);
7276 if(!this.testBit(a-1)) // force MSB set
7277 this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this);
7278 if(this.isEven()) this.dAddOffset(1,0); // force odd
7279 while(!this.isProbablePrime(b)) {
7280 this.dAddOffset(2,0);
7281 if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this);
7282 }
7283 }
7284 }
7285 else {
7286 // new BigInteger(int,RNG)
7287 var x = new Array(), t = a&7;
7288 x.length = (a>>3)+1;
7289 b.nextBytes(x);
7290 if(t > 0) x[0] &= ((1<<t)-1); else x[0] = 0;
7291 this.fromString(x,256);
7292 }
7293}
7294
7295// (public) convert to bigendian byte array
7296function bnToByteArray() {
7297 var i = this.t, r = new Array();
7298 r[0] = this.s;
7299 var p = this.DB-(i*this.DB)%8, d, k = 0;
7300 if(i-- > 0) {
7301 if(p < this.DB && (d = this[i]>>p) != (this.s&this.DM)>>p)
7302 r[k++] = d|(this.s<<(this.DB-p));
7303 while(i >= 0) {
7304 if(p < 8) {
7305 d = (this[i]&((1<<p)-1))<<(8-p);
7306 d |= this[--i]>>(p+=this.DB-8);
7307 }
7308 else {
7309 d = (this[i]>>(p-=8))&0xff;
7310 if(p <= 0) { p += this.DB; --i; }
7311 }
7312 if((d&0x80) != 0) d |= -256;
7313 if(k == 0 && (this.s&0x80) != (d&0x80)) ++k;
7314 if(k > 0 || d != this.s) r[k++] = d;
7315 }
7316 }
7317 return r;
7318}
7319
7320function bnEquals(a) { return(this.compareTo(a)==0); }
7321function bnMin(a) { return(this.compareTo(a)<0)?this:a; }
7322function bnMax(a) { return(this.compareTo(a)>0)?this:a; }
7323
7324// (protected) r = this op a (bitwise)
7325function bnpBitwiseTo(a,op,r) {
7326 var i, f, m = Math.min(a.t,this.t);
7327 for(i = 0; i < m; ++i) r[i] = op(this[i],a[i]);
7328 if(a.t < this.t) {
7329 f = a.s&this.DM;
7330 for(i = m; i < this.t; ++i) r[i] = op(this[i],f);
7331 r.t = this.t;
7332 }
7333 else {
7334 f = this.s&this.DM;
7335 for(i = m; i < a.t; ++i) r[i] = op(f,a[i]);
7336 r.t = a.t;
7337 }
7338 r.s = op(this.s,a.s);
7339 r.clamp();
7340}
7341
7342// (public) this & a
7343function op_and(x,y) { return x&y; }
7344function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; }
7345
7346// (public) this | a
7347function op_or(x,y) { return x|y; }
7348function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; }
7349
7350// (public) this ^ a
7351function op_xor(x,y) { return x^y; }
7352function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; }
7353
7354// (public) this & ~a
7355function op_andnot(x,y) { return x&~y; }
7356function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; }
7357
7358// (public) ~this
7359function bnNot() {
7360 var r = nbi();
7361 for(var i = 0; i < this.t; ++i) r[i] = this.DM&~this[i];
7362 r.t = this.t;
7363 r.s = ~this.s;
7364 return r;
7365}
7366
7367// (public) this << n
7368function bnShiftLeft(n) {
7369 var r = nbi();
7370 if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r);
7371 return r;
7372}
7373
7374// (public) this >> n
7375function bnShiftRight(n) {
7376 var r = nbi();
7377 if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r);
7378 return r;
7379}
7380
7381// return index of lowest 1-bit in x, x < 2^31
7382function lbit(x) {
7383 if(x == 0) return -1;
7384 var r = 0;
7385 if((x&0xffff) == 0) { x >>= 16; r += 16; }
7386 if((x&0xff) == 0) { x >>= 8; r += 8; }
7387 if((x&0xf) == 0) { x >>= 4; r += 4; }
7388 if((x&3) == 0) { x >>= 2; r += 2; }
7389 if((x&1) == 0) ++r;
7390 return r;
7391}
7392
7393// (public) returns index of lowest 1-bit (or -1 if none)
7394function bnGetLowestSetBit() {
7395 for(var i = 0; i < this.t; ++i)
7396 if(this[i] != 0) return i*this.DB+lbit(this[i]);
7397 if(this.s < 0) return this.t*this.DB;
7398 return -1;
7399}
7400
7401// return number of 1 bits in x
7402function cbit(x) {
7403 var r = 0;
7404 while(x != 0) { x &= x-1; ++r; }
7405 return r;
7406}
7407
7408// (public) return number of set bits
7409function bnBitCount() {
7410 var r = 0, x = this.s&this.DM;
7411 for(var i = 0; i < this.t; ++i) r += cbit(this[i]^x);
7412 return r;
7413}
7414
7415// (public) true iff nth bit is set
7416function bnTestBit(n) {
7417 var j = Math.floor(n/this.DB);
7418 if(j >= this.t) return(this.s!=0);
7419 return((this[j]&(1<<(n%this.DB)))!=0);
7420}
7421
7422// (protected) this op (1<<n)
7423function bnpChangeBit(n,op) {
7424 var r = BigInteger.ONE.shiftLeft(n);
7425 this.bitwiseTo(r,op,r);
7426 return r;
7427}
7428
7429// (public) this | (1<<n)
7430function bnSetBit(n) { return this.changeBit(n,op_or); }
7431
7432// (public) this & ~(1<<n)
7433function bnClearBit(n) { return this.changeBit(n,op_andnot); }
7434
7435// (public) this ^ (1<<n)
7436function bnFlipBit(n) { return this.changeBit(n,op_xor); }
7437
7438// (protected) r = this + a
7439function bnpAddTo(a,r) {
7440 var i = 0, c = 0, m = Math.min(a.t,this.t);
7441 while(i < m) {
7442 c += this[i]+a[i];
7443 r[i++] = c&this.DM;
7444 c >>= this.DB;
7445 }
7446 if(a.t < this.t) {
7447 c += a.s;
7448 while(i < this.t) {
7449 c += this[i];
7450 r[i++] = c&this.DM;
7451 c >>= this.DB;
7452 }
7453 c += this.s;
7454 }
7455 else {
7456 c += this.s;
7457 while(i < a.t) {
7458 c += a[i];
7459 r[i++] = c&this.DM;
7460 c >>= this.DB;
7461 }
7462 c += a.s;
7463 }
7464 r.s = (c<0)?-1:0;
7465 if(c > 0) r[i++] = c;
7466 else if(c < -1) r[i++] = this.DV+c;
7467 r.t = i;
7468 r.clamp();
7469}
7470
7471// (public) this + a
7472function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; }
7473
7474// (public) this - a
7475function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; }
7476
7477// (public) this * a
7478function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; }
7479
7480// (public) this / a
7481function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; }
7482
7483// (public) this % a
7484function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; }
7485
7486// (public) [this/a,this%a]
7487function bnDivideAndRemainder(a) {
7488 var q = nbi(), r = nbi();
7489 this.divRemTo(a,q,r);
7490 return new Array(q,r);
7491}
7492
7493// (protected) this *= n, this >= 0, 1 < n < DV
7494function bnpDMultiply(n) {
7495 this[this.t] = this.am(0,n-1,this,0,0,this.t);
7496 ++this.t;
7497 this.clamp();
7498}
7499
7500// (protected) this += n << w words, this >= 0
7501function bnpDAddOffset(n,w) {
7502 if(n == 0) return;
7503 while(this.t <= w) this[this.t++] = 0;
7504 this[w] += n;
7505 while(this[w] >= this.DV) {
7506 this[w] -= this.DV;
7507 if(++w >= this.t) this[this.t++] = 0;
7508 ++this[w];
7509 }
7510}
7511
7512// A "null" reducer
7513function NullExp() {}
7514function nNop(x) { return x; }
7515function nMulTo(x,y,r) { x.multiplyTo(y,r); }
7516function nSqrTo(x,r) { x.squareTo(r); }
7517
7518NullExp.prototype.convert = nNop;
7519NullExp.prototype.revert = nNop;
7520NullExp.prototype.mulTo = nMulTo;
7521NullExp.prototype.sqrTo = nSqrTo;
7522
7523// (public) this^e
7524function bnPow(e) { return this.exp(e,new NullExp()); }
7525
7526// (protected) r = lower n words of "this * a", a.t <= n
7527// "this" should be the larger one if appropriate.
7528function bnpMultiplyLowerTo(a,n,r) {
7529 var i = Math.min(this.t+a.t,n);
7530 r.s = 0; // assumes a,this >= 0
7531 r.t = i;
7532 while(i > 0) r[--i] = 0;
7533 var j;
7534 for(j = r.t-this.t; i < j; ++i) r[i+this.t] = this.am(0,a[i],r,i,0,this.t);
7535 for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a[i],r,i,0,n-i);
7536 r.clamp();
7537}
7538
7539// (protected) r = "this * a" without lower n words, n > 0
7540// "this" should be the larger one if appropriate.
7541function bnpMultiplyUpperTo(a,n,r) {
7542 --n;
7543 var i = r.t = this.t+a.t-n;
7544 r.s = 0; // assumes a,this >= 0
7545 while(--i >= 0) r[i] = 0;
7546 for(i = Math.max(n-this.t,0); i < a.t; ++i)
7547 r[this.t+i-n] = this.am(n-i,a[i],r,0,0,this.t+i-n);
7548 r.clamp();
7549 r.drShiftTo(1,r);
7550}
7551
7552// Barrett modular reduction
7553function Barrett(m) {
7554 // setup Barrett
7555 this.r2 = nbi();
7556 this.q3 = nbi();
7557 BigInteger.ONE.dlShiftTo(2*m.t,this.r2);
7558 this.mu = this.r2.divide(m);
7559 this.m = m;
7560}
7561
7562function barrettConvert(x) {
7563 if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m);
7564 else if(x.compareTo(this.m) < 0) return x;
7565 else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; }
7566}
7567
7568function barrettRevert(x) { return x; }
7569
7570// x = x mod m (HAC 14.42)
7571function barrettReduce(x) {
7572 x.drShiftTo(this.m.t-1,this.r2);
7573 if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); }
7574 this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3);
7575 this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);
7576 while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1);
7577 x.subTo(this.r2,x);
7578 while(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
7579}
7580
7581// r = x^2 mod m; x != r
7582function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
7583
7584// r = x*y mod m; x,y != r
7585function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
7586
7587Barrett.prototype.convert = barrettConvert;
7588Barrett.prototype.revert = barrettRevert;
7589Barrett.prototype.reduce = barrettReduce;
7590Barrett.prototype.mulTo = barrettMulTo;
7591Barrett.prototype.sqrTo = barrettSqrTo;
7592
7593// (public) this^e % m (HAC 14.85)
7594function bnModPow(e,m) {
7595 var i = e.bitLength(), k, r = nbv(1), z;
7596 if(i <= 0) return r;
7597 else if(i < 18) k = 1;
7598 else if(i < 48) k = 3;
7599 else if(i < 144) k = 4;
7600 else if(i < 768) k = 5;
7601 else k = 6;
7602 if(i < 8)
7603 z = new Classic(m);
7604 else if(m.isEven())
7605 z = new Barrett(m);
7606 else
7607 z = new Montgomery(m);
7608
7609 // precomputation
7610 var g = new Array(), n = 3, k1 = k-1, km = (1<<k)-1;
7611 g[1] = z.convert(this);
7612 if(k > 1) {
7613 var g2 = nbi();
7614 z.sqrTo(g[1],g2);
7615 while(n <= km) {
7616 g[n] = nbi();
7617 z.mulTo(g2,g[n-2],g[n]);
7618 n += 2;
7619 }
7620 }
7621
7622 var j = e.t-1, w, is1 = true, r2 = nbi(), t;
7623 i = nbits(e[j])-1;
7624 while(j >= 0) {
7625 if(i >= k1) w = (e[j]>>(i-k1))&km;
7626 else {
7627 w = (e[j]&((1<<(i+1))-1))<<(k1-i);
7628 if(j > 0) w |= e[j-1]>>(this.DB+i-k1);
7629 }
7630
7631 n = k;
7632 while((w&1) == 0) { w >>= 1; --n; }
7633 if((i -= n) < 0) { i += this.DB; --j; }
7634 if(is1) { // ret == 1, don't bother squaring or multiplying it
7635 g[w].copyTo(r);
7636 is1 = false;
7637 }
7638 else {
7639 while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; }
7640 if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; }
7641 z.mulTo(r2,g[w],r);
7642 }
7643
7644 while(j >= 0 && (e[j]&(1<<i)) == 0) {
7645 z.sqrTo(r,r2); t = r; r = r2; r2 = t;
7646 if(--i < 0) { i = this.DB-1; --j; }
7647 }
7648 }
7649 return z.revert(r);
7650}
7651
7652// (public) gcd(this,a) (HAC 14.54)
7653function bnGCD(a) {
7654 var x = (this.s<0)?this.negate():this.clone();
7655 var y = (a.s<0)?a.negate():a.clone();
7656 if(x.compareTo(y) < 0) { var t = x; x = y; y = t; }
7657 var i = x.getLowestSetBit(), g = y.getLowestSetBit();
7658 if(g < 0) return x;
7659 if(i < g) g = i;
7660 if(g > 0) {
7661 x.rShiftTo(g,x);
7662 y.rShiftTo(g,y);
7663 }
7664 while(x.signum() > 0) {
7665 if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x);
7666 if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y);
7667 if(x.compareTo(y) >= 0) {
7668 x.subTo(y,x);
7669 x.rShiftTo(1,x);
7670 }
7671 else {
7672 y.subTo(x,y);
7673 y.rShiftTo(1,y);
7674 }
7675 }
7676 if(g > 0) y.lShiftTo(g,y);
7677 return y;
7678}
7679
7680// (protected) this % n, n < 2^26
7681function bnpModInt(n) {
7682 if(n <= 0) return 0;
7683 var d = this.DV%n, r = (this.s<0)?n-1:0;
7684 if(this.t > 0)
7685 if(d == 0) r = this[0]%n;
7686 else for(var i = this.t-1; i >= 0; --i) r = (d*r+this[i])%n;
7687 return r;
7688}
7689
7690// (public) 1/this % m (HAC 14.61)
7691function bnModInverse(m) {
7692 var ac = m.isEven();
7693 if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
7694 var u = m.clone(), v = this.clone();
7695 var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
7696 while(u.signum() != 0) {
7697 while(u.isEven()) {
7698 u.rShiftTo(1,u);
7699 if(ac) {
7700 if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); }
7701 a.rShiftTo(1,a);
7702 }
7703 else if(!b.isEven()) b.subTo(m,b);
7704 b.rShiftTo(1,b);
7705 }
7706 while(v.isEven()) {
7707 v.rShiftTo(1,v);
7708 if(ac) {
7709 if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); }
7710 c.rShiftTo(1,c);
7711 }
7712 else if(!d.isEven()) d.subTo(m,d);
7713 d.rShiftTo(1,d);
7714 }
7715 if(u.compareTo(v) >= 0) {
7716 u.subTo(v,u);
7717 if(ac) a.subTo(c,a);
7718 b.subTo(d,b);
7719 }
7720 else {
7721 v.subTo(u,v);
7722 if(ac) c.subTo(a,c);
7723 d.subTo(b,d);
7724 }
7725 }
7726 if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
7727 if(d.compareTo(m) >= 0) return d.subtract(m);
7728 if(d.signum() < 0) d.addTo(m,d); else return d;
7729 if(d.signum() < 0) return d.add(m); else return d;
7730}
7731
7732var 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];
7733var lplim = (1<<26)/lowprimes[lowprimes.length-1];
7734
7735// (public) test primality with certainty >= 1-.5^t
7736function bnIsProbablePrime(t) {
7737 var i, x = this.abs();
7738 if(x.t == 1 && x[0] <= lowprimes[lowprimes.length-1]) {
7739 for(i = 0; i < lowprimes.length; ++i)
7740 if(x[0] == lowprimes[i]) return true;
7741 return false;
7742 }
7743 if(x.isEven()) return false;
7744 i = 1;
7745 while(i < lowprimes.length) {
7746 var m = lowprimes[i], j = i+1;
7747 while(j < lowprimes.length && m < lplim) m *= lowprimes[j++];
7748 m = x.modInt(m);
7749 while(i < j) if(m%lowprimes[i++] == 0) return false;
7750 }
7751 return x.millerRabin(t);
7752}
7753
7754// (protected) true if probably prime (HAC 4.24, Miller-Rabin)
7755function bnpMillerRabin(t) {
7756 var n1 = this.subtract(BigInteger.ONE);
7757 var k = n1.getLowestSetBit();
7758 if(k <= 0) return false;
7759 var r = n1.shiftRight(k);
7760 t = (t+1)>>1;
7761 if(t > lowprimes.length) t = lowprimes.length;
7762 var a = nbi();
7763 for(var i = 0; i < t; ++i) {
7764 a.fromInt(lowprimes[i]);
7765 var y = a.modPow(r,this);
7766 if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {
7767 var j = 1;
7768 while(j++ < k && y.compareTo(n1) != 0) {
7769 y = y.modPowInt(2,this);
7770 if(y.compareTo(BigInteger.ONE) == 0) return false;
7771 }
7772 if(y.compareTo(n1) != 0) return false;
7773 }
7774 }
7775 return true;
7776}
7777
7778// protected
7779BigInteger.prototype.chunkSize = bnpChunkSize;
7780BigInteger.prototype.toRadix = bnpToRadix;
7781BigInteger.prototype.fromRadix = bnpFromRadix;
7782BigInteger.prototype.fromNumber = bnpFromNumber;
7783BigInteger.prototype.bitwiseTo = bnpBitwiseTo;
7784BigInteger.prototype.changeBit = bnpChangeBit;
7785BigInteger.prototype.addTo = bnpAddTo;
7786BigInteger.prototype.dMultiply = bnpDMultiply;
7787BigInteger.prototype.dAddOffset = bnpDAddOffset;
7788BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo;
7789BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo;
7790BigInteger.prototype.modInt = bnpModInt;
7791BigInteger.prototype.millerRabin = bnpMillerRabin;
7792
7793// public
7794BigInteger.prototype.clone = bnClone;
7795BigInteger.prototype.intValue = bnIntValue;
7796BigInteger.prototype.byteValue = bnByteValue;
7797BigInteger.prototype.shortValue = bnShortValue;
7798BigInteger.prototype.signum = bnSigNum;
7799BigInteger.prototype.toByteArray = bnToByteArray;
7800BigInteger.prototype.equals = bnEquals;
7801BigInteger.prototype.min = bnMin;
7802BigInteger.prototype.max = bnMax;
7803BigInteger.prototype.and = bnAnd;
7804BigInteger.prototype.or = bnOr;
7805BigInteger.prototype.xor = bnXor;
7806BigInteger.prototype.andNot = bnAndNot;
7807BigInteger.prototype.not = bnNot;
7808BigInteger.prototype.shiftLeft = bnShiftLeft;
7809BigInteger.prototype.shiftRight = bnShiftRight;
7810BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit;
7811BigInteger.prototype.bitCount = bnBitCount;
7812BigInteger.prototype.testBit = bnTestBit;
7813BigInteger.prototype.setBit = bnSetBit;
7814BigInteger.prototype.clearBit = bnClearBit;
7815BigInteger.prototype.flipBit = bnFlipBit;
7816BigInteger.prototype.add = bnAdd;
7817BigInteger.prototype.subtract = bnSubtract;
7818BigInteger.prototype.multiply = bnMultiply;
7819BigInteger.prototype.divide = bnDivide;
7820BigInteger.prototype.remainder = bnRemainder;
7821BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder;
7822BigInteger.prototype.modPow = bnModPow;
7823BigInteger.prototype.modInverse = bnModInverse;
7824BigInteger.prototype.pow = bnPow;
7825BigInteger.prototype.gcd = bnGCD;
7826BigInteger.prototype.isProbablePrime = bnIsProbablePrime;
7827
7828// BigInteger interfaces not implemented in jsbn:
7829
7830// BigInteger(int signum, byte[] magnitude)
7831// double doubleValue()
7832// float floatValue()
7833// int hashCode()
7834// long longValue()
7835// static BigInteger valueOf(long val)