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