blob: 3ec855ac0d237a2522560a2b2236116f5ada5453 [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
4362/* Return a user friendly HTML string with the contents of co.
4363 This also outputs to console.log.
4364 */
4365function contentObjectToHtml(/* ContentObject */ co) {
4366 var output ="";
4367
4368 if(co==-1)
4369 output+= "NO CONTENT FOUND"
4370 else if (co==-2)
4371 output+= "CONTENT NAME IS EMPTY"
4372 else{
4373 if(co.name!=null && co.name.components!=null){
4374 output+= "NAME: " + co.name.to_uri();
4375
4376 output+= "<br />";
4377 output+= "<br />";
4378 }
4379
4380 if(co.content !=null){
4381 output += "CONTENT(ASCII): "+ DataUtils.toString(co.content);
4382
4383 output+= "<br />";
4384 output+= "<br />";
4385 }
4386 if(co.content !=null){
4387 output += "CONTENT(hex): "+ DataUtils.toHex(co.content);
4388
4389 output+= "<br />";
4390 output+= "<br />";
4391 }
4392 if(co.signature !=null && co.signature.signature!=null){
4393 output += "SIGNATURE(hex): "+ DataUtils.toHex(co.signature.signature);
4394
4395 output+= "<br />";
4396 output+= "<br />";
4397 }
4398 if(co.signedInfo !=null && co.signedInfo.publisher!=null && co.signedInfo.publisher.publisherPublicKeyDigest!=null){
4399 output += "Publisher Public Key Digest(hex): "+ DataUtils.toHex(co.signedInfo.publisher.publisherPublicKeyDigest);
4400
4401 output+= "<br />";
4402 output+= "<br />";
4403 }
4404 if(co.signedInfo !=null && co.signedInfo.timestamp!=null){
4405 var d = new Date();
4406 d.setTime( co.signedInfo.timestamp.msec );
4407
4408 var bytes = [217, 185, 12, 225, 217, 185, 12, 225];
4409
4410 output += "TimeStamp: "+d;
4411 output+= "<br />";
4412 output += "TimeStamp(number): "+ co.signedInfo.timestamp.msec;
4413
4414 output+= "<br />";
4415 }
4416 if(co.signedInfo !=null && co.signedInfo.finalBlockID!=null){
4417 output += "FinalBlockID: "+ DataUtils.toHex(co.signedInfo.finalBlockID);
4418 output+= "<br />";
4419 }
4420 if(co.signedInfo!=null && co.signedInfo.locator!=null && co.signedInfo.locator.certificate!=null){
4421 var tmp = DataUtils.toString(co.signedInfo.locator.certificate);
4422 var publickey = rstr2b64(tmp);
4423 var publickeyHex = DataUtils.toHex(co.signedInfo.locator.certificate).toLowerCase();
4424 var publickeyString = DataUtils.toString(co.signedInfo.locator.certificate);
4425 var signature = DataUtils.toHex(co.signature.signature).toLowerCase();
4426 var input = DataUtils.toString(co.rawSignatureData);
4427
4428 output += "DER Certificate: "+publickey ;
4429
4430 output+= "<br />";
4431 output+= "<br />";
4432
4433 if(LOG>2) console.log(" ContentName + SignedInfo + Content = "+input);
4434
4435 if(LOG>2) console.log("HEX OF ContentName + SignedInfo + Content = ");
4436 if(LOG>2) console.log(DataUtils.stringtoBase64(input));
4437
4438 if(LOG>2) console.log(" PublicKey = "+publickey );
4439 if(LOG>2) console.log(" PublicKeyHex = "+publickeyHex );
4440 if(LOG>2) console.log(" PublicKeyString = "+publickeyString );
4441
4442 if(LOG>2) console.log(" Signature is");
4443 if(LOG>2) console.log( signature );
4444 //if(LOG>2) console.log(" Signature NOW IS" );
4445 //if(LOG>2) console.log(co.signature.signature);
4446
4447 var x509 = new X509();
4448 x509.readCertPEM(publickey);
4449
4450 //x509.readCertPEMWithoutRSAInit(publickey);
4451
4452 var result = x509.subjectPublicKeyRSA.verifyByteArray(co.rawSignatureData, signature);
4453 if(LOG>2) console.log('result is '+result);
4454
4455 var n = x509.subjectPublicKeyRSA.n;
4456 var e = x509.subjectPublicKeyRSA.e;
4457
4458 if(LOG>2) console.log('PUBLIC KEY n after is ');
4459 if(LOG>2) console.log(n);
4460
4461 if(LOG>2) console.log('EXPONENT e after is ');
4462 if(LOG>2) console.log(e);
4463
4464 /*var rsakey = new RSAKey();
4465
4466 var kp = publickeyHex.slice(56,314);
4467
4468 output += "PUBLISHER KEY(hex): "+kp ;
4469
4470 output+= "<br />";
4471 output+= "<br />";
4472
4473 console.log('kp is '+kp);
4474
4475 var exp = publickeyHex.slice(318,324);
4476
4477 console.log('kp size is '+kp.length );
4478 output += "exponent: "+exp ;
4479
4480 output+= "<br />";
4481 output+= "<br />";
4482
4483 console.log('exp is '+exp);
4484
4485 rsakey.setPublic(kp,exp);
4486
4487 var result = rsakey.verifyString(input, signature);*/
4488
4489 if(result)
4490 output += 'SIGNATURE VALID';
4491 else
4492 output += 'SIGNATURE INVALID';
4493
4494 //output += "VALID: "+ toHex(co.signedInfo.locator.publicKey);
4495
4496 output+= "<br />";
4497 output+= "<br />";
4498
4499 //if(LOG>4) console.log('str'[1]);
4500 }
4501 if(co.signedInfo!=null && co.signedInfo.locator!=null && co.signedInfo.locator.publicKey!=null){
4502 var publickey = rstr2b64(DataUtils.toString(co.signedInfo.locator.publicKey));
4503 var publickeyHex = DataUtils.toHex(co.signedInfo.locator.publicKey).toLowerCase();
4504 var publickeyString = DataUtils.toString(co.signedInfo.locator.publicKey);
4505 var signature = DataUtils.toHex(co.signature.signature).toLowerCase();
4506 var input = DataUtils.toString(co.rawSignatureData);
4507
4508 output += "DER Certificate: "+publickey ;
4509
4510 output+= "<br />";
4511 output+= "<br />";
4512
4513 if(LOG>2) console.log(" ContentName + SignedInfo + Content = "+input);
4514 if(LOG>2) console.log(" PublicKey = "+publickey );
4515 if(LOG>2) console.log(" PublicKeyHex = "+publickeyHex );
4516 if(LOG>2) console.log(" PublicKeyString = "+publickeyString );
4517
4518 if(LOG>2) console.log(" Signature "+signature );
4519
4520 if(LOG>2) console.log(" Signature NOW IS" );
4521
4522 if(LOG>2) console.log(co.signature.signature);
4523
4524 /*var x509 = new X509();
4525
4526 x509.readCertPEM(publickey);
4527
4528
4529 //x509.readCertPEMWithoutRSAInit(publickey);
4530
4531 var result = x509.subjectPublicKeyRSA.verifyString(input, signature);*/
4532 //console.log('result is '+result);
4533
4534 var kp = publickeyHex.slice(56,314);
4535
4536 output += "PUBLISHER KEY(hex): "+kp ;
4537
4538 output+= "<br />";
4539 output+= "<br />";
4540
Wentao Shang2b740e62012-12-07 00:02:53 -08004541 if(LOG>2) console.log('PUBLIC KEY IN HEX is ');
4542 if(LOG>2) console.log(kp);
Wentao Shang0e291c82012-12-02 23:36:29 -08004543
4544 var exp = publickeyHex.slice(318,324);
4545
Wentao Shang2b740e62012-12-07 00:02:53 -08004546 if(LOG>2) console.log('kp size is '+kp.length );
Wentao Shang0e291c82012-12-02 23:36:29 -08004547 output += "exponent: "+exp ;
4548
4549 output+= "<br />";
4550 output+= "<br />";
4551
Wentao Shang2b740e62012-12-07 00:02:53 -08004552 if(LOG>2) console.log('EXPONENT is ');
4553 if(LOG>2) console.log(exp);
Wentao Shang0e291c82012-12-02 23:36:29 -08004554
Jeff Thompson1a338f82012-12-29 17:07:04 -08004555 var a = _x509_getPublicKeyHexArrayFromCertHex(publickeyHex, _x509_getSubjectPublicKeyPosFromCertHex(publickeyHex, 0));
4556 output += "a[0] " + a[0] + "<br/>";
4557 output += "a[1] " + a[1] + "<br/>";
4558
Wentao Shang0e291c82012-12-02 23:36:29 -08004559 /*var c1 = hex_sha256(input);
4560 var c2 = signature;
4561
4562 if(LOG>4)console.log('input is ');
4563 if(LOG>4)console.log(input);
4564 if(LOG>4)console.log('C1 is ');
4565 if(LOG>4)console.log(c1);
4566 if(LOG>4)console.log('C2 is ');
4567 if(LOG>4)console.log(c2);
4568 var result = c1 == c2;*/
4569
4570 var rsakey = new RSAKey();
4571
4572 rsakey.setPublic(kp,exp);
4573
4574 var result = rsakey.verifyByteArray(co.rawSignatureData,signature);
4575 // var result = rsakey.verifyString(input, signature);
4576
Wentao Shang2b740e62012-12-07 00:02:53 -08004577 if(LOG>2) console.log('PUBLIC KEY n after is ');
4578 if(LOG>2) console.log(rsakey.n);
Wentao Shang0e291c82012-12-02 23:36:29 -08004579
Wentao Shang2b740e62012-12-07 00:02:53 -08004580 if(LOG>2) console.log('EXPONENT e after is ');
4581 if(LOG>2) console.log(rsakey.e);
Wentao Shang0e291c82012-12-02 23:36:29 -08004582
4583 if(result)
4584 output += 'SIGNATURE VALID';
4585 else
4586 output += 'SIGNATURE INVALID';
4587
4588 //output += "VALID: "+ toHex(co.signedInfo.locator.publicKey);
4589
4590 output+= "<br />";
4591 output+= "<br />";
4592
4593 //if(LOG>4) console.log('str'[1]);
4594 }
4595 }
4596
4597 return output;
4598}
Jeff Thompson1a338f82012-12-29 17:07:04 -08004599
4600
Wentao Shangbd63e462012-12-03 16:19:33 -08004601/**
Wentao Shang0e291c82012-12-02 23:36:29 -08004602 * @author: Meki Cheraoui
4603 * See COPYING for copyright and distribution information.
4604 */
4605
4606var KeyManager = function KeyManager(){
4607
4608
4609//Certificate
4610
4611this.certificate = 'MIIBmzCCAQQCCQC32FyQa61S7jANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwd'+
4612
4613'heGVsY2R2MB4XDTEyMDQyODIzNDQzN1oXDTEyMDUyODIzNDQzN1owEjEQMA4GA1'+
4614
4615'UEAxMHYXhlbGNkdjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4X0wp9goq'+
4616
4617'xuECxdULcr2IHr9Ih4Iaypg0Wy39URIup8/CLzQmdsh3RYqd55hqonu5VTTpH3i'+
4618
4619'MLx6xZDVJAZ8OJi7pvXcQ2C4Re2kjL2c8SanI0RfDhlS1zJadfr1VhRPmpivcYa'+
4620
4621'wJ4aFuOLAi+qHFxtN7lhcGCgpW1OV60oXd58CAwEAATANBgkqhkiG9w0BAQUFAA'+
4622
4623'OBgQDLOrA1fXzSrpftUB5Ro6DigX1Bjkf7F5Bkd69hSVp+jYeJFBBlsILQAfSxU'+
4624
4625'ZPQtD+2Yc3iCmSYNyxqu9PcufDRJlnvB7PG29+L3y9lR37tetzUV9eTscJ7rdp8'+
4626
4627'Wt6AzpW32IJ/54yKNfP7S6ZIoIG+LP6EIxq6s8K1MXRt8uBJKw==';
4628
4629
4630//this.publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhfTCn2CirG4QLF1QtyvYgev0iHghrKmDRbLf1REi6nz8IvNCZ2yHdFip3nmGqie7lVNOkfeIwvHrFkNUkBnw4mLum9dxDYLhF7aSMvZzxJqcjRF8OGVLXMlp1+vVWFE+amK9xhrAnhoW44sCL6ocXG03uWFwYKClbU5XrShd3nwIDAQAB';
4631this.publicKey ='30819F300D06092A864886F70D010101050003818D0030818902818100E17D30A7D828AB1B840B17542DCAF6207AFD221E086B2A60D16CB7F54448BA9F3F08BCD099DB21DD162A779E61AA89EEE554D3A47DE230BC7AC590D524067C3898BBA6F5DC4360B845EDA48CBD9CF126A723445F0E1952D7325A75FAF556144F9A98AF7186B0278685B8E2C08BEA87171B4DEE585C1828295B5395EB4A17779F0203010001';
4632//Private Key
4633
4634this.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';
4635
4636
4637/*
4638 this.certificate =
4639 'MIIBvTCCASYCCQD55fNzc0WF7TANBgkqhkiG9w0BAQUFADAjMQswCQYDVQQGEwJK'+
4640 'UDEUMBIGA1UEChMLMDAtVEVTVC1SU0EwHhcNMTAwNTI4MDIwODUxWhcNMjAwNTI1'+
4641 'MDIwODUxWjAjMQswCQYDVQQGEwJKUDEUMBIGA1UEChMLMDAtVEVTVC1SU0EwgZ8w'+
4642 'DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANGEYXtfgDRlWUSDn3haY4NVVQiKI9Cz'+
4643 'Thoua9+DxJuiseyzmBBe7Roh1RPqdvmtOHmEPbJ+kXZYhbozzPRbFGHCJyBfCLzQ'+
4644 'fVos9/qUQ88u83b0SFA2MGmQWQAlRtLy66EkR4rDRwTj2DzR4EEXgEKpIvo8VBs/'+
4645 '3+sHLF3ESgAhAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAEZ6mXFFq3AzfaqWHmCy1'+
4646 'ARjlauYAa8ZmUFnLm0emg9dkVBJ63aEqARhtok6bDQDzSJxiLpCEF6G4b/Nv/M/M'+
4647 'LyhP+OoOTmETMegAVQMq71choVJyOFE5BtQa6M/lCHEOya5QUfoRF2HF9EjRF44K'+
4648 '3OK+u3ivTSj3zwjtpudY5Xo=';
4649
4650 this.privateKey =
4651 'MIICWwIBAAKBgQDRhGF7X4A0ZVlEg594WmODVVUIiiPQs04aLmvfg8SborHss5gQ'+
4652 'Xu0aIdUT6nb5rTh5hD2yfpF2WIW6M8z0WxRhwicgXwi80H1aLPf6lEPPLvN29EhQ'+
4653 'NjBpkFkAJUbS8uuhJEeKw0cE49g80eBBF4BCqSL6PFQbP9/rByxdxEoAIQIDAQAB'+
4654 'AoGAA9/q3Zk6ib2GFRpKDLO/O2KMnAfR+b4XJ6zMGeoZ7Lbpi3MW0Nawk9ckVaX0'+
4655 'ZVGqxbSIX5Cvp/yjHHpww+QbUFrw/gCjLiiYjM9E8C3uAF5AKJ0r4GBPl4u8K4bp'+
4656 'bXeSxSB60/wPQFiQAJVcA5xhZVzqNuF3EjuKdHsw+dk+dPECQQDubX/lVGFgD/xY'+
4657 'uchz56Yc7VHX+58BUkNSewSzwJRbcueqknXRWwj97SXqpnYfKqZq78dnEF10SWsr'+
4658 '/NMKi+7XAkEA4PVqDv/OZAbWr4syXZNv/Mpl4r5suzYMMUD9U8B2JIRnrhmGZPzL'+
4659 'x23N9J4hEJ+Xh8tSKVc80jOkrvGlSv+BxwJAaTOtjA3YTV+gU7Hdza53sCnSw/8F'+
4660 'YLrgc6NOJtYhX9xqdevbyn1lkU0zPr8mPYg/F84m6MXixm2iuSz8HZoyzwJARi2p'+
4661 'aYZ5/5B2lwroqnKdZBJMGKFpUDn7Mb5hiSgocxnvMkv6NjT66Xsi3iYakJII9q8C'+
4662 'Ma1qZvT/cigmdbAh7wJAQNXyoizuGEltiSaBXx4H29EdXNYWDJ9SS5f070BRbAIl'+
4663 'dqRh3rcNvpY6BKJqFapda1DjdcncZECMizT/GMrc1w==';
4664
4665 */
4666};
4667
4668
4669KeyManager.prototype.verify = function verify(message,signature){
4670
4671 var input = message;
4672
4673 var _PEM_X509CERT_STRING_ = this.certificate;
4674
4675 var x509 = new X509();
4676
4677 x509.readCertPEM(_PEM_X509CERT_STRING_);
4678
4679 var result = x509.subjectPublicKeyRSA.verifyString(input, signature);
4680
4681 return result;
4682};
4683
4684KeyManager.prototype.sign= function sign(message){
4685
4686 var input = message;
4687
4688 var _PEM_PRIVATE_KEY_STRING_ = this.privateKey;
4689
4690 var rsa = new RSAKey();
4691
4692 rsa.readPrivateKeyFromPEMString(_PEM_PRIVATE_KEY_STRING_);
4693
4694 var hSig = rsa.signString(input, "sha256");
4695
4696 return hSig;
4697
4698};
4699
4700
4701
4702var globalKeyManager = new KeyManager();
4703//var KeyPair = { "public" : "PUBLIC KEY" , "private" : "PRIVATE KEY" };
4704
4705
4706/*
4707 * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined
4708 * in FIPS 180-2
4709 * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
4710 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
4711 * Distributed under the BSD License
4712 * See http://pajhome.org.uk/crypt/md5 for details.
4713 * Also http://anmar.eu.org/projects/jssha2/
4714 */
4715
4716/*
4717 * Configurable variables. You may need to tweak these to be compatible with
4718 * the server-side, but the defaults work in most cases.
4719 */
4720var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
4721var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
4722
4723/*
4724 * These are the functions you'll usually want to call
4725 * They take string arguments and return either hex or base-64 encoded strings
4726 */
4727
4728//@author axelcdv
4729/**
4730 * Computes the Sha-256 hash of the given byte array
4731 * @param {byte[]}
4732 * @return the hex string corresponding to the Sha-256 hash of the byte array
4733 */
4734function hex_sha256_from_bytes(byteArray){
4735 return rstr2hex(binb2rstr(binb_sha256( byteArray2binb(byteArray), byteArray.length * 8)));
4736}
4737
4738function hex_sha256(s) { return rstr2hex(rstr_sha256(str2rstr_utf8(s))); }
4739function b64_sha256(s) { return rstr2b64(rstr_sha256(str2rstr_utf8(s))); }
4740function any_sha256(s, e) { return rstr2any(rstr_sha256(str2rstr_utf8(s)), e); }
4741function hex_hmac_sha256(k, d)
4742 { return rstr2hex(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d))); }
4743function b64_hmac_sha256(k, d)
4744 { return rstr2b64(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d))); }
4745function any_hmac_sha256(k, d, e)
4746 { return rstr2any(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
4747
4748
4749/*
4750 function hex_sha256(s) { return rstr2hex(rstr_sha256(s)); }
4751function b64_sha256(s) { return rstr2b64(rstr_sha256(s)); }
4752function any_sha256(s, e) { return rstr2any(rstr_sha256(s), e); }
4753function hex_hmac_sha256(k, d)
4754 { return rstr2hex(rstr_hmac_sha256(str2rstr_utf8(k), d)); }
4755function b64_hmac_sha256(k, d)
4756 { return rstr2b64(rstr_hmac_sha256(str2rstr_utf8(k), d)); }
4757function any_hmac_sha256(k, d, e)
4758 { return rstr2any(rstr_hmac_sha256(str2rstr_utf8(k), d), e); }
4759*/
4760
4761/*
4762 * Perform a simple self-test to see if the VM is working
4763 */
4764function sha256_vm_test()
4765{
4766 return hex_sha256("abc").toLowerCase() ==
4767 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad";
4768}
4769
4770/**
4771 * Calculate the sha256 of a raw string
4772 * @param s: the raw string
4773 */
4774function rstr_sha256(s)
4775{
4776 return binb2rstr(binb_sha256(rstr2binb(s), s.length * 8));
4777}
4778
4779/**
4780 * Calculate the HMAC-sha256 of a key and some data (raw strings)
4781 */
4782function rstr_hmac_sha256(key, data)
4783{
4784 var bkey = rstr2binb(key);
4785 if(bkey.length > 16) bkey = binb_sha256(bkey, key.length * 8);
4786
4787 var ipad = Array(16), opad = Array(16);
4788 for(var i = 0; i < 16; i++)
4789 {
4790 ipad[i] = bkey[i] ^ 0x36363636;
4791 opad[i] = bkey[i] ^ 0x5C5C5C5C;
4792 }
4793
4794 var hash = binb_sha256(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
4795 return binb2rstr(binb_sha256(opad.concat(hash), 512 + 256));
4796}
4797
4798/**
4799 * Convert a raw string to a hex string
4800 */
4801function rstr2hex(input)
4802{
4803 try { hexcase } catch(e) { hexcase=0; }
4804 var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
4805 var output = "";
4806 var x;
4807 for(var i = 0; i < input.length; i++)
4808 {
4809 x = input.charCodeAt(i);
4810 output += hex_tab.charAt((x >>> 4) & 0x0F)
4811 + hex_tab.charAt( x & 0x0F);
4812 }
4813 return output;
4814}
4815
4816/*
4817 * Convert a raw string to a base-64 string
4818 */
4819function rstr2b64(input)
4820{
4821 try { b64pad } catch(e) { b64pad=''; }
4822 var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4823 var output = "";
4824 var len = input.length;
4825 for(var i = 0; i < len; i += 3)
4826 {
4827 var triplet = (input.charCodeAt(i) << 16)
4828 | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
4829 | (i + 2 < len ? input.charCodeAt(i+2) : 0);
4830 for(var j = 0; j < 4; j++)
4831 {
4832 if(i * 8 + j * 6 > input.length * 8) output += b64pad;
4833 else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
4834 }
4835 }
4836 return output;
4837}
4838
4839/*
4840 * Convert a raw string to an arbitrary string encoding
4841 */
4842function rstr2any(input, encoding)
4843{
4844 var divisor = encoding.length;
4845 var remainders = Array();
4846 var i, q, x, quotient;
4847
4848 /* Convert to an array of 16-bit big-endian values, forming the dividend */
4849 var dividend = Array(Math.ceil(input.length / 2));
4850 for(i = 0; i < dividend.length; i++)
4851 {
4852 dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
4853 }
4854
4855 /*
4856 * Repeatedly perform a long division. The binary array forms the dividend,
4857 * the length of the encoding is the divisor. Once computed, the quotient
4858 * forms the dividend for the next step. We stop when the dividend is zero.
4859 * All remainders are stored for later use.
4860 */
4861 while(dividend.length > 0)
4862 {
4863 quotient = Array();
4864 x = 0;
4865 for(i = 0; i < dividend.length; i++)
4866 {
4867 x = (x << 16) + dividend[i];
4868 q = Math.floor(x / divisor);
4869 x -= q * divisor;
4870 if(quotient.length > 0 || q > 0)
4871 quotient[quotient.length] = q;
4872 }
4873 remainders[remainders.length] = x;
4874 dividend = quotient;
4875 }
4876
4877 /* Convert the remainders to the output string */
4878 var output = "";
4879 for(i = remainders.length - 1; i >= 0; i--)
4880 output += encoding.charAt(remainders[i]);
4881
4882 /* Append leading zero equivalents */
4883 var full_length = Math.ceil(input.length * 8 /
4884 (Math.log(encoding.length) / Math.log(2)))
4885 for(i = output.length; i < full_length; i++)
4886 output = encoding[0] + output;
4887
4888 return output;
4889}
4890
4891/*
4892 * Encode a string as utf-8.
4893 * For efficiency, this assumes the input is valid utf-16.
4894 */
4895function str2rstr_utf8(input)
4896{
4897 var output = "";
4898 var i = -1;
4899 var x, y;
4900
4901 while(++i < input.length)
4902 {
4903 /* Decode utf-16 surrogate pairs */
4904 x = input.charCodeAt(i);
4905 y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
4906 if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
4907 {
4908 x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
4909 i++;
4910 }
4911
4912 /* Encode output as utf-8 */
4913 if(x <= 0x7F)
4914 output += String.fromCharCode(x);
4915 else if(x <= 0x7FF)
4916 output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
4917 0x80 | ( x & 0x3F));
4918 else if(x <= 0xFFFF)
4919 output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
4920 0x80 | ((x >>> 6 ) & 0x3F),
4921 0x80 | ( x & 0x3F));
4922 else if(x <= 0x1FFFFF)
4923 output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
4924 0x80 | ((x >>> 12) & 0x3F),
4925 0x80 | ((x >>> 6 ) & 0x3F),
4926 0x80 | ( x & 0x3F));
4927 }
4928 return output;
4929}
4930
4931/*
4932 * Encode a string as utf-16
4933 */
4934function str2rstr_utf16le(input)
4935{
4936 var output = "";
4937 for(var i = 0; i < input.length; i++)
4938 output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
4939 (input.charCodeAt(i) >>> 8) & 0xFF);
4940 return output;
4941}
4942
4943function str2rstr_utf16be(input)
4944{
4945 var output = "";
4946 for(var i = 0; i < input.length; i++)
4947 output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
4948 input.charCodeAt(i) & 0xFF);
4949 return output;
4950}
4951
4952/**
4953 * Convert a raw string to an array of big-endian words
4954 * Characters >255 have their high-byte silently ignored.
4955 */
4956function rstr2binb(input)
4957{
4958 //console.log('Raw string comming is '+input);
4959 var output = Array(input.length >> 2);
Wentao Shangc0311e52012-12-03 10:38:23 -08004960 /* JavaScript automatically zeroizes a new array.
Wentao Shang0e291c82012-12-02 23:36:29 -08004961 for(var i = 0; i < output.length; i++)
4962 output[i] = 0;
Wentao Shangc0311e52012-12-03 10:38:23 -08004963 */
Wentao Shang0e291c82012-12-02 23:36:29 -08004964 for(var i = 0; i < input.length * 8; i += 8)
4965 output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
4966 return output;
4967}
4968
4969/**
4970 * @author axelcdv
4971 * Convert a byte array to an array of big-endian words
4972 * @param {byte[]} input
4973 * @return the array of big-endian words
4974 */
4975function byteArray2binb(input){
4976 //console.log("Byte array coming is " + input);
4977 var output = Array(input.length >> 2);
Wentao Shangc0311e52012-12-03 10:38:23 -08004978 /* JavaScript automatically zeroizes a new array.
Wentao Shang0e291c82012-12-02 23:36:29 -08004979 for(var i = 0; i < output.length; i++)
4980 output[i] = 0;
Wentao Shangc0311e52012-12-03 10:38:23 -08004981 */
Wentao Shang0e291c82012-12-02 23:36:29 -08004982 for(var i = 0; i < input.length * 8; i += 8)
4983 output[i>>5] |= (input[i / 8] & 0xFF) << (24 - i % 32);
4984 return output;
4985}
4986
4987/*
4988 * Convert an array of big-endian words to a string
4989 */
4990function binb2rstr(input)
4991{
4992 var output = "";
4993 for(var i = 0; i < input.length * 32; i += 8)
4994 output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
4995 return output;
4996}
4997
4998/*
4999 * Main sha256 function, with its support functions
5000 */
5001function sha256_S (X, n) {return ( X >>> n ) | (X << (32 - n));}
5002function sha256_R (X, n) {return ( X >>> n );}
5003function sha256_Ch(x, y, z) {return ((x & y) ^ ((~x) & z));}
5004function sha256_Maj(x, y, z) {return ((x & y) ^ (x & z) ^ (y & z));}
5005function sha256_Sigma0256(x) {return (sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22));}
5006function sha256_Sigma1256(x) {return (sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25));}
5007function sha256_Gamma0256(x) {return (sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3));}
5008function sha256_Gamma1256(x) {return (sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10));}
5009function sha256_Sigma0512(x) {return (sha256_S(x, 28) ^ sha256_S(x, 34) ^ sha256_S(x, 39));}
5010function sha256_Sigma1512(x) {return (sha256_S(x, 14) ^ sha256_S(x, 18) ^ sha256_S(x, 41));}
5011function sha256_Gamma0512(x) {return (sha256_S(x, 1) ^ sha256_S(x, 8) ^ sha256_R(x, 7));}
5012function sha256_Gamma1512(x) {return (sha256_S(x, 19) ^ sha256_S(x, 61) ^ sha256_R(x, 6));}
5013
5014var sha256_K = new Array
5015(
5016 1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993,
5017 -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987,
5018 1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522,
5019 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986,
5020 -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585,
5021 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291,
5022 1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885,
5023 -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344,
5024 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218,
5025 1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872,
5026 -1866530822, -1538233109, -1090935817, -965641998
5027);
5028
5029function binb_sha256(m, l)
5030{
5031 var HASH = new Array(1779033703, -1150833019, 1013904242, -1521486534,
5032 1359893119, -1694144372, 528734635, 1541459225);
5033 var W = new Array(64);
Wentao Shang0e291c82012-12-02 23:36:29 -08005034
5035 /* append padding */
5036 m[l >> 5] |= 0x80 << (24 - l % 32);
5037 m[((l + 64 >> 9) << 4) + 15] = l;
Wentao Shangc0311e52012-12-03 10:38:23 -08005038
5039 for(var offset = 0; offset < m.length; offset += 16)
5040 processBlock_sha256(m, offset, HASH, W);
Wentao Shang0e291c82012-12-02 23:36:29 -08005041
Wentao Shangc0311e52012-12-03 10:38:23 -08005042 return HASH;
5043}
5044
5045/*
5046 * Process a block of 16 4-byte words in m starting at offset and update HASH.
5047 * offset must be a multiple of 16 and less than m.length. W is a scratchpad Array(64).
5048 */
5049function processBlock_sha256(m, offset, HASH, W) {
5050 var a, b, c, d, e, f, g, h;
5051 var j, T1, T2;
5052
Wentao Shang0e291c82012-12-02 23:36:29 -08005053 a = HASH[0];
5054 b = HASH[1];
5055 c = HASH[2];
5056 d = HASH[3];
5057 e = HASH[4];
5058 f = HASH[5];
5059 g = HASH[6];
5060 h = HASH[7];
5061
5062 for(j = 0; j < 64; j++)
5063 {
Wentao Shangc0311e52012-12-03 10:38:23 -08005064 if (j < 16) W[j] = m[j + offset];
Wentao Shang0e291c82012-12-02 23:36:29 -08005065 else W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]),
5066 sha256_Gamma0256(W[j - 15])), W[j - 16]);
5067
5068 T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)),
5069 sha256_K[j]), W[j]);
5070 T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
5071 h = g;
5072 g = f;
5073 f = e;
5074 e = safe_add(d, T1);
5075 d = c;
5076 c = b;
5077 b = a;
5078 a = safe_add(T1, T2);
5079 }
5080
5081 HASH[0] = safe_add(a, HASH[0]);
5082 HASH[1] = safe_add(b, HASH[1]);
5083 HASH[2] = safe_add(c, HASH[2]);
5084 HASH[3] = safe_add(d, HASH[3]);
5085 HASH[4] = safe_add(e, HASH[4]);
5086 HASH[5] = safe_add(f, HASH[5]);
5087 HASH[6] = safe_add(g, HASH[6]);
5088 HASH[7] = safe_add(h, HASH[7]);
Wentao Shang0e291c82012-12-02 23:36:29 -08005089}
5090
5091function safe_add (x, y)
5092{
5093 var lsw = (x & 0xFFFF) + (y & 0xFFFF);
5094 var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
5095 return (msw << 16) | (lsw & 0xFFFF);
5096}
Wentao Shangc0311e52012-12-03 10:38:23 -08005097
5098/*
5099 * Create a Sha256, call update(data) multiple times, then call finalize().
5100 */
5101var Sha256 = function Sha256() {
5102 this.W = new Array(64);
5103 this.hash = new Array(1779033703, -1150833019, 1013904242, -1521486534,
5104 1359893119, -1694144372, 528734635, 1541459225);
5105 this.nTotalBytes = 0;
5106 this.buffer = new Uint8Array(16 * 4);
5107 this.nBufferBytes = 0;
5108}
5109
5110/*
5111 * Update the hash with data, which is Uint8Array.
5112 */
5113Sha256.prototype.update = function(data) {
5114 this.nTotalBytes += data.length;
5115
5116 if (this.nBufferBytes > 0) {
5117 // Fill up the buffer and process it first.
5118 var bytesNeeded = this.buffer.length - this.nBufferBytes;
5119 if (data.length < bytesNeeded) {
5120 this.buffer.set(data, this.nBufferBytes);
5121 this.nBufferBytes += data.length;
5122 return;
5123 }
5124 else {
5125 this.buffer.set(data.subarray(0, bytesNeeded), this.nBufferBytes);
5126 processBlock_sha256(byteArray2binb(this.buffer), 0, this.hash, this.W);
5127 this.nBufferBytes = 0;
5128 // Consume the bytes from data.
5129 data = data.subarray(bytesNeeded, data.length);
5130 if (data.length == 0)
5131 return;
5132 }
5133 }
5134
5135 // 2^6 is 16 * 4.
5136 var nBlocks = data.length >> 6;
5137 if (nBlocks > 0) {
5138 var nBytes = nBlocks * 16 * 4;
5139 var m = byteArray2binb(data.subarray(0, nBytes));
5140 for(var offset = 0; offset < m.length; offset += 16)
5141 processBlock_sha256(m, offset, this.hash, this.W);
5142
5143 data = data.subarray(nBytes, data.length);
5144 }
5145
5146 if (data.length > 0) {
5147 // Save the remainder in the buffer.
5148 this.buffer.set(data);
5149 this.nBufferBytes = data.length;
5150 }
5151}
5152
5153/*
5154 * Finalize the hash and return the result as Uint8Array.
5155 * Only call this once. Return values on subsequent calls are undefined.
5156 */
5157Sha256.prototype.finalize = function() {
5158 var m = byteArray2binb(this.buffer.subarray(0, this.nBufferBytes));
5159 /* append padding */
5160 var l = this.nBufferBytes * 8;
5161 m[l >> 5] |= 0x80 << (24 - l % 32);
5162 m[((l + 64 >> 9) << 4) + 15] = this.nTotalBytes * 8;
5163
5164 for(var offset = 0; offset < m.length; offset += 16)
5165 processBlock_sha256(m, offset, this.hash, this.W);
5166
5167 return Sha256.binb2Uint8Array(this.hash);
5168}
5169
5170/*
5171 * Convert an array of big-endian words to Uint8Array.
5172 */
5173Sha256.binb2Uint8Array = function(input)
5174{
5175 var output = new Uint8Array(input.length * 4);
5176 var iOutput = 0;
5177 for (var i = 0; i < input.length * 32; i += 8)
5178 output[iOutput++] = (input[i>>5] >>> (24 - i % 32)) & 0xFF;
5179 return output;
5180}
Wentao Shang0e291c82012-12-02 23:36:29 -08005181var b64map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
5182var b64pad="=";
5183
5184function hex2b64(h) {
5185 var i;
5186 var c;
5187 var ret = "";
5188 for(i = 0; i+3 <= h.length; i+=3) {
5189 c = parseInt(h.substring(i,i+3),16);
5190 ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63);
5191 }
5192 if(i+1 == h.length) {
5193 c = parseInt(h.substring(i,i+1),16);
5194 ret += b64map.charAt(c << 2);
5195 }
5196 else if(i+2 == h.length) {
5197 c = parseInt(h.substring(i,i+2),16);
5198 ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4);
5199 }
5200 while((ret.length & 3) > 0) ret += b64pad;
5201 return ret;
5202}
5203
5204// convert a base64 string to hex
5205function b64tohex(s) {
5206 var ret = ""
5207 var i;
5208 var k = 0; // b64 state, 0-3
5209 var slop;
5210 for(i = 0; i < s.length; ++i) {
5211 if(s.charAt(i) == b64pad) break;
5212 v = b64map.indexOf(s.charAt(i));
5213 if(v < 0) continue;
5214 if(k == 0) {
5215 ret += int2char(v >> 2);
5216 slop = v & 3;
5217 k = 1;
5218 }
5219 else if(k == 1) {
5220 ret += int2char((slop << 2) | (v >> 4));
5221 slop = v & 0xf;
5222 k = 2;
5223 }
5224 else if(k == 2) {
5225 ret += int2char(slop);
5226 ret += int2char(v >> 2);
5227 slop = v & 3;
5228 k = 3;
5229 }
5230 else {
5231 ret += int2char((slop << 2) | (v >> 4));
5232 ret += int2char(v & 0xf);
5233 k = 0;
5234 }
5235 }
5236 if(k == 1)
5237 ret += int2char(slop << 2);
5238 return ret;
5239}
5240
5241// convert a base64 string to a byte/number array
5242function b64toBA(s) {
5243 //piggyback on b64tohex for now, optimize later
5244 var h = b64tohex(s);
5245 var i;
5246 var a = new Array();
5247 for(i = 0; 2*i < h.length; ++i) {
5248 a[i] = parseInt(h.substring(2*i,2*i+2),16);
5249 }
5250 return a;
5251}
5252// Depends on jsbn.js and rng.js
5253
5254// Version 1.1: support utf-8 encoding in pkcs1pad2
5255
5256// convert a (hex) string to a bignum object
5257function parseBigInt(str,r) {
5258 return new BigInteger(str,r);
5259}
5260
5261function linebrk(s,n) {
5262 var ret = "";
5263 var i = 0;
5264 while(i + n < s.length) {
5265 ret += s.substring(i,i+n) + "\n";
5266 i += n;
5267 }
5268 return ret + s.substring(i,s.length);
5269}
5270
5271function byte2Hex(b) {
5272 if(b < 0x10)
5273 return "0" + b.toString(16);
5274 else
5275 return b.toString(16);
5276}
5277
5278/**
5279 * PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint
5280 * @param s: the string to encode
5281 * @param n: the size in byte
5282 */
5283function pkcs1pad2(s,n) {
5284 if(n < s.length + 11) { // TODO: fix for utf-8
5285 alert("Message too long for RSA");
5286 return null;
5287 }
5288 var ba = new Array();
5289 var i = s.length - 1;
5290 while(i >= 0 && n > 0) {
5291 var c = s.charCodeAt(i--);
5292 if(c < 128) { // encode using utf-8
5293 ba[--n] = c;
5294 }
5295 else if((c > 127) && (c < 2048)) {
5296 ba[--n] = (c & 63) | 128;
5297 ba[--n] = (c >> 6) | 192;
5298 }
5299 else {
5300 ba[--n] = (c & 63) | 128;
5301 ba[--n] = ((c >> 6) & 63) | 128;
5302 ba[--n] = (c >> 12) | 224;
5303 }
5304 }
5305 ba[--n] = 0;
5306 var rng = new SecureRandom();
5307 var x = new Array();
5308 while(n > 2) { // random non-zero pad
5309 x[0] = 0;
5310 while(x[0] == 0) rng.nextBytes(x);
5311 ba[--n] = x[0];
5312 }
5313 ba[--n] = 2;
5314 ba[--n] = 0;
5315 return new BigInteger(ba);
5316}
5317
5318/**
5319 * "empty" RSA key constructor
5320 * @returns {RSAKey}
5321 */
5322function RSAKey() {
5323 this.n = null;
5324 this.e = 0;
5325 this.d = null;
5326 this.p = null;
5327 this.q = null;
5328 this.dmp1 = null;
5329 this.dmq1 = null;
5330 this.coeff = null;
5331}
5332
5333/**
5334 * Set the public key fields N and e from hex strings
5335 * @param N
5336 * @param E
5337 * @returns {RSASetPublic}
5338 */
5339function RSASetPublic(N,E) {
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 }
5344 else
5345 alert("Invalid RSA public key");
5346}
5347
5348/**
5349 * Perform raw public operation on "x": return x^e (mod n)
5350 * @param x
5351 * @returns x^e (mod n)
5352 */
5353function RSADoPublic(x) {
5354 return x.modPowInt(this.e, this.n);
5355}
5356
5357/**
5358 * Return the PKCS#1 RSA encryption of "text" as an even-length hex string
5359 */
5360function RSAEncrypt(text) {
5361 var m = pkcs1pad2(text,(this.n.bitLength()+7)>>3);
5362 if(m == null) return null;
5363 var c = this.doPublic(m);
5364 if(c == null) return null;
5365 var h = c.toString(16);
5366 if((h.length & 1) == 0) return h; else return "0" + h;
5367}
5368
5369// Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string
5370//function RSAEncryptB64(text) {
5371// var h = this.encrypt(text);
5372// if(h) return hex2b64(h); else return null;
5373//}
5374
5375// protected
5376RSAKey.prototype.doPublic = RSADoPublic;
5377
5378// public
5379RSAKey.prototype.setPublic = RSASetPublic;
5380RSAKey.prototype.encrypt = RSAEncrypt;
5381//RSAKey.prototype.encrypt_b64 = RSAEncryptB64;
5382// Depends on rsa.js and jsbn2.js
5383
5384// Version 1.1: support utf-8 decoding in pkcs1unpad2
5385
5386// Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext
5387function pkcs1unpad2(d,n) {
5388 var b = d.toByteArray();
5389 var i = 0;
5390 while(i < b.length && b[i] == 0) ++i;
5391 if(b.length-i != n-1 || b[i] != 2)
5392 return null;
5393 ++i;
5394 while(b[i] != 0)
5395 if(++i >= b.length) return null;
5396 var ret = "";
5397 while(++i < b.length) {
5398 var c = b[i] & 255;
5399 if(c < 128) { // utf-8 decode
5400 ret += String.fromCharCode(c);
5401 }
5402 else if((c > 191) && (c < 224)) {
5403 ret += String.fromCharCode(((c & 31) << 6) | (b[i+1] & 63));
5404 ++i;
5405 }
5406 else {
5407 ret += String.fromCharCode(((c & 15) << 12) | ((b[i+1] & 63) << 6) | (b[i+2] & 63));
5408 i += 2;
5409 }
5410 }
5411 return ret;
5412}
5413
5414// Set the private key fields N, e, and d from hex strings
5415function RSASetPrivate(N,E,D) {
5416 if(N != null && E != null && N.length > 0 && E.length > 0) {
5417 this.n = parseBigInt(N,16);
5418 this.e = parseInt(E,16);
5419 this.d = parseBigInt(D,16);
5420 }
5421 else
5422 alert("Invalid RSA private key");
5423}
5424
5425// Set the private key fields N, e, d and CRT params from hex strings
5426function RSASetPrivateEx(N,E,D,P,Q,DP,DQ,C) {
5427 if(N != null && E != null && N.length > 0 && E.length > 0) {
5428 this.n = parseBigInt(N,16);
5429 this.e = parseInt(E,16);
5430 this.d = parseBigInt(D,16);
5431 this.p = parseBigInt(P,16);
5432 this.q = parseBigInt(Q,16);
5433 this.dmp1 = parseBigInt(DP,16);
5434 this.dmq1 = parseBigInt(DQ,16);
5435 this.coeff = parseBigInt(C,16);
5436 }
5437 else
5438 alert("Invalid RSA private key");
5439}
5440
5441/**
5442 * Generate a new random private key B bits long, using public expt E
5443 */
5444function RSAGenerate(B,E) {
5445 var rng = new SecureRandom();
5446 var qs = B>>1;
5447 this.e = parseInt(E,16);
5448 var ee = new BigInteger(E,16);
5449 for(;;) {
5450 for(;;) {
5451 this.p = new BigInteger(B-qs,1,rng);
5452 if(this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.p.isProbablePrime(10)) break;
5453 }
5454 for(;;) {
5455 this.q = new BigInteger(qs,1,rng);
5456 if(this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.q.isProbablePrime(10)) break;
5457 }
5458 if(this.p.compareTo(this.q) <= 0) {
5459 var t = this.p;
5460 this.p = this.q;
5461 this.q = t;
5462 }
5463 var p1 = this.p.subtract(BigInteger.ONE); // p1 = p - 1
5464 var q1 = this.q.subtract(BigInteger.ONE); // q1 = q - 1
5465 var phi = p1.multiply(q1);
5466 if(phi.gcd(ee).compareTo(BigInteger.ONE) == 0) {
5467 this.n = this.p.multiply(this.q); // this.n = p * q
5468 this.d = ee.modInverse(phi); // this.d =
5469 this.dmp1 = this.d.mod(p1); // this.dmp1 = d mod (p - 1)
5470 this.dmq1 = this.d.mod(q1); // this.dmq1 = d mod (q - 1)
5471 this.coeff = this.q.modInverse(this.p); // this.coeff = (q ^ -1) mod p
5472 break;
5473 }
5474 }
5475}
5476
5477/**
5478 * Perform raw private operation on "x": return x^d (mod n)
5479 * @return x^d (mod n)
5480 */
5481function RSADoPrivate(x) {
5482 if(this.p == null || this.q == null)
5483 return x.modPow(this.d, this.n);
5484
5485 // TODO: re-calculate any missing CRT params
5486 var xp = x.mod(this.p).modPow(this.dmp1, this.p); // xp=cp?
5487 var xq = x.mod(this.q).modPow(this.dmq1, this.q); // xq=cq?
5488
5489 while(xp.compareTo(xq) < 0)
5490 xp = xp.add(this.p);
5491 // NOTE:
5492 // xp.subtract(xq) => cp -cq
5493 // xp.subtract(xq).multiply(this.coeff).mod(this.p) => (cp - cq) * u mod p = h
5494 // xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq) => cq + (h * q) = M
5495 return xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq);
5496}
5497
5498// Return the PKCS#1 RSA decryption of "ctext".
5499// "ctext" is an even-length hex string and the output is a plain string.
5500function RSADecrypt(ctext) {
5501 var c = parseBigInt(ctext, 16);
5502 var m = this.doPrivate(c);
5503 if(m == null) return null;
5504 return pkcs1unpad2(m, (this.n.bitLength()+7)>>3);
5505}
5506
5507// Return the PKCS#1 RSA decryption of "ctext".
5508// "ctext" is a Base64-encoded string and the output is a plain string.
5509//function RSAB64Decrypt(ctext) {
5510// var h = b64tohex(ctext);
5511// if(h) return this.decrypt(h); else return null;
5512//}
5513
5514// protected
5515RSAKey.prototype.doPrivate = RSADoPrivate;
5516
5517// public
5518RSAKey.prototype.setPrivate = RSASetPrivate;
5519RSAKey.prototype.setPrivateEx = RSASetPrivateEx;
5520RSAKey.prototype.generate = RSAGenerate;
5521RSAKey.prototype.decrypt = RSADecrypt;
5522//RSAKey.prototype.b64_decrypt = RSAB64Decrypt;
5523/*! rsapem-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
5524 */
5525//
5526// rsa-pem.js - adding function for reading/writing PKCS#1 PEM private key
5527// to RSAKey class.
5528//
5529// version: 1.1 (2012-May-10)
5530//
5531// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
5532//
5533// This software is licensed under the terms of the MIT License.
5534// http://kjur.github.com/jsrsasign/license/
5535//
5536// The above copyright and license notice shall be
5537// included in all copies or substantial portions of the Software.
5538//
5539//
5540// Depends on:
5541//
5542//
5543//
5544// _RSApem_pemToBase64(sPEM)
5545//
5546// removing PEM header, PEM footer and space characters including
5547// new lines from PEM formatted RSA private key string.
5548//
5549
5550function _rsapem_pemToBase64(sPEMPrivateKey) {
5551 var s = sPEMPrivateKey;
5552 s = s.replace("-----BEGIN RSA PRIVATE KEY-----", "");
5553 s = s.replace("-----END RSA PRIVATE KEY-----", "");
5554 s = s.replace(/[ \n]+/g, "");
5555 return s;
5556}
5557
5558function _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey) {
5559 var a = new Array();
5560 var v1 = ASN1HEX.getStartPosOfV_AtObj(hPrivateKey, 0);
5561 var n1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, v1);
5562 var e1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, n1);
5563 var d1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, e1);
5564 var p1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, d1);
5565 var q1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, p1);
5566 var dp1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, q1);
5567 var dq1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dp1);
5568 var co1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dq1);
5569 a.push(v1, n1, e1, d1, p1, q1, dp1, dq1, co1);
5570 return a;
5571}
5572
5573function _rsapem_getHexValueArrayOfChildrenFromHex(hPrivateKey) {
5574 var posArray = _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey);
5575 var v = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[0]);
5576 var n = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[1]);
5577 var e = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[2]);
5578 var d = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[3]);
5579 var p = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[4]);
5580 var q = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[5]);
5581 var dp = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[6]);
5582 var dq = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[7]);
5583 var co = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[8]);
5584 var a = new Array();
5585 a.push(v, n, e, d, p, q, dp, dq, co);
5586 return a;
5587}
5588
5589/**
5590 * read PKCS#1 private key from a string
5591 * @name readPrivateKeyFromPEMString
5592 * @memberOf RSAKey#
5593 * @function
5594 * @param {String} keyPEM string of PKCS#1 private key.
5595 */
5596function _rsapem_readPrivateKeyFromPEMString(keyPEM) {
5597 var keyB64 = _rsapem_pemToBase64(keyPEM);
5598 var keyHex = b64tohex(keyB64) // depends base64.js
5599 var a = _rsapem_getHexValueArrayOfChildrenFromHex(keyHex);
5600 this.setPrivateEx(a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]);
5601}
5602
5603RSAKey.prototype.readPrivateKeyFromPEMString = _rsapem_readPrivateKeyFromPEMString;
5604/*! rsasign-1.2.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
5605 */
5606//
5607// rsa-sign.js - adding signing functions to RSAKey class.
5608//
5609//
5610// version: 1.2.1 (08 May 2012)
5611//
5612// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
5613//
5614// This software is licensed under the terms of the MIT License.
5615// http://kjur.github.com/jsrsasign/license/
5616//
5617// The above copyright and license notice shall be
5618// included in all copies or substantial portions of the Software.
5619
5620//
5621// Depends on:
5622// function sha1.hex(s) of sha1.js
5623// jsbn.js
5624// jsbn2.js
5625// rsa.js
5626// rsa2.js
5627//
5628
5629// keysize / pmstrlen
5630// 512 / 128
5631// 1024 / 256
5632// 2048 / 512
5633// 4096 / 1024
5634
5635/**
5636 * @property {Dictionary} _RSASIGN_DIHEAD
5637 * @description Array of head part of hexadecimal DigestInfo value for hash algorithms.
5638 * You can add any DigestInfo hash algorith for signing.
5639 * See PKCS#1 v2.1 spec (p38).
5640 */
5641var _RSASIGN_DIHEAD = [];
5642_RSASIGN_DIHEAD['sha1'] = "3021300906052b0e03021a05000414";
5643_RSASIGN_DIHEAD['sha256'] = "3031300d060960864801650304020105000420";
5644_RSASIGN_DIHEAD['sha384'] = "3041300d060960864801650304020205000430";
5645_RSASIGN_DIHEAD['sha512'] = "3051300d060960864801650304020305000440";
5646_RSASIGN_DIHEAD['md2'] = "3020300c06082a864886f70d020205000410";
5647_RSASIGN_DIHEAD['md5'] = "3020300c06082a864886f70d020505000410";
5648_RSASIGN_DIHEAD['ripemd160'] = "3021300906052b2403020105000414";
5649
5650/**
5651 * @property {Dictionary} _RSASIGN_HASHHEXFUNC
5652 * @description Array of functions which calculate hash and returns it as hexadecimal.
5653 * You can add any hash algorithm implementations.
5654 */
5655var _RSASIGN_HASHHEXFUNC = [];
5656_RSASIGN_HASHHEXFUNC['sha1'] = function(s){return hex_sha1(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
5657_RSASIGN_HASHHEXFUNC['sha256'] = function(s){return hex_sha256(s);} // http://pajhome.org.uk/crypt/md5/md5.html
5658_RSASIGN_HASHHEXFUNC['sha512'] = function(s){return hex_sha512(s);} // http://pajhome.org.uk/crypt/md5/md5.html
5659_RSASIGN_HASHHEXFUNC['md5'] = function(s){return hex_md5(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
5660_RSASIGN_HASHHEXFUNC['ripemd160'] = function(s){return hex_rmd160(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
5661
5662//@author axelcdv
5663var _RSASIGN_HASHBYTEFUNC = [];
5664_RSASIGN_HASHBYTEFUNC['sha256'] = function(byteArray){return hex_sha256_from_bytes(byteArray);};
5665
5666//_RSASIGN_HASHHEXFUNC['sha1'] = function(s){return sha1.hex(s);} // http://user1.matsumoto.ne.jp/~goma/js/hash.html
5667//_RSASIGN_HASHHEXFUNC['sha256'] = function(s){return sha256.hex;} // http://user1.matsumoto.ne.jp/~goma/js/hash.html
5668
5669var _RE_HEXDECONLY = new RegExp("");
5670_RE_HEXDECONLY.compile("[^0-9a-f]", "gi");
5671
5672// ========================================================================
5673// Signature Generation
5674// ========================================================================
5675
5676function _rsasign_getHexPaddedDigestInfoForString(s, keySize, hashAlg) {
5677 var pmStrLen = keySize / 4;
5678 var hashFunc = _RSASIGN_HASHHEXFUNC[hashAlg];
5679 var sHashHex = hashFunc(s);
5680
5681 var sHead = "0001";
5682 var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex;
5683 var sMid = "";
5684 var fLen = pmStrLen - sHead.length - sTail.length;
5685 for (var i = 0; i < fLen; i += 2) {
5686 sMid += "ff";
5687 }
5688 sPaddedMessageHex = sHead + sMid + sTail;
5689 return sPaddedMessageHex;
5690}
5691
5692
5693//@author: Meki Cheraoui
5694function _rsasign_getHexPaddedDigestInfoForStringHEX(s, keySize, hashAlg) {
5695 var pmStrLen = keySize / 4;
5696 var hashFunc = _RSASIGN_HASHHEXFUNC[hashAlg];
5697 var sHashHex = hashFunc(s);
5698
5699 var sHead = "0001";
5700 var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex;
5701 var sMid = "";
5702 var fLen = pmStrLen - sHead.length - sTail.length;
5703 for (var i = 0; i < fLen; i += 2) {
5704 sMid += "ff";
5705 }
5706 sPaddedMessageHex = sHead + sMid + sTail;
5707 return sPaddedMessageHex;
5708}
5709
5710/**
5711 * Apply padding, then computes the hash of the given byte array, according to the key size and with the hash algorithm
5712 * @param byteArray (byte[])
5713 * @param keySize (int)
5714 * @param hashAlg the hash algorithm to apply (string)
5715 * @return the hash of byteArray
5716 */
5717function _rsasign_getHexPaddedDigestInfoForByteArray(byteArray, keySize, hashAlg){
5718 var pmStrLen = keySize / 4;
5719 var hashFunc = _RSASIGN_HASHBYTEFUNC[hashAlg];
5720 var sHashHex = hashFunc(byteArray); //returns hex hash
5721
5722 var sHead = "0001";
5723 var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex;
5724 var sMid = "";
5725 var fLen = pmStrLen - sHead.length - sTail.length;
5726 for (var i = 0; i < fLen; i += 2) {
5727 sMid += "ff";
5728 }
5729 sPaddedMessageHex = sHead + sMid + sTail;
5730 return sPaddedMessageHex;
5731}
5732
5733function _zeroPaddingOfSignature(hex, bitLength) {
5734 var s = "";
5735 var nZero = bitLength / 4 - hex.length;
5736 for (var i = 0; i < nZero; i++) {
5737 s = s + "0";
5738 }
5739 return s + hex;
5740}
5741
5742/**
5743 * sign for a message string with RSA private key.<br/>
5744 * @name signString
5745 * @memberOf RSAKey#
5746 * @function
5747 * @param {String} s message string to be signed.
5748 * @param {String} hashAlg hash algorithm name for signing.<br/>
5749 * @return returns hexadecimal string of signature value.
5750 */
5751function _rsasign_signString(s, hashAlg) {
5752 //alert("this.n.bitLength() = " + this.n.bitLength());
5753 var hPM = _rsasign_getHexPaddedDigestInfoForString(s, this.n.bitLength(), hashAlg);
5754 var biPaddedMessage = parseBigInt(hPM, 16);
5755 var biSign = this.doPrivate(biPaddedMessage);
5756 var hexSign = biSign.toString(16);
5757 return _zeroPaddingOfSignature(hexSign, this.n.bitLength());
5758}
5759
5760//@author: ucla-cs
5761function _rsasign_signStringHEX(s, hashAlg) {
5762 //alert("this.n.bitLength() = " + this.n.bitLength());
5763 var hPM = _rsasign_getHexPaddedDigestInfoForString(s, this.n.bitLength(), hashAlg);
5764 var biPaddedMessage = parseBigInt(hPM, 16);
5765 var biSign = this.doPrivate(biPaddedMessage);
5766 var hexSign = biSign.toString(16);
5767 return _zeroPaddingOfSignature(hexSign, this.n.bitLength());
5768}
5769
5770
5771/**
5772 * Sign a message byteArray with an RSA private key
5773 * @name signByteArray
5774 * @memberOf RSAKey#
5775 * @function
5776 * @param {byte[]} byteArray
5777 * @param {Sring} hashAlg the hash algorithm to apply
5778 * @param {RSAKey} rsa key to sign with: hack because the context is lost here
5779 * @return hexadecimal string of signature value
5780 */
5781function _rsasign_signByteArray(byteArray, hashAlg, rsaKey) {
5782 var hPM = _rsasign_getHexPaddedDigestInfoForByteArray(byteArray, rsaKey.n.bitLength(), hashAlg); ///hack because the context is lost here
5783 var biPaddedMessage = parseBigInt(hPM, 16);
5784 var biSign = rsaKey.doPrivate(biPaddedMessage); //hack because the context is lost here
5785 var hexSign = biSign.toString(16);
5786 return _zeroPaddingOfSignature(hexSign, rsaKey.n.bitLength()); //hack because the context is lost here
5787}
5788
5789/**
5790 * Sign a byte array with the Sha-256 algorithm
5791 * @param {byte[]} byteArray
5792 * @return hexadecimal string of signature value
5793 */
5794function _rsasign_signByteArrayWithSHA256(byteArray){
5795 return _rsasign_signByteArray(byteArray, 'sha256', this); //Hack because the context is lost in the next function
5796}
5797
5798
5799function _rsasign_signStringWithSHA1(s) {
5800 return _rsasign_signString(s, 'sha1');
5801}
5802
5803function _rsasign_signStringWithSHA256(s) {
5804 return _rsasign_signString(s, 'sha256');
5805}
5806
5807// ========================================================================
5808// Signature Verification
5809// ========================================================================
5810
5811function _rsasign_getDecryptSignatureBI(biSig, hN, hE) {
5812 var rsa = new RSAKey();
5813 rsa.setPublic(hN, hE);
5814 var biDecryptedSig = rsa.doPublic(biSig);
5815 return biDecryptedSig;
5816}
5817
5818function _rsasign_getHexDigestInfoFromSig(biSig, hN, hE) {
5819 var biDecryptedSig = _rsasign_getDecryptSignatureBI(biSig, hN, hE);
5820 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
5821 return hDigestInfo;
5822}
5823
5824function _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo) {
5825 for (var algName in _RSASIGN_DIHEAD) {
5826 var head = _RSASIGN_DIHEAD[algName];
5827 var len = head.length;
5828 if (hDigestInfo.substring(0, len) == head) {
5829 var a = [algName, hDigestInfo.substring(len)];
5830 return a;
5831 }
5832 }
5833 return [];
5834}
5835
5836function _rsasign_verifySignatureWithArgs(sMsg, biSig, hN, hE) {
5837 var hDigestInfo = _rsasign_getHexDigestInfoFromSig(biSig, hN, hE);
5838 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
5839 if (digestInfoAry.length == 0) return false;
5840 var algName = digestInfoAry[0];
5841 var diHashValue = digestInfoAry[1];
5842 var ff = _RSASIGN_HASHHEXFUNC[algName];
5843 var msgHashValue = ff(sMsg);
5844 return (diHashValue == msgHashValue);
5845}
5846
5847function _rsasign_verifyHexSignatureForMessage(hSig, sMsg) {
5848 var biSig = parseBigInt(hSig, 16);
5849 var result = _rsasign_verifySignatureWithArgs(sMsg, biSig,
5850 this.n.toString(16),
5851 this.e.toString(16));
5852 return result;
5853}
5854
5855/**
5856 * verifies a sigature for a message string with RSA public key.<br/>
5857 * @name verifyString
5858 * @memberOf RSAKey#
5859 * @function
5860 * @param {String} sMsg message string to be verified.
5861 * @param {String} hSig hexadecimal string of siganture.<br/>
5862 * non-hexadecimal charactors including new lines will be ignored.
5863 * @return returns 1 if valid, otherwise 0
5864 */
5865function _rsasign_verifyString(sMsg, hSig) {
5866 hSig = hSig.replace(_RE_HEXDECONLY, '');
5867
5868 if(LOG>3)console.log('n is '+this.n);
5869 if(LOG>3)console.log('e is '+this.e);
5870
5871 if (hSig.length != this.n.bitLength() / 4) return 0;
5872 hSig = hSig.replace(/[ \n]+/g, "");
5873 var biSig = parseBigInt(hSig, 16);
5874 var biDecryptedSig = this.doPublic(biSig);
5875 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
5876 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
5877
5878 if (digestInfoAry.length == 0) return false;
5879 var algName = digestInfoAry[0];
5880 var diHashValue = digestInfoAry[1];
5881 var ff = _RSASIGN_HASHHEXFUNC[algName];
5882 var msgHashValue = ff(sMsg);
5883 return (diHashValue == msgHashValue);
5884}
5885
5886/**
5887 * verifies a sigature for a message byte array with RSA public key.<br/>
5888 * @name verifyByteArray
5889 * @memberOf RSAKey#
5890 * @function
5891 * @param {byte[]} byteArray message byte array to be verified.
5892 * @param {String} hSig hexadecimal string of signature.<br/>
5893 * non-hexadecimal charactors including new lines will be ignored.
5894 * @return returns 1 if valid, otherwise 0
5895 */
5896function _rsasign_verifyByteArray(byteArray, hSig) {
5897 hSig = hSig.replace(_RE_HEXDECONLY, '');
5898
5899 if(LOG>3)console.log('n is '+this.n);
5900 if(LOG>3)console.log('e is '+this.e);
5901
5902 if (hSig.length != this.n.bitLength() / 4) return 0;
5903 hSig = hSig.replace(/[ \n]+/g, "");
5904 var biSig = parseBigInt(hSig, 16);
5905 var biDecryptedSig = this.doPublic(biSig);
5906 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
5907 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
5908
5909 if (digestInfoAry.length == 0) return false;
5910 var algName = digestInfoAry[0];
5911 var diHashValue = digestInfoAry[1];
5912 var ff = _RSASIGN_HASHBYTEFUNC[algName];
5913 var msgHashValue = ff(byteArray);
5914 return (diHashValue == msgHashValue);
5915}
5916
5917RSAKey.prototype.signString = _rsasign_signString;
5918
5919RSAKey.prototype.signByteArray = _rsasign_signByteArray; //@author axelcdv
5920RSAKey.prototype.signByteArrayWithSHA256 = _rsasign_signByteArrayWithSHA256; //@author axelcdv
5921
5922RSAKey.prototype.signStringWithSHA1 = _rsasign_signStringWithSHA1;
5923RSAKey.prototype.signStringWithSHA256 = _rsasign_signStringWithSHA256;
5924RSAKey.prototype.sign = _rsasign_signString;
5925RSAKey.prototype.signWithSHA1 = _rsasign_signStringWithSHA1;
5926RSAKey.prototype.signWithSHA256 = _rsasign_signStringWithSHA256;
5927
5928
5929/*RSAKey.prototype.signStringHEX = _rsasign_signStringHEX;
5930RSAKey.prototype.signStringWithSHA1HEX = _rsasign_signStringWithSHA1HEX;
5931RSAKey.prototype.signStringWithSHA256HEX = _rsasign_signStringWithSHA256HEX;
5932RSAKey.prototype.signHEX = _rsasign_signStringHEX;
5933RSAKey.prototype.signWithSHA1HEX = _rsasign_signStringWithSHA1HEX;
5934RSAKey.prototype.signWithSHA256HEX = _rsasign_signStringWithSHA256HEX;
5935*/
5936
5937RSAKey.prototype.verifyByteArray = _rsasign_verifyByteArray;
5938RSAKey.prototype.verifyString = _rsasign_verifyString;
5939RSAKey.prototype.verifyHexSignatureForMessage = _rsasign_verifyHexSignatureForMessage;
5940RSAKey.prototype.verify = _rsasign_verifyString;
5941RSAKey.prototype.verifyHexSignatureForByteArrayMessage = _rsasign_verifyHexSignatureForMessage;
5942
5943/*
5944RSAKey.prototype.verifyStringHEX = _rsasign_verifyStringHEX;
5945RSAKey.prototype.verifyHexSignatureForMessageHEX = _rsasign_verifyHexSignatureForMessageHEX;
5946RSAKey.prototype.verifyHEX = _rsasign_verifyStringHEX;
5947RSAKey.prototype.verifyHexSignatureForByteArrayMessageHEX = _rsasign_verifyHexSignatureForMessageHEX;
5948*/
5949
5950
5951/**
5952 * @name RSAKey
5953 * @class
5954 * @description Tom Wu's RSA Key class and extension
5955 */
5956/*! asn1hex-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
5957 */
5958//
5959// asn1hex.js - Hexadecimal represented ASN.1 string library
5960//
5961// version: 1.1 (09-May-2012)
5962//
5963// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
5964//
5965// This software is licensed under the terms of the MIT License.
5966// http://kjur.github.com/jsrsasign/license/
5967//
5968// The above copyright and license notice shall be
5969// included in all copies or substantial portions of the Software.
5970//
5971// Depends on:
5972//
5973
5974// MEMO:
5975// f('3082025b02...', 2) ... 82025b ... 3bytes
5976// f('020100', 2) ... 01 ... 1byte
5977// f('0203001...', 2) ... 03 ... 1byte
5978// f('02818003...', 2) ... 8180 ... 2bytes
5979// f('3080....0000', 2) ... 80 ... -1
5980//
5981// Requirements:
5982// - ASN.1 type octet length MUST be 1.
5983// (i.e. ASN.1 primitives like SET, SEQUENCE, INTEGER, OCTETSTRING ...)
5984// -
5985/**
5986 * get byte length for ASN.1 L(length) bytes
5987 * @name getByteLengthOfL_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 byte length for ASN.1 L(length) bytes
5993 */
5994function _asnhex_getByteLengthOfL_AtObj(s, pos) {
5995 if (s.substring(pos + 2, pos + 3) != '8') return 1;
5996 var i = parseInt(s.substring(pos + 3, pos + 4));
5997 if (i == 0) return -1; // length octet '80' indefinite length
5998 if (0 < i && i < 10) return i + 1; // including '8?' octet;
5999 return -2; // malformed format
6000}
6001
6002
6003/**
6004 * get hexadecimal string for ASN.1 L(length) bytes
6005 * @name getHexOfL_AtObj
6006 * @memberOf ASN1HEX
6007 * @function
6008 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6009 * @param {Number} pos string index
6010 * @return {String} hexadecimal string for ASN.1 L(length) bytes
6011 */
6012function _asnhex_getHexOfL_AtObj(s, pos) {
6013 var len = _asnhex_getByteLengthOfL_AtObj(s, pos);
6014 if (len < 1) return '';
6015 return s.substring(pos + 2, pos + 2 + len * 2);
6016}
6017
6018//
6019// getting ASN.1 length value at the position 'idx' of
6020// hexa decimal string 's'.
6021//
6022// f('3082025b02...', 0) ... 82025b ... ???
6023// f('020100', 0) ... 01 ... 1
6024// f('0203001...', 0) ... 03 ... 3
6025// f('02818003...', 0) ... 8180 ... 128
6026/**
6027 * get integer value of ASN.1 length for ASN.1 data
6028 * @name getIntOfL_AtObj
6029 * @memberOf ASN1HEX
6030 * @function
6031 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6032 * @param {Number} pos string index
6033 * @return ASN.1 L(length) integer value
6034 */
6035function _asnhex_getIntOfL_AtObj(s, pos) {
6036 var hLength = _asnhex_getHexOfL_AtObj(s, pos);
6037 if (hLength == '') return -1;
6038 var bi;
6039 if (parseInt(hLength.substring(0, 1)) < 8) {
6040 bi = parseBigInt(hLength, 16);
6041 } else {
6042 bi = parseBigInt(hLength.substring(2), 16);
6043 }
6044 return bi.intValue();
6045}
6046
6047/**
6048 * get ASN.1 value starting string position for ASN.1 object refered by index 'idx'.
6049 * @name getStartPosOfV_AtObj
6050 * @memberOf ASN1HEX
6051 * @function
6052 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6053 * @param {Number} pos string index
6054 */
6055function _asnhex_getStartPosOfV_AtObj(s, pos) {
6056 var l_len = _asnhex_getByteLengthOfL_AtObj(s, pos);
6057 if (l_len < 0) return l_len;
6058 return pos + (l_len + 1) * 2;
6059}
6060
6061/**
6062 * get hexadecimal string of ASN.1 V(value)
6063 * @name getHexOfV_AtObj
6064 * @memberOf ASN1HEX
6065 * @function
6066 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6067 * @param {Number} pos string index
6068 * @return {String} hexadecimal string of ASN.1 value.
6069 */
6070function _asnhex_getHexOfV_AtObj(s, pos) {
6071 var pos1 = _asnhex_getStartPosOfV_AtObj(s, pos);
6072 var len = _asnhex_getIntOfL_AtObj(s, pos);
6073 return s.substring(pos1, pos1 + len * 2);
6074}
6075
6076/**
6077 * get hexadecimal string of ASN.1 TLV at
6078 * @name getHexOfTLV_AtObj
6079 * @memberOf ASN1HEX
6080 * @function
6081 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6082 * @param {Number} pos string index
6083 * @return {String} hexadecimal string of ASN.1 TLV.
6084 * @since 1.1
6085 */
6086function _asnhex_getHexOfTLV_AtObj(s, pos) {
6087 var hT = s.substr(pos, 2);
6088 var hL = _asnhex_getHexOfL_AtObj(s, pos);
6089 var hV = _asnhex_getHexOfV_AtObj(s, pos);
6090 return hT + hL + hV;
6091}
6092
6093/**
6094 * get next sibling starting index for ASN.1 object string
6095 * @name getPosOfNextSibling_AtObj
6096 * @memberOf ASN1HEX
6097 * @function
6098 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6099 * @param {Number} pos string index
6100 * @return next sibling starting index for ASN.1 object string
6101 */
6102function _asnhex_getPosOfNextSibling_AtObj(s, pos) {
6103 var pos1 = _asnhex_getStartPosOfV_AtObj(s, pos);
6104 var len = _asnhex_getIntOfL_AtObj(s, pos);
6105 return pos1 + len * 2;
6106}
6107
6108/**
6109 * get array of indexes of child ASN.1 objects
6110 * @name getPosArrayOfChildren_AtObj
6111 * @memberOf ASN1HEX
6112 * @function
6113 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6114 * @param {Number} start string index of ASN.1 object
6115 * @return {Array of Number} array of indexes for childen of ASN.1 objects
6116 */
6117function _asnhex_getPosArrayOfChildren_AtObj(h, pos) {
6118 var a = new Array();
6119 var p0 = _asnhex_getStartPosOfV_AtObj(h, pos);
6120 a.push(p0);
6121
6122 var len = _asnhex_getIntOfL_AtObj(h, pos);
6123 var p = p0;
6124 var k = 0;
6125 while (1) {
6126 var pNext = _asnhex_getPosOfNextSibling_AtObj(h, p);
6127 if (pNext == null || (pNext - p0 >= (len * 2))) break;
6128 if (k >= 200) break;
6129
6130 a.push(pNext);
6131 p = pNext;
6132
6133 k++;
6134 }
6135
6136 return a;
6137}
6138
6139/**
6140 * get string index of nth child object of ASN.1 object refered by h, idx
6141 * @name getNthChildIndex_AtObj
6142 * @memberOf ASN1HEX
6143 * @function
6144 * @param {String} h hexadecimal string of ASN.1 DER encoded data
6145 * @param {Number} idx start string index of ASN.1 object
6146 * @param {Number} nth for child
6147 * @return {Number} string index of nth child.
6148 * @since 1.1
6149 */
6150function _asnhex_getNthChildIndex_AtObj(h, idx, nth) {
6151 var a = _asnhex_getPosArrayOfChildren_AtObj(h, idx);
6152 return a[nth];
6153}
6154
6155// ========== decendant methods ==============================
6156
6157/**
6158 * get string index of nth child object of ASN.1 object refered by h, idx
6159 * @name getDecendantIndexByNthList
6160 * @memberOf ASN1HEX
6161 * @function
6162 * @param {String} h hexadecimal string of ASN.1 DER encoded data
6163 * @param {Number} currentIndex start string index of ASN.1 object
6164 * @param {Array of Number} nthList array list of nth
6165 * @return {Number} string index refered by nthList
6166 * @since 1.1
6167 */
6168function _asnhex_getDecendantIndexByNthList(h, currentIndex, nthList) {
6169 if (nthList.length == 0) {
6170 return currentIndex;
6171 }
6172 var firstNth = nthList.shift();
6173 var a = _asnhex_getPosArrayOfChildren_AtObj(h, currentIndex);
6174 return _asnhex_getDecendantIndexByNthList(h, a[firstNth], nthList);
6175}
6176
6177/**
6178 * get hexadecimal string of ASN.1 TLV refered by current index and nth index list.
6179 * @name getDecendantHexTLVByNthList
6180 * @memberOf ASN1HEX
6181 * @function
6182 * @param {String} h hexadecimal string of ASN.1 DER encoded data
6183 * @param {Number} currentIndex start string index of ASN.1 object
6184 * @param {Array of Number} nthList array list of nth
6185 * @return {Number} hexadecimal string of ASN.1 TLV refered by nthList
6186 * @since 1.1
6187 */
6188function _asnhex_getDecendantHexTLVByNthList(h, currentIndex, nthList) {
6189 var idx = _asnhex_getDecendantIndexByNthList(h, currentIndex, nthList);
6190 return _asnhex_getHexOfTLV_AtObj(h, idx);
6191}
6192
6193/**
6194 * get hexadecimal string of ASN.1 V refered by current index and nth index list.
6195 * @name getDecendantHexVByNthList
6196 * @memberOf ASN1HEX
6197 * @function
6198 * @param {String} h hexadecimal string of ASN.1 DER encoded data
6199 * @param {Number} currentIndex start string index of ASN.1 object
6200 * @param {Array of Number} nthList array list of nth
6201 * @return {Number} hexadecimal string of ASN.1 V refered by nthList
6202 * @since 1.1
6203 */
6204function _asnhex_getDecendantHexVByNthList(h, currentIndex, nthList) {
6205 var idx = _asnhex_getDecendantIndexByNthList(h, currentIndex, nthList);
6206 return _asnhex_getHexOfV_AtObj(h, idx);
6207}
6208
6209// ========== class definition ==============================
6210
6211/**
6212 * ASN.1 DER encoded hexadecimal string utility class
6213 * @class ASN.1 DER encoded hexadecimal string utility class
6214 * @author Kenji Urushima
6215 * @version 1.1 (09 May 2012)
6216 * @see <a href="http://kjur.github.com/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a>
6217 * @since 1.1
6218 */
6219function ASN1HEX() {
6220 return ASN1HEX;
6221}
6222
6223ASN1HEX.getByteLengthOfL_AtObj = _asnhex_getByteLengthOfL_AtObj;
6224ASN1HEX.getHexOfL_AtObj = _asnhex_getHexOfL_AtObj;
6225ASN1HEX.getIntOfL_AtObj = _asnhex_getIntOfL_AtObj;
6226ASN1HEX.getStartPosOfV_AtObj = _asnhex_getStartPosOfV_AtObj;
6227ASN1HEX.getHexOfV_AtObj = _asnhex_getHexOfV_AtObj;
6228ASN1HEX.getHexOfTLV_AtObj = _asnhex_getHexOfTLV_AtObj;
6229ASN1HEX.getPosOfNextSibling_AtObj = _asnhex_getPosOfNextSibling_AtObj;
6230ASN1HEX.getPosArrayOfChildren_AtObj = _asnhex_getPosArrayOfChildren_AtObj;
6231ASN1HEX.getNthChildIndex_AtObj = _asnhex_getNthChildIndex_AtObj;
6232ASN1HEX.getDecendantIndexByNthList = _asnhex_getDecendantIndexByNthList;
6233ASN1HEX.getDecendantHexVByNthList = _asnhex_getDecendantHexVByNthList;
6234ASN1HEX.getDecendantHexTLVByNthList = _asnhex_getDecendantHexTLVByNthList;
Jeff Thompson1a338f82012-12-29 17:07:04 -08006235/*! x509-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
6236 */
6237//
6238// x509.js - X509 class to read subject public key from certificate.
6239//
6240// version: 1.1 (10-May-2012)
6241//
6242// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
6243//
6244// This software is licensed under the terms of the MIT License.
6245// http://kjur.github.com/jsrsasign/license
6246//
6247// The above copyright and license notice shall be
6248// included in all copies or substantial portions of the Software.
6249//
6250
6251// Depends:
6252// base64.js
6253// rsa.js
6254// asn1hex.js
6255
6256function _x509_pemToBase64(sCertPEM) {
6257 var s = sCertPEM;
6258 s = s.replace("-----BEGIN CERTIFICATE-----", "");
6259 s = s.replace("-----END CERTIFICATE-----", "");
6260 s = s.replace(/[ \n]+/g, "");
6261 return s;
6262}
6263
6264function _x509_pemToHex(sCertPEM) {
6265 var b64Cert = _x509_pemToBase64(sCertPEM);
6266 var hCert = b64tohex(b64Cert);
6267 return hCert;
6268}
6269
6270function _x509_getHexTbsCertificateFromCert(hCert) {
6271 var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0);
6272 return pTbsCert;
6273}
6274
6275// NOTE: privateKeyUsagePeriod field of X509v2 not supported.
6276// NOTE: v1 and v3 supported
6277function _x509_getSubjectPublicKeyInfoPosFromCertHex(hCert) {
6278 var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0);
6279 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pTbsCert);
6280 if (a.length < 1) return -1;
6281 if (hCert.substring(a[0], a[0] + 10) == "a003020102") { // v3
6282 if (a.length < 6) return -1;
6283 return a[6];
6284 } else {
6285 if (a.length < 5) return -1;
6286 return a[5];
6287 }
6288}
6289
6290// NOTE: Without BITSTRING encapsulation.
6291// If pInfo is supplied, it is the position in hCert of the SubjectPublicKeyInfo.
6292function _x509_getSubjectPublicKeyPosFromCertHex(hCert, pInfo) {
6293 if (pInfo == null)
6294 pInfo = _x509_getSubjectPublicKeyInfoPosFromCertHex(hCert);
6295 if (pInfo == -1) return -1;
6296 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pInfo);
6297
6298 if (a.length != 2) return -1;
6299 var pBitString = a[1];
6300 if (hCert.substring(pBitString, pBitString + 2) != '03') return -1;
6301 var pBitStringV = ASN1HEX.getStartPosOfV_AtObj(hCert, pBitString);
6302
6303 if (hCert.substring(pBitStringV, pBitStringV + 2) != '00') return -1;
6304 return pBitStringV + 2;
6305}
6306
6307// If p is supplied, it is the public key position in hCert.
6308function _x509_getPublicKeyHexArrayFromCertHex(hCert, p) {
6309 if (p == null)
6310 p = _x509_getSubjectPublicKeyPosFromCertHex(hCert);
6311 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, p);
6312 //var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a[3]);
6313 if(LOG>4){
6314 console.log('a is now');
6315 console.log(a);
6316 }
6317
6318 //if (a.length != 2) return [];
6319 if (a.length < 2) return [];
6320
6321 var hN = ASN1HEX.getHexOfV_AtObj(hCert, a[0]);
6322 var hE = ASN1HEX.getHexOfV_AtObj(hCert, a[1]);
6323 if (hN != null && hE != null) {
6324 return [hN, hE];
6325 } else {
6326 return [];
6327 }
6328}
6329
6330function _x509_getPublicKeyHexArrayFromCertPEM(sCertPEM) {
6331 var hCert = _x509_pemToHex(sCertPEM);
6332 var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
6333 return a;
6334}
6335
6336// ===== get basic fields from hex =====================================
6337/**
6338 * get hexadecimal string of serialNumber field of certificate.<br/>
6339 * @name getSerialNumberHex
6340 * @memberOf X509#
6341 * @function
6342 */
6343function _x509_getSerialNumberHex() {
6344 return ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 1]);
6345}
6346
6347/**
6348 * get hexadecimal string of issuer field of certificate.<br/>
6349 * @name getIssuerHex
6350 * @memberOf X509#
6351 * @function
6352 */
6353function _x509_getIssuerHex() {
6354 return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]);
6355}
6356
6357/**
6358 * get string of issuer field of certificate.<br/>
6359 * @name getIssuerString
6360 * @memberOf X509#
6361 * @function
6362 */
6363function _x509_getIssuerString() {
6364 return _x509_hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]));
6365}
6366
6367/**
6368 * get hexadecimal string of subject field of certificate.<br/>
6369 * @name getSubjectHex
6370 * @memberOf X509#
6371 * @function
6372 */
6373function _x509_getSubjectHex() {
6374 return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]);
6375}
6376
6377/**
6378 * get string of subject field of certificate.<br/>
6379 * @name getSubjectString
6380 * @memberOf X509#
6381 * @function
6382 */
6383function _x509_getSubjectString() {
6384 return _x509_hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]));
6385}
6386
6387/**
6388 * get notBefore field string of certificate.<br/>
6389 * @name getNotBefore
6390 * @memberOf X509#
6391 * @function
6392 */
6393function _x509_getNotBefore() {
6394 var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 0]);
6395 s = s.replace(/(..)/g, "%$1");
6396 s = decodeURIComponent(s);
6397 return s;
6398}
6399
6400/**
6401 * get notAfter field string of certificate.<br/>
6402 * @name getNotAfter
6403 * @memberOf X509#
6404 * @function
6405 */
6406function _x509_getNotAfter() {
6407 var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 1]);
6408 s = s.replace(/(..)/g, "%$1");
6409 s = decodeURIComponent(s);
6410 return s;
6411}
6412
6413// ===== read certificate =====================================
6414
6415_x509_DN_ATTRHEX = {
6416 "0603550406": "C",
6417 "060355040a": "O",
6418 "060355040b": "OU",
6419 "0603550403": "CN",
6420 "0603550405": "SN",
6421 "0603550408": "ST",
6422 "0603550407": "L" };
6423
6424function _x509_hex2dn(hDN) {
6425 var s = "";
6426 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hDN, 0);
6427 for (var i = 0; i < a.length; i++) {
6428 var hRDN = ASN1HEX.getHexOfTLV_AtObj(hDN, a[i]);
6429 s = s + "/" + _x509_hex2rdn(hRDN);
6430 }
6431 return s;
6432}
6433
6434function _x509_hex2rdn(hRDN) {
6435 var hType = ASN1HEX.getDecendantHexTLVByNthList(hRDN, 0, [0, 0]);
6436 var hValue = ASN1HEX.getDecendantHexVByNthList(hRDN, 0, [0, 1]);
6437 var type = "";
6438 try { type = _x509_DN_ATTRHEX[hType]; } catch (ex) { type = hType; }
6439 hValue = hValue.replace(/(..)/g, "%$1");
6440 var value = decodeURIComponent(hValue);
6441 return type + "=" + value;
6442}
6443
6444// ===== read certificate =====================================
6445
6446
6447/**
6448 * read PEM formatted X.509 certificate from string.<br/>
6449 * @name readCertPEM
6450 * @memberOf X509#
6451 * @function
6452 * @param {String} sCertPEM string for PEM formatted X.509 certificate
6453 */
6454function _x509_readCertPEM(sCertPEM) {
6455 var hCert = _x509_pemToHex(sCertPEM);
6456 var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
6457 if(LOG>4){
6458 console.log('HEX VALUE IS ' + hCert);
6459 console.log('type of a' + typeof a);
6460 console.log('a VALUE IS ');
6461 console.log(a);
6462 console.log('a[0] VALUE IS ' + a[0]);
6463 console.log('a[1] VALUE IS ' + a[1]);
6464 }
6465 var rsa = new RSAKey();
6466 rsa.setPublic(a[0], a[1]);
6467 this.subjectPublicKeyRSA = rsa;
6468 this.subjectPublicKeyRSA_hN = a[0];
6469 this.subjectPublicKeyRSA_hE = a[1];
6470 this.hex = hCert;
6471}
6472
6473/**
6474 * read hex formatted X.509 certificate from string.
6475 * @name readCertHex
6476 * @memberOf X509#
6477 * @function
6478 * @param {String} hCert string for hex formatted X.509 certificate
6479 */
6480function _x509_readCertHex(hCert) {
6481 hCert = hCert.toLowerCase();
6482 var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
6483 var rsa = new RSAKey();
6484 rsa.setPublic(a[0], a[1]);
6485 this.subjectPublicKeyRSA = rsa;
6486 this.subjectPublicKeyRSA_hN = a[0];
6487 this.subjectPublicKeyRSA_hE = a[1];
6488 this.hex = hCert;
6489}
6490
6491function _x509_readCertPEMWithoutRSAInit(sCertPEM) {
6492 var hCert = _x509_pemToHex(sCertPEM);
6493 var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
6494 this.subjectPublicKeyRSA.setPublic(a[0], a[1]);
6495 this.subjectPublicKeyRSA_hN = a[0];
6496 this.subjectPublicKeyRSA_hE = a[1];
6497 this.hex = hCert;
6498}
6499
6500/**
6501 * X.509 certificate class.<br/>
6502 * @class X.509 certificate class
6503 * @property {RSAKey} subjectPublicKeyRSA Tom Wu's RSAKey object
6504 * @property {String} subjectPublicKeyRSA_hN hexadecimal string for modulus of RSA public key
6505 * @property {String} subjectPublicKeyRSA_hE hexadecimal string for public exponent of RSA public key
6506 * @property {String} hex hexacedimal string for X.509 certificate.
6507 * @author Kenji Urushima
6508 * @version 1.0.1 (08 May 2012)
6509 * @see <a href="http://kjur.github.com/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a>
6510 */
6511function X509() {
6512 this.subjectPublicKeyRSA = null;
6513 this.subjectPublicKeyRSA_hN = null;
6514 this.subjectPublicKeyRSA_hE = null;
6515 this.hex = null;
6516}
6517
6518X509.prototype.readCertPEM = _x509_readCertPEM;
6519X509.prototype.readCertHex = _x509_readCertHex;
6520X509.prototype.readCertPEMWithoutRSAInit = _x509_readCertPEMWithoutRSAInit;
6521X509.prototype.getSerialNumberHex = _x509_getSerialNumberHex;
6522X509.prototype.getIssuerHex = _x509_getIssuerHex;
6523X509.prototype.getSubjectHex = _x509_getSubjectHex;
6524X509.prototype.getIssuerString = _x509_getIssuerString;
6525X509.prototype.getSubjectString = _x509_getSubjectString;
6526X509.prototype.getNotBefore = _x509_getNotBefore;
6527X509.prototype.getNotAfter = _x509_getNotAfter;
6528
Wentao Shang0e291c82012-12-02 23:36:29 -08006529// Copyright (c) 2005 Tom Wu
6530// All Rights Reserved.
6531// See "LICENSE" for details.
6532
6533// Basic JavaScript BN library - subset useful for RSA encryption.
6534
6535// Bits per digit
6536var dbits;
6537
6538// JavaScript engine analysis
6539var canary = 0xdeadbeefcafe;
6540var j_lm = ((canary&0xffffff)==0xefcafe);
6541
6542// (public) Constructor
6543function BigInteger(a,b,c) {
6544 if(a != null)
6545 if("number" == typeof a) this.fromNumber(a,b,c);
6546 else if(b == null && "string" != typeof a) this.fromString(a,256);
6547 else this.fromString(a,b);
6548}
6549
6550// return new, unset BigInteger
6551function nbi() { return new BigInteger(null); }
6552
6553// am: Compute w_j += (x*this_i), propagate carries,
6554// c is initial carry, returns final carry.
6555// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
6556// We need to select the fastest one that works in this environment.
6557
6558// am1: use a single mult and divide to get the high bits,
6559// max digit bits should be 26 because
6560// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
6561function am1(i,x,w,j,c,n) {
6562 while(--n >= 0) {
6563 var v = x*this[i++]+w[j]+c;
6564 c = Math.floor(v/0x4000000);
6565 w[j++] = v&0x3ffffff;
6566 }
6567 return c;
6568}
6569// am2 avoids a big mult-and-extract completely.
6570// Max digit bits should be <= 30 because we do bitwise ops
6571// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
6572function am2(i,x,w,j,c,n) {
6573 var xl = x&0x7fff, xh = x>>15;
6574 while(--n >= 0) {
6575 var l = this[i]&0x7fff;
6576 var h = this[i++]>>15;
6577 var m = xh*l+h*xl;
6578 l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff);
6579 c = (l>>>30)+(m>>>15)+xh*h+(c>>>30);
6580 w[j++] = l&0x3fffffff;
6581 }
6582 return c;
6583}
6584// Alternately, set max digit bits to 28 since some
6585// browsers slow down when dealing with 32-bit numbers.
6586function am3(i,x,w,j,c,n) {
6587 var xl = x&0x3fff, xh = x>>14;
6588 while(--n >= 0) {
6589 var l = this[i]&0x3fff;
6590 var h = this[i++]>>14;
6591 var m = xh*l+h*xl;
6592 l = xl*l+((m&0x3fff)<<14)+w[j]+c;
6593 c = (l>>28)+(m>>14)+xh*h;
6594 w[j++] = l&0xfffffff;
6595 }
6596 return c;
6597}
6598if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
6599 BigInteger.prototype.am = am2;
6600 dbits = 30;
6601}
6602else if(j_lm && (navigator.appName != "Netscape")) {
6603 BigInteger.prototype.am = am1;
6604 dbits = 26;
6605}
6606else { // Mozilla/Netscape seems to prefer am3
6607 BigInteger.prototype.am = am3;
6608 dbits = 28;
6609}
6610
6611BigInteger.prototype.DB = dbits;
6612BigInteger.prototype.DM = ((1<<dbits)-1);
6613BigInteger.prototype.DV = (1<<dbits);
6614
6615var BI_FP = 52;
6616BigInteger.prototype.FV = Math.pow(2,BI_FP);
6617BigInteger.prototype.F1 = BI_FP-dbits;
6618BigInteger.prototype.F2 = 2*dbits-BI_FP;
6619
6620// Digit conversions
6621var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
6622var BI_RC = new Array();
6623var rr,vv;
6624rr = "0".charCodeAt(0);
6625for(vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
6626rr = "a".charCodeAt(0);
6627for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
6628rr = "A".charCodeAt(0);
6629for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
6630
6631function int2char(n) { return BI_RM.charAt(n); }
6632function intAt(s,i) {
6633 var c = BI_RC[s.charCodeAt(i)];
6634 return (c==null)?-1:c;
6635}
6636
6637// (protected) copy this to r
6638function bnpCopyTo(r) {
6639 for(var i = this.t-1; i >= 0; --i) r[i] = this[i];
6640 r.t = this.t;
6641 r.s = this.s;
6642}
6643
6644// (protected) set from integer value x, -DV <= x < DV
6645function bnpFromInt(x) {
6646 this.t = 1;
6647 this.s = (x<0)?-1:0;
6648 if(x > 0) this[0] = x;
6649 else if(x < -1) this[0] = x+DV;
6650 else this.t = 0;
6651}
6652
6653// return bigint initialized to value
6654function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
6655
6656// (protected) set from string and radix
6657function bnpFromString(s,b) {
6658 var k;
6659 if(b == 16) k = 4;
6660 else if(b == 8) k = 3;
6661 else if(b == 256) k = 8; // byte array
6662 else if(b == 2) k = 1;
6663 else if(b == 32) k = 5;
6664 else if(b == 4) k = 2;
6665 else { this.fromRadix(s,b); return; }
6666 this.t = 0;
6667 this.s = 0;
6668 var i = s.length, mi = false, sh = 0;
6669 while(--i >= 0) {
6670 var x = (k==8)?s[i]&0xff:intAt(s,i);
6671 if(x < 0) {
6672 if(s.charAt(i) == "-") mi = true;
6673 continue;
6674 }
6675 mi = false;
6676 if(sh == 0)
6677 this[this.t++] = x;
6678 else if(sh+k > this.DB) {
6679 this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<<sh;
6680 this[this.t++] = (x>>(this.DB-sh));
6681 }
6682 else
6683 this[this.t-1] |= x<<sh;
6684 sh += k;
6685 if(sh >= this.DB) sh -= this.DB;
6686 }
6687 if(k == 8 && (s[0]&0x80) != 0) {
6688 this.s = -1;
6689 if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh;
6690 }
6691 this.clamp();
6692 if(mi) BigInteger.ZERO.subTo(this,this);
6693}
6694
6695// (protected) clamp off excess high words
6696function bnpClamp() {
6697 var c = this.s&this.DM;
6698 while(this.t > 0 && this[this.t-1] == c) --this.t;
6699}
6700
6701// (public) return string representation in given radix
6702function bnToString(b) {
6703 if(this.s < 0) return "-"+this.negate().toString(b);
6704 var k;
6705 if(b == 16) k = 4;
6706 else if(b == 8) k = 3;
6707 else if(b == 2) k = 1;
6708 else if(b == 32) k = 5;
6709 else if(b == 4) k = 2;
6710 else return this.toRadix(b);
6711 var km = (1<<k)-1, d, m = false, r = "", i = this.t;
6712 var p = this.DB-(i*this.DB)%k;
6713 if(i-- > 0) {
6714 if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); }
6715 while(i >= 0) {
6716 if(p < k) {
6717 d = (this[i]&((1<<p)-1))<<(k-p);
6718 d |= this[--i]>>(p+=this.DB-k);
6719 }
6720 else {
6721 d = (this[i]>>(p-=k))&km;
6722 if(p <= 0) { p += this.DB; --i; }
6723 }
6724 if(d > 0) m = true;
6725 if(m) r += int2char(d);
6726 }
6727 }
6728 return m?r:"0";
6729}
6730
6731// (public) -this
6732function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }
6733
6734// (public) |this|
6735function bnAbs() { return (this.s<0)?this.negate():this; }
6736
6737// (public) return + if this > a, - if this < a, 0 if equal
6738function bnCompareTo(a) {
6739 var r = this.s-a.s;
6740 if(r != 0) return r;
6741 var i = this.t;
6742 r = i-a.t;
6743 if(r != 0) return r;
6744 while(--i >= 0) if((r=this[i]-a[i]) != 0) return r;
6745 return 0;
6746}
6747
6748// returns bit length of the integer x
6749function nbits(x) {
6750 var r = 1, t;
6751 if((t=x>>>16) != 0) { x = t; r += 16; }
6752 if((t=x>>8) != 0) { x = t; r += 8; }
6753 if((t=x>>4) != 0) { x = t; r += 4; }
6754 if((t=x>>2) != 0) { x = t; r += 2; }
6755 if((t=x>>1) != 0) { x = t; r += 1; }
6756 return r;
6757}
6758
6759// (public) return the number of bits in "this"
6760function bnBitLength() {
6761 if(this.t <= 0) return 0;
6762 return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM));
6763}
6764
6765// (protected) r = this << n*DB
6766function bnpDLShiftTo(n,r) {
6767 var i;
6768 for(i = this.t-1; i >= 0; --i) r[i+n] = this[i];
6769 for(i = n-1; i >= 0; --i) r[i] = 0;
6770 r.t = this.t+n;
6771 r.s = this.s;
6772}
6773
6774// (protected) r = this >> n*DB
6775function bnpDRShiftTo(n,r) {
6776 for(var i = n; i < this.t; ++i) r[i-n] = this[i];
6777 r.t = Math.max(this.t-n,0);
6778 r.s = this.s;
6779}
6780
6781// (protected) r = this << n
6782function bnpLShiftTo(n,r) {
6783 var bs = n%this.DB;
6784 var cbs = this.DB-bs;
6785 var bm = (1<<cbs)-1;
6786 var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i;
6787 for(i = this.t-1; i >= 0; --i) {
6788 r[i+ds+1] = (this[i]>>cbs)|c;
6789 c = (this[i]&bm)<<bs;
6790 }
6791 for(i = ds-1; i >= 0; --i) r[i] = 0;
6792 r[ds] = c;
6793 r.t = this.t+ds+1;
6794 r.s = this.s;
6795 r.clamp();
6796}
6797
6798// (protected) r = this >> n
6799function bnpRShiftTo(n,r) {
6800 r.s = this.s;
6801 var ds = Math.floor(n/this.DB);
6802 if(ds >= this.t) { r.t = 0; return; }
6803 var bs = n%this.DB;
6804 var cbs = this.DB-bs;
6805 var bm = (1<<bs)-1;
6806 r[0] = this[ds]>>bs;
6807 for(var i = ds+1; i < this.t; ++i) {
6808 r[i-ds-1] |= (this[i]&bm)<<cbs;
6809 r[i-ds] = this[i]>>bs;
6810 }
6811 if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs;
6812 r.t = this.t-ds;
6813 r.clamp();
6814}
6815
6816// (protected) r = this - a
6817function bnpSubTo(a,r) {
6818 var i = 0, c = 0, m = Math.min(a.t,this.t);
6819 while(i < m) {
6820 c += this[i]-a[i];
6821 r[i++] = c&this.DM;
6822 c >>= this.DB;
6823 }
6824 if(a.t < this.t) {
6825 c -= a.s;
6826 while(i < this.t) {
6827 c += this[i];
6828 r[i++] = c&this.DM;
6829 c >>= this.DB;
6830 }
6831 c += this.s;
6832 }
6833 else {
6834 c += this.s;
6835 while(i < a.t) {
6836 c -= a[i];
6837 r[i++] = c&this.DM;
6838 c >>= this.DB;
6839 }
6840 c -= a.s;
6841 }
6842 r.s = (c<0)?-1:0;
6843 if(c < -1) r[i++] = this.DV+c;
6844 else if(c > 0) r[i++] = c;
6845 r.t = i;
6846 r.clamp();
6847}
6848
6849// (protected) r = this * a, r != this,a (HAC 14.12)
6850// "this" should be the larger one if appropriate.
6851function bnpMultiplyTo(a,r) {
6852 var x = this.abs(), y = a.abs();
6853 var i = x.t;
6854 r.t = i+y.t;
6855 while(--i >= 0) r[i] = 0;
6856 for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t);
6857 r.s = 0;
6858 r.clamp();
6859 if(this.s != a.s) BigInteger.ZERO.subTo(r,r);
6860}
6861
6862// (protected) r = this^2, r != this (HAC 14.16)
6863function bnpSquareTo(r) {
6864 var x = this.abs();
6865 var i = r.t = 2*x.t;
6866 while(--i >= 0) r[i] = 0;
6867 for(i = 0; i < x.t-1; ++i) {
6868 var c = x.am(i,x[i],r,2*i,0,1);
6869 if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) {
6870 r[i+x.t] -= x.DV;
6871 r[i+x.t+1] = 1;
6872 }
6873 }
6874 if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1);
6875 r.s = 0;
6876 r.clamp();
6877}
6878
6879// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
6880// r != q, this != m. q or r may be null.
6881function bnpDivRemTo(m,q,r) {
6882 var pm = m.abs();
6883 if(pm.t <= 0) return;
6884 var pt = this.abs();
6885 if(pt.t < pm.t) {
6886 if(q != null) q.fromInt(0);
6887 if(r != null) this.copyTo(r);
6888 return;
6889 }
6890 if(r == null) r = nbi();
6891 var y = nbi(), ts = this.s, ms = m.s;
6892 var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus
6893 if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); }
6894 else { pm.copyTo(y); pt.copyTo(r); }
6895 var ys = y.t;
6896 var y0 = y[ys-1];
6897 if(y0 == 0) return;
6898 var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0);
6899 var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
6900 var i = r.t, j = i-ys, t = (q==null)?nbi():q;
6901 y.dlShiftTo(j,t);
6902 if(r.compareTo(t) >= 0) {
6903 r[r.t++] = 1;
6904 r.subTo(t,r);
6905 }
6906 BigInteger.ONE.dlShiftTo(ys,t);
6907 t.subTo(y,y); // "negative" y so we can replace sub with am later
6908 while(y.t < ys) y[y.t++] = 0;
6909 while(--j >= 0) {
6910 // Estimate quotient digit
6911 var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);
6912 if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out
6913 y.dlShiftTo(j,t);
6914 r.subTo(t,r);
6915 while(r[i] < --qd) r.subTo(t,r);
6916 }
6917 }
6918 if(q != null) {
6919 r.drShiftTo(ys,q);
6920 if(ts != ms) BigInteger.ZERO.subTo(q,q);
6921 }
6922 r.t = ys;
6923 r.clamp();
6924 if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder
6925 if(ts < 0) BigInteger.ZERO.subTo(r,r);
6926}
6927
6928// (public) this mod a
6929function bnMod(a) {
6930 var r = nbi();
6931 this.abs().divRemTo(a,null,r);
6932 if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r);
6933 return r;
6934}
6935
6936// Modular reduction using "classic" algorithm
6937function Classic(m) { this.m = m; }
6938function cConvert(x) {
6939 if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
6940 else return x;
6941}
6942function cRevert(x) { return x; }
6943function cReduce(x) { x.divRemTo(this.m,null,x); }
6944function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
6945function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
6946
6947Classic.prototype.convert = cConvert;
6948Classic.prototype.revert = cRevert;
6949Classic.prototype.reduce = cReduce;
6950Classic.prototype.mulTo = cMulTo;
6951Classic.prototype.sqrTo = cSqrTo;
6952
6953// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
6954// justification:
6955// xy == 1 (mod m)
6956// xy = 1+km
6957// xy(2-xy) = (1+km)(1-km)
6958// x[y(2-xy)] = 1-k^2m^2
6959// x[y(2-xy)] == 1 (mod m^2)
6960// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
6961// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
6962// JS multiply "overflows" differently from C/C++, so care is needed here.
6963function bnpInvDigit() {
6964 if(this.t < 1) return 0;
6965 var x = this[0];
6966 if((x&1) == 0) return 0;
6967 var y = x&3; // y == 1/x mod 2^2
6968 y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4
6969 y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8
6970 y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16
6971 // last step - calculate inverse mod DV directly;
6972 // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
6973 y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits
6974 // we really want the negative inverse, and -DV < y < DV
6975 return (y>0)?this.DV-y:-y;
6976}
6977
6978// Montgomery reduction
6979function Montgomery(m) {
6980 this.m = m;
6981 this.mp = m.invDigit();
6982 this.mpl = this.mp&0x7fff;
6983 this.mph = this.mp>>15;
6984 this.um = (1<<(m.DB-15))-1;
6985 this.mt2 = 2*m.t;
6986}
6987
6988// xR mod m
6989function montConvert(x) {
6990 var r = nbi();
6991 x.abs().dlShiftTo(this.m.t,r);
6992 r.divRemTo(this.m,null,r);
6993 if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r);
6994 return r;
6995}
6996
6997// x/R mod m
6998function montRevert(x) {
6999 var r = nbi();
7000 x.copyTo(r);
7001 this.reduce(r);
7002 return r;
7003}
7004
7005// x = x/R mod m (HAC 14.32)
7006function montReduce(x) {
7007 while(x.t <= this.mt2) // pad x so am has enough room later
7008 x[x.t++] = 0;
7009 for(var i = 0; i < this.m.t; ++i) {
7010 // faster way of calculating u0 = x[i]*mp mod DV
7011 var j = x[i]&0x7fff;
7012 var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM;
7013 // use am to combine the multiply-shift-add into one call
7014 j = i+this.m.t;
7015 x[j] += this.m.am(0,u0,x,i,0,this.m.t);
7016 // propagate carry
7017 while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; }
7018 }
7019 x.clamp();
7020 x.drShiftTo(this.m.t,x);
7021 if(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
7022}
7023
7024// r = "x^2/R mod m"; x != r
7025function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
7026
7027// r = "xy/R mod m"; x,y != r
7028function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
7029
7030Montgomery.prototype.convert = montConvert;
7031Montgomery.prototype.revert = montRevert;
7032Montgomery.prototype.reduce = montReduce;
7033Montgomery.prototype.mulTo = montMulTo;
7034Montgomery.prototype.sqrTo = montSqrTo;
7035
7036// (protected) true iff this is even
7037function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; }
7038
7039// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
7040function bnpExp(e,z) {
7041 if(e > 0xffffffff || e < 1) return BigInteger.ONE;
7042 var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1;
7043 g.copyTo(r);
7044 while(--i >= 0) {
7045 z.sqrTo(r,r2);
7046 if((e&(1<<i)) > 0) z.mulTo(r2,g,r);
7047 else { var t = r; r = r2; r2 = t; }
7048 }
7049 return z.revert(r);
7050}
7051
7052// (public) this^e % m, 0 <= e < 2^32
7053function bnModPowInt(e,m) {
7054 var z;
7055 if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
7056 return this.exp(e,z);
7057}
7058
7059// protected
7060BigInteger.prototype.copyTo = bnpCopyTo;
7061BigInteger.prototype.fromInt = bnpFromInt;
7062BigInteger.prototype.fromString = bnpFromString;
7063BigInteger.prototype.clamp = bnpClamp;
7064BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
7065BigInteger.prototype.drShiftTo = bnpDRShiftTo;
7066BigInteger.prototype.lShiftTo = bnpLShiftTo;
7067BigInteger.prototype.rShiftTo = bnpRShiftTo;
7068BigInteger.prototype.subTo = bnpSubTo;
7069BigInteger.prototype.multiplyTo = bnpMultiplyTo;
7070BigInteger.prototype.squareTo = bnpSquareTo;
7071BigInteger.prototype.divRemTo = bnpDivRemTo;
7072BigInteger.prototype.invDigit = bnpInvDigit;
7073BigInteger.prototype.isEven = bnpIsEven;
7074BigInteger.prototype.exp = bnpExp;
7075
7076// public
7077BigInteger.prototype.toString = bnToString;
7078BigInteger.prototype.negate = bnNegate;
7079BigInteger.prototype.abs = bnAbs;
7080BigInteger.prototype.compareTo = bnCompareTo;
7081BigInteger.prototype.bitLength = bnBitLength;
7082BigInteger.prototype.mod = bnMod;
7083BigInteger.prototype.modPowInt = bnModPowInt;
7084
7085// "constants"
7086BigInteger.ZERO = nbv(0);
7087BigInteger.ONE = nbv(1);
7088// Copyright (c) 2005-2009 Tom Wu
7089// All Rights Reserved.
7090// See "LICENSE" for details.
7091
7092// Extended JavaScript BN functions, required for RSA private ops.
7093
7094// Version 1.1: new BigInteger("0", 10) returns "proper" zero
7095
7096// (public)
7097function bnClone() { var r = nbi(); this.copyTo(r); return r; }
7098
7099// (public) return value as integer
7100function bnIntValue() {
7101 if(this.s < 0) {
7102 if(this.t == 1) return this[0]-this.DV;
7103 else if(this.t == 0) return -1;
7104 }
7105 else if(this.t == 1) return this[0];
7106 else if(this.t == 0) return 0;
7107 // assumes 16 < DB < 32
7108 return ((this[1]&((1<<(32-this.DB))-1))<<this.DB)|this[0];
7109}
7110
7111// (public) return value as byte
7112function bnByteValue() { return (this.t==0)?this.s:(this[0]<<24)>>24; }
7113
7114// (public) return value as short (assumes DB>=16)
7115function bnShortValue() { return (this.t==0)?this.s:(this[0]<<16)>>16; }
7116
7117// (protected) return x s.t. r^x < DV
7118function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); }
7119
7120// (public) 0 if this == 0, 1 if this > 0
7121function bnSigNum() {
7122 if(this.s < 0) return -1;
7123 else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
7124 else return 1;
7125}
7126
7127// (protected) convert to radix string
7128function bnpToRadix(b) {
7129 if(b == null) b = 10;
7130 if(this.signum() == 0 || b < 2 || b > 36) return "0";
7131 var cs = this.chunkSize(b);
7132 var a = Math.pow(b,cs);
7133 var d = nbv(a), y = nbi(), z = nbi(), r = "";
7134 this.divRemTo(d,y,z);
7135 while(y.signum() > 0) {
7136 r = (a+z.intValue()).toString(b).substr(1) + r;
7137 y.divRemTo(d,y,z);
7138 }
7139 return z.intValue().toString(b) + r;
7140}
7141
7142// (protected) convert from radix string
7143function bnpFromRadix(s,b) {
7144 this.fromInt(0);
7145 if(b == null) b = 10;
7146 var cs = this.chunkSize(b);
7147 var d = Math.pow(b,cs), mi = false, j = 0, w = 0;
7148 for(var i = 0; i < s.length; ++i) {
7149 var x = intAt(s,i);
7150 if(x < 0) {
7151 if(s.charAt(i) == "-" && this.signum() == 0) mi = true;
7152 continue;
7153 }
7154 w = b*w+x;
7155 if(++j >= cs) {
7156 this.dMultiply(d);
7157 this.dAddOffset(w,0);
7158 j = 0;
7159 w = 0;
7160 }
7161 }
7162 if(j > 0) {
7163 this.dMultiply(Math.pow(b,j));
7164 this.dAddOffset(w,0);
7165 }
7166 if(mi) BigInteger.ZERO.subTo(this,this);
7167}
7168
7169// (protected) alternate constructor
7170function bnpFromNumber(a,b,c) {
7171 if("number" == typeof b) {
7172 // new BigInteger(int,int,RNG)
7173 if(a < 2) this.fromInt(1);
7174 else {
7175 this.fromNumber(a,c);
7176 if(!this.testBit(a-1)) // force MSB set
7177 this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this);
7178 if(this.isEven()) this.dAddOffset(1,0); // force odd
7179 while(!this.isProbablePrime(b)) {
7180 this.dAddOffset(2,0);
7181 if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this);
7182 }
7183 }
7184 }
7185 else {
7186 // new BigInteger(int,RNG)
7187 var x = new Array(), t = a&7;
7188 x.length = (a>>3)+1;
7189 b.nextBytes(x);
7190 if(t > 0) x[0] &= ((1<<t)-1); else x[0] = 0;
7191 this.fromString(x,256);
7192 }
7193}
7194
7195// (public) convert to bigendian byte array
7196function bnToByteArray() {
7197 var i = this.t, r = new Array();
7198 r[0] = this.s;
7199 var p = this.DB-(i*this.DB)%8, d, k = 0;
7200 if(i-- > 0) {
7201 if(p < this.DB && (d = this[i]>>p) != (this.s&this.DM)>>p)
7202 r[k++] = d|(this.s<<(this.DB-p));
7203 while(i >= 0) {
7204 if(p < 8) {
7205 d = (this[i]&((1<<p)-1))<<(8-p);
7206 d |= this[--i]>>(p+=this.DB-8);
7207 }
7208 else {
7209 d = (this[i]>>(p-=8))&0xff;
7210 if(p <= 0) { p += this.DB; --i; }
7211 }
7212 if((d&0x80) != 0) d |= -256;
7213 if(k == 0 && (this.s&0x80) != (d&0x80)) ++k;
7214 if(k > 0 || d != this.s) r[k++] = d;
7215 }
7216 }
7217 return r;
7218}
7219
7220function bnEquals(a) { return(this.compareTo(a)==0); }
7221function bnMin(a) { return(this.compareTo(a)<0)?this:a; }
7222function bnMax(a) { return(this.compareTo(a)>0)?this:a; }
7223
7224// (protected) r = this op a (bitwise)
7225function bnpBitwiseTo(a,op,r) {
7226 var i, f, m = Math.min(a.t,this.t);
7227 for(i = 0; i < m; ++i) r[i] = op(this[i],a[i]);
7228 if(a.t < this.t) {
7229 f = a.s&this.DM;
7230 for(i = m; i < this.t; ++i) r[i] = op(this[i],f);
7231 r.t = this.t;
7232 }
7233 else {
7234 f = this.s&this.DM;
7235 for(i = m; i < a.t; ++i) r[i] = op(f,a[i]);
7236 r.t = a.t;
7237 }
7238 r.s = op(this.s,a.s);
7239 r.clamp();
7240}
7241
7242// (public) this & a
7243function op_and(x,y) { return x&y; }
7244function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; }
7245
7246// (public) this | a
7247function op_or(x,y) { return x|y; }
7248function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; }
7249
7250// (public) this ^ a
7251function op_xor(x,y) { return x^y; }
7252function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; }
7253
7254// (public) this & ~a
7255function op_andnot(x,y) { return x&~y; }
7256function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; }
7257
7258// (public) ~this
7259function bnNot() {
7260 var r = nbi();
7261 for(var i = 0; i < this.t; ++i) r[i] = this.DM&~this[i];
7262 r.t = this.t;
7263 r.s = ~this.s;
7264 return r;
7265}
7266
7267// (public) this << n
7268function bnShiftLeft(n) {
7269 var r = nbi();
7270 if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r);
7271 return r;
7272}
7273
7274// (public) this >> n
7275function bnShiftRight(n) {
7276 var r = nbi();
7277 if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r);
7278 return r;
7279}
7280
7281// return index of lowest 1-bit in x, x < 2^31
7282function lbit(x) {
7283 if(x == 0) return -1;
7284 var r = 0;
7285 if((x&0xffff) == 0) { x >>= 16; r += 16; }
7286 if((x&0xff) == 0) { x >>= 8; r += 8; }
7287 if((x&0xf) == 0) { x >>= 4; r += 4; }
7288 if((x&3) == 0) { x >>= 2; r += 2; }
7289 if((x&1) == 0) ++r;
7290 return r;
7291}
7292
7293// (public) returns index of lowest 1-bit (or -1 if none)
7294function bnGetLowestSetBit() {
7295 for(var i = 0; i < this.t; ++i)
7296 if(this[i] != 0) return i*this.DB+lbit(this[i]);
7297 if(this.s < 0) return this.t*this.DB;
7298 return -1;
7299}
7300
7301// return number of 1 bits in x
7302function cbit(x) {
7303 var r = 0;
7304 while(x != 0) { x &= x-1; ++r; }
7305 return r;
7306}
7307
7308// (public) return number of set bits
7309function bnBitCount() {
7310 var r = 0, x = this.s&this.DM;
7311 for(var i = 0; i < this.t; ++i) r += cbit(this[i]^x);
7312 return r;
7313}
7314
7315// (public) true iff nth bit is set
7316function bnTestBit(n) {
7317 var j = Math.floor(n/this.DB);
7318 if(j >= this.t) return(this.s!=0);
7319 return((this[j]&(1<<(n%this.DB)))!=0);
7320}
7321
7322// (protected) this op (1<<n)
7323function bnpChangeBit(n,op) {
7324 var r = BigInteger.ONE.shiftLeft(n);
7325 this.bitwiseTo(r,op,r);
7326 return r;
7327}
7328
7329// (public) this | (1<<n)
7330function bnSetBit(n) { return this.changeBit(n,op_or); }
7331
7332// (public) this & ~(1<<n)
7333function bnClearBit(n) { return this.changeBit(n,op_andnot); }
7334
7335// (public) this ^ (1<<n)
7336function bnFlipBit(n) { return this.changeBit(n,op_xor); }
7337
7338// (protected) r = this + a
7339function bnpAddTo(a,r) {
7340 var i = 0, c = 0, m = Math.min(a.t,this.t);
7341 while(i < m) {
7342 c += this[i]+a[i];
7343 r[i++] = c&this.DM;
7344 c >>= this.DB;
7345 }
7346 if(a.t < this.t) {
7347 c += a.s;
7348 while(i < this.t) {
7349 c += this[i];
7350 r[i++] = c&this.DM;
7351 c >>= this.DB;
7352 }
7353 c += this.s;
7354 }
7355 else {
7356 c += this.s;
7357 while(i < a.t) {
7358 c += a[i];
7359 r[i++] = c&this.DM;
7360 c >>= this.DB;
7361 }
7362 c += a.s;
7363 }
7364 r.s = (c<0)?-1:0;
7365 if(c > 0) r[i++] = c;
7366 else if(c < -1) r[i++] = this.DV+c;
7367 r.t = i;
7368 r.clamp();
7369}
7370
7371// (public) this + a
7372function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; }
7373
7374// (public) this - a
7375function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; }
7376
7377// (public) this * a
7378function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; }
7379
7380// (public) this / a
7381function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; }
7382
7383// (public) this % a
7384function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; }
7385
7386// (public) [this/a,this%a]
7387function bnDivideAndRemainder(a) {
7388 var q = nbi(), r = nbi();
7389 this.divRemTo(a,q,r);
7390 return new Array(q,r);
7391}
7392
7393// (protected) this *= n, this >= 0, 1 < n < DV
7394function bnpDMultiply(n) {
7395 this[this.t] = this.am(0,n-1,this,0,0,this.t);
7396 ++this.t;
7397 this.clamp();
7398}
7399
7400// (protected) this += n << w words, this >= 0
7401function bnpDAddOffset(n,w) {
7402 if(n == 0) return;
7403 while(this.t <= w) this[this.t++] = 0;
7404 this[w] += n;
7405 while(this[w] >= this.DV) {
7406 this[w] -= this.DV;
7407 if(++w >= this.t) this[this.t++] = 0;
7408 ++this[w];
7409 }
7410}
7411
7412// A "null" reducer
7413function NullExp() {}
7414function nNop(x) { return x; }
7415function nMulTo(x,y,r) { x.multiplyTo(y,r); }
7416function nSqrTo(x,r) { x.squareTo(r); }
7417
7418NullExp.prototype.convert = nNop;
7419NullExp.prototype.revert = nNop;
7420NullExp.prototype.mulTo = nMulTo;
7421NullExp.prototype.sqrTo = nSqrTo;
7422
7423// (public) this^e
7424function bnPow(e) { return this.exp(e,new NullExp()); }
7425
7426// (protected) r = lower n words of "this * a", a.t <= n
7427// "this" should be the larger one if appropriate.
7428function bnpMultiplyLowerTo(a,n,r) {
7429 var i = Math.min(this.t+a.t,n);
7430 r.s = 0; // assumes a,this >= 0
7431 r.t = i;
7432 while(i > 0) r[--i] = 0;
7433 var j;
7434 for(j = r.t-this.t; i < j; ++i) r[i+this.t] = this.am(0,a[i],r,i,0,this.t);
7435 for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a[i],r,i,0,n-i);
7436 r.clamp();
7437}
7438
7439// (protected) r = "this * a" without lower n words, n > 0
7440// "this" should be the larger one if appropriate.
7441function bnpMultiplyUpperTo(a,n,r) {
7442 --n;
7443 var i = r.t = this.t+a.t-n;
7444 r.s = 0; // assumes a,this >= 0
7445 while(--i >= 0) r[i] = 0;
7446 for(i = Math.max(n-this.t,0); i < a.t; ++i)
7447 r[this.t+i-n] = this.am(n-i,a[i],r,0,0,this.t+i-n);
7448 r.clamp();
7449 r.drShiftTo(1,r);
7450}
7451
7452// Barrett modular reduction
7453function Barrett(m) {
7454 // setup Barrett
7455 this.r2 = nbi();
7456 this.q3 = nbi();
7457 BigInteger.ONE.dlShiftTo(2*m.t,this.r2);
7458 this.mu = this.r2.divide(m);
7459 this.m = m;
7460}
7461
7462function barrettConvert(x) {
7463 if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m);
7464 else if(x.compareTo(this.m) < 0) return x;
7465 else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; }
7466}
7467
7468function barrettRevert(x) { return x; }
7469
7470// x = x mod m (HAC 14.42)
7471function barrettReduce(x) {
7472 x.drShiftTo(this.m.t-1,this.r2);
7473 if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); }
7474 this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3);
7475 this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);
7476 while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1);
7477 x.subTo(this.r2,x);
7478 while(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
7479}
7480
7481// r = x^2 mod m; x != r
7482function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
7483
7484// r = x*y mod m; x,y != r
7485function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
7486
7487Barrett.prototype.convert = barrettConvert;
7488Barrett.prototype.revert = barrettRevert;
7489Barrett.prototype.reduce = barrettReduce;
7490Barrett.prototype.mulTo = barrettMulTo;
7491Barrett.prototype.sqrTo = barrettSqrTo;
7492
7493// (public) this^e % m (HAC 14.85)
7494function bnModPow(e,m) {
7495 var i = e.bitLength(), k, r = nbv(1), z;
7496 if(i <= 0) return r;
7497 else if(i < 18) k = 1;
7498 else if(i < 48) k = 3;
7499 else if(i < 144) k = 4;
7500 else if(i < 768) k = 5;
7501 else k = 6;
7502 if(i < 8)
7503 z = new Classic(m);
7504 else if(m.isEven())
7505 z = new Barrett(m);
7506 else
7507 z = new Montgomery(m);
7508
7509 // precomputation
7510 var g = new Array(), n = 3, k1 = k-1, km = (1<<k)-1;
7511 g[1] = z.convert(this);
7512 if(k > 1) {
7513 var g2 = nbi();
7514 z.sqrTo(g[1],g2);
7515 while(n <= km) {
7516 g[n] = nbi();
7517 z.mulTo(g2,g[n-2],g[n]);
7518 n += 2;
7519 }
7520 }
7521
7522 var j = e.t-1, w, is1 = true, r2 = nbi(), t;
7523 i = nbits(e[j])-1;
7524 while(j >= 0) {
7525 if(i >= k1) w = (e[j]>>(i-k1))&km;
7526 else {
7527 w = (e[j]&((1<<(i+1))-1))<<(k1-i);
7528 if(j > 0) w |= e[j-1]>>(this.DB+i-k1);
7529 }
7530
7531 n = k;
7532 while((w&1) == 0) { w >>= 1; --n; }
7533 if((i -= n) < 0) { i += this.DB; --j; }
7534 if(is1) { // ret == 1, don't bother squaring or multiplying it
7535 g[w].copyTo(r);
7536 is1 = false;
7537 }
7538 else {
7539 while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; }
7540 if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; }
7541 z.mulTo(r2,g[w],r);
7542 }
7543
7544 while(j >= 0 && (e[j]&(1<<i)) == 0) {
7545 z.sqrTo(r,r2); t = r; r = r2; r2 = t;
7546 if(--i < 0) { i = this.DB-1; --j; }
7547 }
7548 }
7549 return z.revert(r);
7550}
7551
7552// (public) gcd(this,a) (HAC 14.54)
7553function bnGCD(a) {
7554 var x = (this.s<0)?this.negate():this.clone();
7555 var y = (a.s<0)?a.negate():a.clone();
7556 if(x.compareTo(y) < 0) { var t = x; x = y; y = t; }
7557 var i = x.getLowestSetBit(), g = y.getLowestSetBit();
7558 if(g < 0) return x;
7559 if(i < g) g = i;
7560 if(g > 0) {
7561 x.rShiftTo(g,x);
7562 y.rShiftTo(g,y);
7563 }
7564 while(x.signum() > 0) {
7565 if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x);
7566 if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y);
7567 if(x.compareTo(y) >= 0) {
7568 x.subTo(y,x);
7569 x.rShiftTo(1,x);
7570 }
7571 else {
7572 y.subTo(x,y);
7573 y.rShiftTo(1,y);
7574 }
7575 }
7576 if(g > 0) y.lShiftTo(g,y);
7577 return y;
7578}
7579
7580// (protected) this % n, n < 2^26
7581function bnpModInt(n) {
7582 if(n <= 0) return 0;
7583 var d = this.DV%n, r = (this.s<0)?n-1:0;
7584 if(this.t > 0)
7585 if(d == 0) r = this[0]%n;
7586 else for(var i = this.t-1; i >= 0; --i) r = (d*r+this[i])%n;
7587 return r;
7588}
7589
7590// (public) 1/this % m (HAC 14.61)
7591function bnModInverse(m) {
7592 var ac = m.isEven();
7593 if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
7594 var u = m.clone(), v = this.clone();
7595 var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
7596 while(u.signum() != 0) {
7597 while(u.isEven()) {
7598 u.rShiftTo(1,u);
7599 if(ac) {
7600 if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); }
7601 a.rShiftTo(1,a);
7602 }
7603 else if(!b.isEven()) b.subTo(m,b);
7604 b.rShiftTo(1,b);
7605 }
7606 while(v.isEven()) {
7607 v.rShiftTo(1,v);
7608 if(ac) {
7609 if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); }
7610 c.rShiftTo(1,c);
7611 }
7612 else if(!d.isEven()) d.subTo(m,d);
7613 d.rShiftTo(1,d);
7614 }
7615 if(u.compareTo(v) >= 0) {
7616 u.subTo(v,u);
7617 if(ac) a.subTo(c,a);
7618 b.subTo(d,b);
7619 }
7620 else {
7621 v.subTo(u,v);
7622 if(ac) c.subTo(a,c);
7623 d.subTo(b,d);
7624 }
7625 }
7626 if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
7627 if(d.compareTo(m) >= 0) return d.subtract(m);
7628 if(d.signum() < 0) d.addTo(m,d); else return d;
7629 if(d.signum() < 0) return d.add(m); else return d;
7630}
7631
7632var 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];
7633var lplim = (1<<26)/lowprimes[lowprimes.length-1];
7634
7635// (public) test primality with certainty >= 1-.5^t
7636function bnIsProbablePrime(t) {
7637 var i, x = this.abs();
7638 if(x.t == 1 && x[0] <= lowprimes[lowprimes.length-1]) {
7639 for(i = 0; i < lowprimes.length; ++i)
7640 if(x[0] == lowprimes[i]) return true;
7641 return false;
7642 }
7643 if(x.isEven()) return false;
7644 i = 1;
7645 while(i < lowprimes.length) {
7646 var m = lowprimes[i], j = i+1;
7647 while(j < lowprimes.length && m < lplim) m *= lowprimes[j++];
7648 m = x.modInt(m);
7649 while(i < j) if(m%lowprimes[i++] == 0) return false;
7650 }
7651 return x.millerRabin(t);
7652}
7653
7654// (protected) true if probably prime (HAC 4.24, Miller-Rabin)
7655function bnpMillerRabin(t) {
7656 var n1 = this.subtract(BigInteger.ONE);
7657 var k = n1.getLowestSetBit();
7658 if(k <= 0) return false;
7659 var r = n1.shiftRight(k);
7660 t = (t+1)>>1;
7661 if(t > lowprimes.length) t = lowprimes.length;
7662 var a = nbi();
7663 for(var i = 0; i < t; ++i) {
7664 a.fromInt(lowprimes[i]);
7665 var y = a.modPow(r,this);
7666 if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {
7667 var j = 1;
7668 while(j++ < k && y.compareTo(n1) != 0) {
7669 y = y.modPowInt(2,this);
7670 if(y.compareTo(BigInteger.ONE) == 0) return false;
7671 }
7672 if(y.compareTo(n1) != 0) return false;
7673 }
7674 }
7675 return true;
7676}
7677
7678// protected
7679BigInteger.prototype.chunkSize = bnpChunkSize;
7680BigInteger.prototype.toRadix = bnpToRadix;
7681BigInteger.prototype.fromRadix = bnpFromRadix;
7682BigInteger.prototype.fromNumber = bnpFromNumber;
7683BigInteger.prototype.bitwiseTo = bnpBitwiseTo;
7684BigInteger.prototype.changeBit = bnpChangeBit;
7685BigInteger.prototype.addTo = bnpAddTo;
7686BigInteger.prototype.dMultiply = bnpDMultiply;
7687BigInteger.prototype.dAddOffset = bnpDAddOffset;
7688BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo;
7689BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo;
7690BigInteger.prototype.modInt = bnpModInt;
7691BigInteger.prototype.millerRabin = bnpMillerRabin;
7692
7693// public
7694BigInteger.prototype.clone = bnClone;
7695BigInteger.prototype.intValue = bnIntValue;
7696BigInteger.prototype.byteValue = bnByteValue;
7697BigInteger.prototype.shortValue = bnShortValue;
7698BigInteger.prototype.signum = bnSigNum;
7699BigInteger.prototype.toByteArray = bnToByteArray;
7700BigInteger.prototype.equals = bnEquals;
7701BigInteger.prototype.min = bnMin;
7702BigInteger.prototype.max = bnMax;
7703BigInteger.prototype.and = bnAnd;
7704BigInteger.prototype.or = bnOr;
7705BigInteger.prototype.xor = bnXor;
7706BigInteger.prototype.andNot = bnAndNot;
7707BigInteger.prototype.not = bnNot;
7708BigInteger.prototype.shiftLeft = bnShiftLeft;
7709BigInteger.prototype.shiftRight = bnShiftRight;
7710BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit;
7711BigInteger.prototype.bitCount = bnBitCount;
7712BigInteger.prototype.testBit = bnTestBit;
7713BigInteger.prototype.setBit = bnSetBit;
7714BigInteger.prototype.clearBit = bnClearBit;
7715BigInteger.prototype.flipBit = bnFlipBit;
7716BigInteger.prototype.add = bnAdd;
7717BigInteger.prototype.subtract = bnSubtract;
7718BigInteger.prototype.multiply = bnMultiply;
7719BigInteger.prototype.divide = bnDivide;
7720BigInteger.prototype.remainder = bnRemainder;
7721BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder;
7722BigInteger.prototype.modPow = bnModPow;
7723BigInteger.prototype.modInverse = bnModInverse;
7724BigInteger.prototype.pow = bnPow;
7725BigInteger.prototype.gcd = bnGCD;
7726BigInteger.prototype.isProbablePrime = bnIsProbablePrime;
7727
7728// BigInteger interfaces not implemented in jsbn:
7729
7730// BigInteger(int signum, byte[] magnitude)
7731// double doubleValue()
7732// float floatValue()
7733// int hashCode()
7734// long longValue()
7735// static BigInteger valueOf(long val)