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