blob: b5064ef47f85785806c1f2edb1007c36bea4b9f4 [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 Thompson42806a12012-12-29 18:19:39 -0800179 interest.interestLifetime = 4000; // default interest timeout value in milliseconds.
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));
Jeff Thompson42806a12012-12-29 18:19:39 -0800219 interest.interestLifetime = 4000; // milliseconds
Jeff Thompson3dfddaa2012-12-16 17:55:47 -0800220
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 Thompson42806a12012-12-29 18:19:39 -0800431 interest.interestLifetime = 4000; // milliseconds
Jeff Thompson84db2632012-12-09 22:31:39 -0800432 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 Thompson96978b42012-12-29 21:59:54 -0800483 }, interest.interestLifetime); // interestLifetime is in milliseconds.
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
Jeff Thompson42806a12012-12-29 18:19:39 -08001681// _interestLifetime is in milliseconds.
Wentao Shang0e291c82012-12-02 23:36:29 -08001682var Interest = function Interest(_name,_faceInstance,_minSuffixComponents,_maxSuffixComponents,_publisherPublicKeyDigest, _exclude, _childSelector,_answerOriginKind,_scope,_interestLifetime,_nonce){
1683
1684 this.name = _name;
1685 this.faceInstance = _faceInstance;
1686 this.maxSuffixComponents = _maxSuffixComponents;
1687 this.minSuffixComponents = _minSuffixComponents;
1688
1689 this.publisherPublicKeyDigest = _publisherPublicKeyDigest;
1690 this.exclude = _exclude;
1691 this.childSelector = _childSelector;
1692 this.answerOriginKind = _answerOriginKind;
1693 this.scope = _scope;
Jeff Thompson42806a12012-12-29 18:19:39 -08001694 this.interestLifetime = _interestLifetime; // milli seconds
Wentao Shang0e291c82012-12-02 23:36:29 -08001695 this.nonce = _nonce;
1696};
1697
1698Interest.RECURSIVE_POSTFIX = "*";
1699
1700Interest.CHILD_SELECTOR_LEFT = 0;
1701Interest.CHILD_SELECTOR_RIGHT = 1;
1702Interest.ANSWER_CONTENT_STORE = 1;
1703Interest.ANSWER_GENERATED = 2;
1704Interest.ANSWER_STALE = 4; // Stale answer OK
1705Interest.MARK_STALE = 16; // Must have scope 0. Michael calls this a "hack"
1706
1707Interest.DEFAULT_ANSWER_ORIGIN_KIND = Interest.ANSWER_CONTENT_STORE | Interest.ANSWER_GENERATED;
1708
1709
1710Interest.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
1711
1712 decoder.readStartElement(CCNProtocolDTags.Interest);
1713
1714 this.name = new Name();
1715 this.name.from_ccnb(decoder);
1716
1717 if (decoder.peekStartElement(CCNProtocolDTags.MinSuffixComponents))
1718 this.minSuffixComponents = decoder.readIntegerElement(CCNProtocolDTags.MinSuffixComponents);
1719
1720 if (decoder.peekStartElement(CCNProtocolDTags.MaxSuffixComponents))
1721 this.maxSuffixComponents = decoder.readIntegerElement(CCNProtocolDTags.MaxSuffixComponents);
1722
1723 if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
1724 this.publisherPublicKeyDigest = new PublisherPublicKeyDigest();
1725 this.publisherPublicKeyDigest.from_ccnb(decoder);
1726 }
1727
1728 if (decoder.peekStartElement(CCNProtocolDTags.Exclude)) {
1729 this.exclude = new Exclude();
1730 this.exclude.from_ccnb(decoder);
1731 }
1732
1733 if (decoder.peekStartElement(CCNProtocolDTags.ChildSelector))
1734 this.childSelector = decoder.readIntegerElement(CCNProtocolDTags.ChildSelector);
1735
1736 if (decoder.peekStartElement(CCNProtocolDTags.AnswerOriginKind))
1737 this.answerOriginKind = decoder.readIntegerElement(CCNProtocolDTags.AnswerOriginKind);
1738
1739 if (decoder.peekStartElement(CCNProtocolDTags.Scope))
1740 this.scope = decoder.readIntegerElement(CCNProtocolDTags.Scope);
1741
1742 if (decoder.peekStartElement(CCNProtocolDTags.InterestLifetime))
Jeff Thompson42806a12012-12-29 18:19:39 -08001743 this.interestLifetime = 1000.0 * DataUtils.bigEndianToUnsignedInt
Wentao Shang0e291c82012-12-02 23:36:29 -08001744 (decoder.readBinaryElement(CCNProtocolDTags.InterestLifetime)) / 4096;
1745
1746 if (decoder.peekStartElement(CCNProtocolDTags.Nonce))
1747 this.nonce = decoder.readBinaryElement(CCNProtocolDTags.Nonce);
1748
1749 decoder.readEndElement();
1750};
1751
1752Interest.prototype.to_ccnb = function(/*XMLEncoder*/ encoder){
1753 //Could check if name is present
1754
1755 encoder.writeStartElement(CCNProtocolDTags.Interest);
1756
1757 this.name.to_ccnb(encoder);
1758
1759 if (null != this.minSuffixComponents)
1760 encoder.writeElement(CCNProtocolDTags.MinSuffixComponents, this.minSuffixComponents);
1761
1762 if (null != this.maxSuffixComponents)
1763 encoder.writeElement(CCNProtocolDTags.MaxSuffixComponents, this.maxSuffixComponents);
1764
1765 if (null != this.publisherPublicKeyDigest)
1766 this.publisherPublicKeyDigest.to_ccnb(encoder);
1767
1768 if (null != this.exclude)
1769 this.exclude.to_ccnb(encoder);
1770
1771 if (null != this.childSelector)
1772 encoder.writeElement(CCNProtocolDTags.ChildSelector, this.childSelector);
1773
1774 if (this.DEFAULT_ANSWER_ORIGIN_KIND != this.answerOriginKind && this.answerOriginKind!=null)
1775 encoder.writeElement(CCNProtocolDTags.AnswerOriginKind, this.answerOriginKind);
1776
1777 if (null != this.scope)
1778 encoder.writeElement(CCNProtocolDTags.Scope, this.scope);
1779
1780 if (null != this.interestLifetime)
1781 encoder.writeElement(CCNProtocolDTags.InterestLifetime,
Jeff Thompson42806a12012-12-29 18:19:39 -08001782 DataUtils.nonNegativeIntToBigEndian((this.interestLifetime / 1000.0) * 4096));
Wentao Shang0e291c82012-12-02 23:36:29 -08001783
1784 if (null != this.nonce)
1785 encoder.writeElement(CCNProtocolDTags.Nonce, this.nonce);
1786
1787 encoder.writeEndElement();
1788
1789};
1790
1791Interest.prototype.matches_name = function(/*Name*/ name){
1792 var i_name = this.name.components;
1793 var o_name = name.components;
1794
1795 // The intrest name is longer than the name we are checking it against.
1796 if (i_name.length > o_name.length)
1797 return false;
1798
1799 // Check if at least one of given components doesn't match.
1800 for (var i = 0; i < i_name.length; ++i) {
1801 if (!DataUtils.arraysEqual(i_name[i], o_name[i]))
1802 return false;
1803 }
1804
1805 return true;
1806}
1807
1808/**
1809 * Exclude
1810 */
1811var Exclude = function Exclude(_values){
1812
1813 this.OPTIMUM_FILTER_SIZE = 100;
1814
1815
1816 this.values = _values; //array of elements
1817
1818}
1819
1820Exclude.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
1821
1822
1823
1824 decoder.readStartElement(this.getElementLabel());
1825
1826 //TODO APPLY FILTERS/EXCLUDE
1827
1828 //TODO
1829 /*var component;
1830 var any = false;
1831 while ((component = decoder.peekStartElement(CCNProtocolDTags.Component)) ||
1832 (any = decoder.peekStartElement(CCNProtocolDTags.Any)) ||
1833 decoder.peekStartElement(CCNProtocolDTags.Bloom)) {
1834 var ee = component?new ExcludeComponent(): any ? new ExcludeAny() : new BloomFilter();
1835 ee.decode(decoder);
1836 _values.add(ee);
1837 }*/
1838
1839 decoder.readEndElement();
1840
1841};
1842
1843Exclude.prototype.to_ccnb=function(/*XMLEncoder*/ encoder) {
1844 if (!validate()) {
1845 throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
1846 }
1847
1848 if (empty())
1849 return;
1850
1851 encoder.writeStartElement(getElementLabel());
1852
1853 encoder.writeEndElement();
1854
1855 };
1856
1857Exclude.prototype.getElementLabel = function() { return CCNProtocolDTags.Exclude; };
1858
1859
1860/**
1861 * ExcludeAny
1862 */
1863var ExcludeAny = function ExcludeAny() {
1864
1865};
1866
1867ExcludeAny.prototype.from_ccnb = function(decoder) {
1868 decoder.readStartElement(this.getElementLabel());
1869 decoder.readEndElement();
1870};
1871
1872
1873ExcludeAny.prototype.to_ccnb = function( encoder) {
1874 encoder.writeStartElement(this.getElementLabel());
1875 encoder.writeEndElement();
1876};
1877
1878ExcludeAny.prototype.getElementLabel=function() { return CCNProtocolDTags.Any; };
1879
1880
1881/**
1882 * ExcludeComponent
1883 */
1884var ExcludeComponent = function ExcludeComponent(_body) {
1885
1886 //TODO Check BODY is an Array of componenets.
1887
1888 this.body = _body
1889};
1890
1891ExcludeComponent.prototype.from_ccnb = function( decoder) {
1892 this.body = decoder.readBinaryElement(this.getElementLabel());
1893};
1894
1895ExcludeComponent.prototype.to_ccnb = function(encoder) {
1896 encoder.writeElement(this.getElementLabel(), this.body);
1897};
1898
1899ExcludeComponent.prototype.getElementLabel = function() { return CCNProtocolDTags.Component; };
Wentao Shangbd63e462012-12-03 16:19:33 -08001900/**
Wentao Shang0e291c82012-12-02 23:36:29 -08001901 * @author: Meki Cheraoui
1902 * See COPYING for copyright and distribution information.
1903 * This class represents Key Objects
1904 */
1905
1906var Key = function Key(){
1907 /* TODO: Port from PyCCN:
1908 generateRSA()
1909 privateToDER()
1910 publicToDER()
1911 privateToPEM()
1912 publicToPEM()
1913 fromDER()
1914 fromPEM()
1915 */
1916}
1917
1918/**
1919 * KeyLocator
1920 */
1921var KeyLocatorType = {
1922 NAME:1,
1923 KEY:2,
1924 CERTIFICATE:3
1925};
1926
1927var KeyLocator = function KeyLocator(_input,_type){
1928
1929 this.type=_type;
1930
1931 if (_type==KeyLocatorType.NAME){
1932 this.keyName = _input;
1933 }
1934 else if(_type==KeyLocatorType.KEY){
1935 if(LOG>4)console.log('SET KEY');
1936 this.publicKey = _input;
1937 }
1938 else if(_type==KeyLocatorType.CERTIFICATE){
1939 this.certificate = _input;
1940 }
1941
1942};
1943
1944KeyLocator.prototype.from_ccnb = function(decoder) {
1945
1946 decoder.readStartElement(this.getElementLabel());
1947
1948 if (decoder.peekStartElement(CCNProtocolDTags.Key)) {
1949 try {
1950 encodedKey = decoder.readBinaryElement(CCNProtocolDTags.Key);
1951 // This is a DER-encoded SubjectPublicKeyInfo.
1952
1953 //TODO FIX THIS, This should create a Key Object instead of keeping bytes
1954
1955 this.publicKey = encodedKey;//CryptoUtil.getPublicKey(encodedKey);
1956 this.type = 2;
1957
1958
1959 if(LOG>4) console.log('PUBLIC KEY FOUND: '+ this.publicKey);
1960 //this.publicKey = encodedKey;
1961
1962
1963 } catch (e) {
1964 throw new Error("Cannot parse key: ", e);
1965 }
1966
1967 if (null == this.publicKey) {
1968 throw new Error("Cannot parse key: ");
1969 }
1970
1971 } else if ( decoder.peekStartElement(CCNProtocolDTags.Certificate)) {
1972 try {
1973 encodedCert = decoder.readBinaryElement(CCNProtocolDTags.Certificate);
1974
1975 /*
1976 * Certificates not yet working
1977 */
1978
1979 //CertificateFactory factory = CertificateFactory.getInstance("X.509");
1980 //this.certificate = (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(encodedCert));
1981
1982
1983 this.certificate = encodedCert;
1984 this.type = 3;
1985
1986 if(LOG>4) console.log('CERTIFICATE FOUND: '+ this.certificate);
1987
1988 } catch ( e) {
1989 throw new Error("Cannot decode certificate: " + e);
1990 }
1991 if (null == this.certificate) {
1992 throw new Error("Cannot parse certificate! ");
1993 }
1994 } else {
1995 this.type = 1;
1996
1997
1998 this.keyName = new KeyName();
1999 this.keyName.from_ccnb(decoder);
2000 }
2001 decoder.readEndElement();
2002 }
2003
2004
2005 KeyLocator.prototype.to_ccnb = function( encoder) {
2006
2007 if(LOG>4) console.log('type is is ' + this.type);
2008 //TODO Check if Name is missing
2009 if (!this.validate()) {
2010 throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
2011 }
2012
2013
2014 //TODO FIX THIS TOO
2015 encoder.writeStartElement(this.getElementLabel());
2016
2017 if (this.type == KeyLocatorType.KEY) {
2018 if(LOG>5)console.log('About to encode a public key' +this.publicKey);
2019 encoder.writeElement(CCNProtocolDTags.Key, this.publicKey);
2020
2021 } else if (this.type == KeyLocatorType.CERTIFICATE) {
2022
2023 try {
2024 encoder.writeElement(CCNProtocolDTags.Certificate, this.certificate);
2025 } catch ( e) {
2026 throw new Error("CertificateEncodingException attempting to write key locator: " + e);
2027 }
2028
2029 } else if (this.type == KeyLocatorType.NAME) {
2030
2031 this.keyName.to_ccnb(encoder);
2032 }
2033 encoder.writeEndElement();
2034
2035};
2036
2037KeyLocator.prototype.getElementLabel = function() {
2038 return CCNProtocolDTags.KeyLocator;
2039};
2040
2041KeyLocator.prototype.validate = function() {
2042 return ( (null != this.keyName) || (null != this.publicKey) || (null != this.certificate) );
2043};
2044
2045/**
2046 * KeyName is only used by KeyLocator.
2047 */
2048var KeyName = function KeyName() {
2049
2050
2051 this.contentName = this.contentName;//contentName
2052 this.publisherID =this.publisherID;//publisherID
2053
2054};
2055
2056KeyName.prototype.from_ccnb=function( decoder){
2057
2058
2059 decoder.readStartElement(this.getElementLabel());
2060
2061 this.contentName = new Name();
2062 this.contentName.from_ccnb(decoder);
2063
2064 if(LOG>4) console.log('KEY NAME FOUND: ');
2065
2066 if ( PublisherID.peek(decoder) ) {
2067 this.publisherID = new PublisherID();
2068 this.publisherID.from_ccnb(decoder);
2069 }
2070
2071 decoder.readEndElement();
2072};
2073
2074KeyName.prototype.to_ccnb = function( encoder) {
2075 if (!this.validate()) {
2076 throw new Error("Cannot encode : field values missing.");
2077 }
2078
2079 encoder.writeStartElement(this.getElementLabel());
2080
2081 this.contentName.to_ccnb(encoder);
2082 if (null != this.publisherID)
2083 this.publisherID.to_ccnb(encoder);
2084
2085 encoder.writeEndElement();
2086};
2087
2088KeyName.prototype.getElementLabel = function() { return CCNProtocolDTags.KeyName; };
2089
2090KeyName.prototype.validate = function() {
2091 // DKS -- do we do recursive validation?
2092 // null signedInfo ok
2093 return (null != this.contentName);
2094};
Wentao Shangbd63e462012-12-03 16:19:33 -08002095/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002096 * @author: Meki Cheraoui
2097 * See COPYING for copyright and distribution information.
2098 * This class represents Publisher and PublisherType Objects
2099 */
2100
2101
2102var PublisherType = function PublisherType(_tag){
2103 this.KEY =(CCNProtocolDTags.PublisherPublicKeyDigest);
2104 this.CERTIFICATE= (CCNProtocolDTags.PublisherCertificateDigest);
2105 this.ISSUER_KEY= (CCNProtocolDTags.PublisherIssuerKeyDigest);
2106 this.ISSUER_CERTIFICATE =(CCNProtocolDTags.PublisherIssuerCertificateDigest);
2107
2108 this.Tag = _tag;
2109};
2110
2111var isTypeTagVal = function(tagVal) {
2112 if ((tagVal == CCNProtocolDTags.PublisherPublicKeyDigest) ||
2113 (tagVal == CCNProtocolDTags.PublisherCertificateDigest) ||
2114 (tagVal == CCNProtocolDTags.PublisherIssuerKeyDigest) ||
2115 (tagVal == CCNProtocolDTags.PublisherIssuerCertificateDigest)) {
2116 return true;
2117 }
2118 return false;
2119};
2120
2121
2122
2123
2124var PublisherID = function PublisherID() {
2125
2126 this.PUBLISHER_ID_DIGEST_ALGORITHM = "SHA-256";
2127 this.PUBLISHER_ID_LEN = 256/8;
2128
2129 //TODO, implement publisherID creation and key creation
2130
2131 //TODO implement generatePublicKeyDigest
2132 this.publisherID =null;//= generatePublicKeyDigest(key);//ByteArray
2133
2134 //TODO implement generate key
2135 //CryptoUtil.generateKeyID(PUBLISHER_ID_DIGEST_ALGORITHM, key);
2136 this.publisherType = null;//isIssuer ? PublisherType.ISSUER_KEY : PublisherType.KEY;//publisher Type
2137
2138};
2139
2140
2141PublisherID.prototype.from_ccnb = function(decoder) {
2142
2143 // We have a choice here of one of 4 binary element types.
2144 var nextTag = decoder.peekStartElementAsLong();
2145
2146 if (null == nextTag) {
2147 throw new Error("Cannot parse publisher ID.");
2148 }
2149
2150 this.publisherType = new PublisherType(nextTag);
2151
2152 if (!isTypeTagVal(nextTag)) {
2153 throw new Error("Invalid publisher ID, got unexpected type: " + nextTag);
2154 }
2155 this.publisherID = decoder.readBinaryElement(nextTag);
2156 if (null == this.publisherID) {
2157 throw new ContentDecodingException(new Error("Cannot parse publisher ID of type : " + nextTag + "."));
2158 }
2159};
2160
2161PublisherID.prototype.to_ccnb = function(encoder) {
2162 if (!this.validate()) {
2163 throw new Error("Cannot encode " + this.getClass().getName() + ": field values missing.");
2164 }
2165
2166 encoder.writeElement(this.getElementLabel(), this.publisherID);
2167};
2168
2169PublisherID.peek = function(/* XMLDecoder */ decoder) {
2170
2171 //Long
2172 nextTag = decoder.peekStartElementAsLong();
2173
2174 if (null == nextTag) {
2175 // on end element
2176 return false;
2177 }
2178 return (isTypeTagVal(nextTag));
2179 };
2180
2181PublisherID.prototype.getElementLabel = function() {
2182 return this.publisherType.Tag;
2183};
2184
2185PublisherID.prototype.validate = function(){
2186 return ((null != id() && (null != type())));
2187};
2188
2189
2190
Wentao Shangbd63e462012-12-03 16:19:33 -08002191/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002192 * @author: Meki Cheraoui
2193 * See COPYING for copyright and distribution information.
2194 * This class represents PublisherPublicKeyDigest Objects
2195 */
2196var PublisherPublicKeyDigest = function PublisherPublicKeyDigest(_pkd){
2197
2198 //this.PUBLISHER_ID_LEN = 256/8;
2199 this.PUBLISHER_ID_LEN = 512/8;
2200
2201
2202 this.publisherPublicKeyDigest = _pkd;
2203 //if( typeof _pkd == "object") this.publisherPublicKeyDigest = _pkd; // Byte Array
2204 //else if( typeof _pkd == "PublicKey") ;//TODO...
2205
2206};
2207
2208PublisherPublicKeyDigest.prototype.from_ccnb = function( decoder) {
2209
2210 this.publisherPublicKeyDigest = decoder.readBinaryElement(this.getElementLabel());
2211
2212 if(LOG>4)console.log('Publisher public key digest is ' + this.publisherPublicKeyDigest);
2213
2214 if (null == this.publisherPublicKeyDigest) {
2215 throw new Error("Cannot parse publisher key digest.");
2216 }
2217
2218 //TODO check if the length of the PublisherPublicKeyDigest is correct ( Security reason)
2219
2220 if (this.publisherPublicKeyDigest.length != this.PUBLISHER_ID_LEN) {
2221 if (LOG > 0)
2222 console.log('LENGTH OF PUBLISHER ID IS WRONG! Expected ' + this.PUBLISHER_ID_LEN + ", got " + this.publisherPublicKeyDigest.length);
2223
2224 //this.publisherPublicKeyDigest = new PublisherPublicKeyDigest(this.PublisherPublicKeyDigest).PublisherKeyDigest;
2225 }
2226 };
2227
2228PublisherPublicKeyDigest.prototype.to_ccnb= function( encoder) {
2229 //TODO Check that the ByteArray for the key is present
2230 if (!this.validate()) {
2231 throw new Error("Cannot encode : field values missing.");
2232 }
2233 if(LOG>3) console.log('PUBLISHER KEY DIGEST IS'+this.publisherPublicKeyDigest);
2234 encoder.writeElement(this.getElementLabel(), this.publisherPublicKeyDigest);
2235};
2236
2237PublisherPublicKeyDigest.prototype.getElementLabel = function() { return CCNProtocolDTags.PublisherPublicKeyDigest; };
2238
2239PublisherPublicKeyDigest.prototype.validate =function() {
2240 return (null != this.publisherPublicKeyDigest);
2241};
Wentao Shangbd63e462012-12-03 16:19:33 -08002242/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002243 * @author: Meki Cheraoui
2244 * See COPYING for copyright and distribution information.
2245 * This class represents Face Instances
2246 */
2247
2248var NetworkProtocol = { TCP:6, UDP:17};
2249
2250var FaceInstance = function FaceInstance(
2251 _action,
2252 _publisherPublicKeyDigest,
2253 _faceID,
2254 _ipProto,
2255 _host,
2256 _port,
2257 _multicastInterface,
2258 _multicastTTL,
2259 _freshnessSeconds){
2260
2261
2262 this.action = _action;
2263 this.publisherPublicKeyDigest = _publisherPublicKeyDigest;
2264 this.faceID = _faceID;
2265 this.ipProto = _ipProto;
2266 this.host = _host;
2267 this.Port = _port;
2268 this.multicastInterface =_multicastInterface;
2269 this.multicastTTL =_multicastTTL;
2270 this.freshnessSeconds = _freshnessSeconds;
2271
2272 //action ::= ("newface" | "destroyface" | "queryface")
2273 //publisherPublicKeyDigest ::= SHA-256 digest
2274 //faceID ::= nonNegativeInteger
2275 //ipProto ::= nonNegativeInteger [IANA protocol number, 6=TCP, 17=UDP]
2276 //Host ::= textual representation of numeric IPv4 or IPv6 address
2277 //Port ::= nonNegativeInteger [1..65535]
2278 //MulticastInterface ::= textual representation of numeric IPv4 or IPv6 address
2279 //MulticastTTL ::= nonNegativeInteger [1..255]
2280 //freshnessSeconds ::= nonNegativeInteger
2281
2282};
2283
2284/**
2285 * Used by NetworkObject to decode the object from a network stream.
2286 */
2287FaceInstance.prototype.from_ccnb = function(//XMLDecoder
2288 decoder) {
2289
2290 decoder.readStartElement(this.getElementLabel());
2291
2292 if (decoder.peekStartElement(CCNProtocolDTags.Action)) {
2293
2294 this.action = decoder.readUTF8Element(CCNProtocolDTags.Action);
2295
2296 }
2297 if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
2298
2299 this.publisherPublicKeyDigest = new PublisherPublicKeyDigest();
2300 this.publisherPublicKeyDigest.from_ccnb(decoder);
2301
2302 }
2303 if (decoder.peekStartElement(CCNProtocolDTags.FaceID)) {
2304
2305 this.faceID = decoder.readIntegerElement(CCNProtocolDTags.FaceID);
2306
2307 }
2308 if (decoder.peekStartElement(CCNProtocolDTags.IPProto)) {
2309
2310 //int
2311 var pI = decoder.readIntegerElement(CCNProtocolDTags.IPProto);
2312
2313 this.ipProto = null;
2314
2315 if (NetworkProtocol.TCP == pI) {
2316
2317 this.ipProto = NetworkProtocol.TCP;
2318
2319 } else if (NetworkProtocol.UDP == pI) {
2320
2321 this.ipProto = NetworkProtocol.UDP;
2322
2323 } else {
2324
2325 throw new Error("FaceInstance.decoder. Invalid " +
2326 CCNProtocolDTags.tagToString(CCNProtocolDTags.IPProto) + " field: " + pI);
2327
2328 }
2329 }
2330
2331 if (decoder.peekStartElement(CCNProtocolDTags.Host)) {
2332
2333 this.host = decoder.readUTF8Element(CCNProtocolDTags.Host);
2334
2335 }
2336
2337 if (decoder.peekStartElement(CCNProtocolDTags.Port)) {
2338 this.Port = decoder.readIntegerElement(CCNProtocolDTags.Port);
2339 }
2340
2341 if (decoder.peekStartElement(CCNProtocolDTags.MulticastInterface)) {
2342 this.multicastInterface = decoder.readUTF8Element(CCNProtocolDTags.MulticastInterface);
2343 }
2344
2345 if (decoder.peekStartElement(CCNProtocolDTags.MulticastTTL)) {
2346 this.multicastTTL = decoder.readIntegerElement(CCNProtocolDTags.MulticastTTL);
2347 }
2348
2349 if (decoder.peekStartElement(CCNProtocolDTags.FreshnessSeconds)) {
2350 this.freshnessSeconds = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
2351 }
2352 decoder.readEndElement();
2353}
2354
2355/**
2356 * Used by NetworkObject to encode the object to a network stream.
2357 */
2358FaceInstance.prototype.to_ccnb = function(//XMLEncoder
2359 encoder){
2360
2361 //if (!this.validate()) {
2362 //throw new Error("Cannot encode : field values missing.");
2363 //throw new Error("")
2364 //}
2365 encoder.writeStartElement(this.getElementLabel());
2366
2367 if (null != this.action && this.action.length != 0)
2368 encoder.writeElement(CCNProtocolDTags.Action, this.action);
2369
2370 if (null != this.publisherPublicKeyDigest) {
2371 this.publisherPublicKeyDigest.to_ccnb(encoder);
2372 }
2373 if (null != this.faceID) {
2374 encoder.writeElement(CCNProtocolDTags.FaceID, this.faceID);
2375 }
2376 if (null != this.ipProto) {
2377 //encoder.writeElement(CCNProtocolDTags.IPProto, this.IpProto.value());
2378 encoder.writeElement(CCNProtocolDTags.IPProto, this.ipProto);
2379 }
2380 if (null != this.host && this.host.length != 0) {
2381 encoder.writeElement(CCNProtocolDTags.Host, this.host);
2382 }
2383 if (null != this.Port) {
2384 encoder.writeElement(CCNProtocolDTags.Port, this.Port);
2385 }
2386 if (null != this.multicastInterface && this.multicastInterface.length != 0) {
2387 encoder.writeElement(CCNProtocolDTags.MulticastInterface, this.multicastInterface);
2388 }
2389 if (null != this.multicastTTL) {
2390 encoder.writeElement(CCNProtocolDTags.MulticastTTL, this.multicastTTL);
2391 }
2392 if (null != this.freshnessSeconds) {
2393 encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.freshnessSeconds);
2394 }
2395 encoder.writeEndElement();
2396}
2397
2398
2399FaceInstance.prototype.getElementLabel= function(){return CCNProtocolDTags.FaceInstance;};
2400
Wentao Shangbd63e462012-12-03 16:19:33 -08002401/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002402 * @author: Meki Cheraoui
2403 * See COPYING for copyright and distribution information.
2404 * This class represents Forwarding Entries
2405 */
2406
2407var ForwardingEntry = function ForwardingEntry(
2408 //ActionType
2409 _action,
2410 //Name
2411 _prefixName,
2412 //PublisherPublicKeyDigest
2413 _ccndId,
2414 //Integer
2415 _faceID,
2416 //Integer
2417 _flags,
2418 //Integer
2419 _lifetime){
2420
2421
2422
2423 //String
2424 this.action = _action;
2425 //Name\
2426 this.prefixName = _prefixName;
2427 //PublisherPublicKeyDigest
2428 this.ccndID = _ccndId;
2429 //Integer
2430 this.faceID = _faceID;
2431 //Integer
2432 this.flags = _flags;
2433 //Integer
2434 this.lifetime = _lifetime; // in seconds
2435
2436};
2437
2438ForwardingEntry.prototype.from_ccnb =function(
2439 //XMLDecoder
2440 decoder)
2441 //throws ContentDecodingException
2442 {
2443 decoder.readStartElement(this.getElementLabel());
2444 if (decoder.peekStartElement(CCNProtocolDTags.Action)) {
2445 this.action = decoder.readUTF8Element(CCNProtocolDTags.Action);
2446 }
2447 if (decoder.peekStartElement(CCNProtocolDTags.Name)) {
2448 this.prefixName = new Name();
2449 this.prefixName.from_ccnb(decoder) ;
2450 }
2451 if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
2452 this.CcndId = new PublisherPublicKeyDigest();
2453 this.CcndId.from_ccnb(decoder);
2454 }
2455 if (decoder.peekStartElement(CCNProtocolDTags.FaceID)) {
2456 this.faceID = decoder.readIntegerElement(CCNProtocolDTags.FaceID);
2457 }
2458 if (decoder.peekStartElement(CCNProtocolDTags.ForwardingFlags)) {
2459 this.flags = decoder.readIntegerElement(CCNProtocolDTags.ForwardingFlags);
2460 }
2461 if (decoder.peekStartElement(CCNProtocolDTags.FreshnessSeconds)) {
2462 this.lifetime = decoder.readIntegerElement(CCNProtocolDTags.FreshnessSeconds);
2463 }
2464 decoder.readEndElement();
2465 };
2466
2467 /**
2468 * Used by NetworkObject to encode the object to a network stream.
2469 */
2470ForwardingEntry.prototype.to_ccnb =function(
2471 //XMLEncoder
2472encoder)
2473{
2474
2475
2476 //if (!validate()) {
2477 //throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
2478 //}
2479 encoder.writeStartElement(this.getElementLabel());
2480 if (null != this.action && this.action.length != 0)
2481 encoder.writeElement(CCNProtocolDTags.Action, this.action);
2482 if (null != this.prefixName) {
2483 this.prefixName.to_ccnb(encoder);
2484 }
2485 if (null != this.CcndId) {
2486 this.CcndId.to_ccnb(encoder);
2487 }
2488 if (null != this.faceID) {
2489 encoder.writeElement(CCNProtocolDTags.FaceID, this.faceID);
2490 }
2491 if (null != this.flags) {
2492 encoder.writeElement(CCNProtocolDTags.ForwardingFlags, this.flags);
2493 }
2494 if (null != this.lifetime) {
2495 encoder.writeElement(CCNProtocolDTags.FreshnessSeconds, this.lifetime);
2496 }
2497 encoder.writeEndElement();
2498 };
2499
2500ForwardingEntry.prototype.getElementLabel = function() { return CCNProtocolDTags.ForwardingEntry; }
Wentao Shangbd63e462012-12-03 16:19:33 -08002501/**
Jeff Thompson96978b42012-12-29 21:59:54 -08002502 * @author: Jeff Thompson
2503 * See COPYING for copyright and distribution information.
2504 * Encapsulate an Uint8Array and support dynamic reallocation.
2505 */
2506
2507/*
2508 * Create a DynamicUint8Array where this.array is a Uint8Array of size length.
2509 * If length is not supplied, use a default initial length.
2510 * The methods will update this.length.
2511 * To access the array, use this.array or call subarray.
2512 */
2513var DynamicUint8Array = function DynamicUint8Array(length) {
2514 if (!length)
2515 length = 16;
2516
2517 this.array = new Uint8Array(length);
2518 this.length = length;
2519};
2520
2521/*
2522 * Ensure that this.array has the length, reallocate and copy if necessary.
2523 * Update this.length which may be greater than length.
2524 */
2525DynamicUint8Array.prototype.ensureLength = function(length) {
2526 if (this.array.length >= length)
2527 return;
2528
2529 // See if double is enough.
2530 var newLength = this.array.length * 2;
2531 if (length > newLength)
2532 // The needed length is much greater, so use it.
2533 newLength = length;
2534
2535 var newArray = new Uint8Array(newLength);
2536 newArray.set(this.array);
2537 this.array = newArray;
2538 this.length = newLength;
2539};
2540
2541/*
2542 * Call this.array.set(value, offset), reallocating if necessary.
2543 */
2544DynamicUint8Array.prototype.set = function(value, offset) {
2545 this.ensureLength(value.length + offset);
2546 this.array.set(value, offset);
2547};
2548
2549/*
2550 * Return this.array.subarray(begin, end);
2551 */
2552DynamicUint8Array.prototype.subarray = function(begin, end) {
2553 return this.array.subarray(begin, end);
2554}
2555/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002556 * This class is used to encode ccnb binary elements (blob, type/value pairs).
2557 *
2558 * @author: Meki Cheraoui
2559 * See COPYING for copyright and distribution information.
2560 */
2561
2562var XML_EXT = 0x00;
2563
2564var XML_TAG = 0x01;
2565
2566var XML_DTAG = 0x02;
2567
2568var XML_ATTR = 0x03;
2569
2570var XML_DATTR = 0x04;
2571
2572var XML_BLOB = 0x05;
2573
2574var XML_UDATA = 0x06;
2575
2576var XML_CLOSE = 0x0;
2577
2578var XML_SUBTYPE_PROCESSING_INSTRUCTIONS = 16;
2579
2580
2581var XML_TT_BITS = 3;
2582var XML_TT_MASK = ((1 << XML_TT_BITS) - 1);
2583var XML_TT_VAL_BITS = XML_TT_BITS + 1;
2584var XML_TT_VAL_MASK = ((1 << (XML_TT_VAL_BITS)) - 1);
2585var XML_REG_VAL_BITS = 7;
2586var XML_REG_VAL_MASK = ((1 << XML_REG_VAL_BITS) - 1);
2587var XML_TT_NO_MORE = (1 << XML_REG_VAL_BITS); // 0x80
2588var BYTE_MASK = 0xFF;
2589var LONG_BYTES = 8;
2590var LONG_BITS = 64;
2591
2592var bits_11 = 0x0000007FF;
2593var bits_18 = 0x00003FFFF;
2594var bits_32 = 0x0FFFFFFFF;
2595
2596
2597var BinaryXMLEncoder = function BinaryXMLEncoder(){
Jeff Thompson96978b42012-12-29 21:59:54 -08002598 this.ostream = new DynamicUint8Array(100);
Wentao Shang0e291c82012-12-02 23:36:29 -08002599 this.offset =0;
2600 this.CODEC_NAME = "Binary";
2601};
2602
2603/*
2604 * Encode utf8Content as utf8.
2605 */
2606BinaryXMLEncoder.prototype.writeUString = function(/*String*/ utf8Content) {
2607 this.encodeUString(utf8Content, XML_UDATA);
2608};
2609
2610
2611BinaryXMLEncoder.prototype.writeBlob = function(
2612 /*Uint8Array*/ binaryContent
2613 ) {
2614
2615 if(LOG >3) console.log(binaryContent);
2616
2617 this.encodeBlob(binaryContent, binaryContent.length);
2618};
2619
2620
2621BinaryXMLEncoder.prototype.writeStartElement = function(
2622 /*String*/ tag,
2623 /*TreeMap<String,String>*/ attributes
2624 ) {
2625
2626 /*Long*/ var dictionaryVal = tag; //stringToTag(tag);
2627
2628 if (null == dictionaryVal) {
2629 this.encodeUString(tag, XML_TAG);
2630 } else {
2631 this.encodeTypeAndVal(XML_DTAG, dictionaryVal);
2632 }
2633
2634 if (null != attributes) {
2635 this.writeAttributes(attributes);
2636 }
2637};
2638
2639
2640BinaryXMLEncoder.prototype.writeEndElement = function() {
Jeff Thompson96978b42012-12-29 21:59:54 -08002641 this.ostream.ensureLength(this.offset + 1);
2642 this.ostream.array[this.offset] = XML_CLOSE;
Wentao Shang0e291c82012-12-02 23:36:29 -08002643 this.offset += 1;
2644}
2645
2646
2647BinaryXMLEncoder.prototype.writeAttributes = function(/*TreeMap<String,String>*/ attributes) {
2648 if (null == attributes) {
2649 return;
2650 }
2651
2652 // the keySet of a TreeMap is sorted.
2653
2654 for(var i=0; i<attributes.length;i++){
2655 var strAttr = attributes[i].k;
2656 var strValue = attributes[i].v;
2657
2658 var dictionaryAttr = stringToTag(strAttr);
2659 if (null == dictionaryAttr) {
2660 // not in dictionary, encode as attr
2661 // compressed format wants length of tag represented as length-1
2662 // to save that extra bit, as tag cannot be 0 length.
2663 // encodeUString knows to do that.
2664 this.encodeUString(strAttr, XML_ATTR);
2665 } else {
2666 this.encodeTypeAndVal(XML_DATTR, dictionaryAttr);
2667 }
2668 // Write value
2669 this.encodeUString(strValue);
2670
2671 }
2672}
2673
2674
2675//returns a string
2676stringToTag = function(/*long*/ tagVal) {
2677 if ((tagVal >= 0) && (tagVal < CCNProtocolDTagsStrings.length)) {
2678 return CCNProtocolDTagsStrings[tagVal];
2679 } else if (tagVal == CCNProtocolDTags.CCNProtocolDataUnit) {
2680 return CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT;
2681 }
2682 return null;
2683};
2684
2685//returns a Long
2686tagToString = function(/*String*/ tagName) {
2687 // the slow way, but right now we don't care.... want a static lookup for the forward direction
2688 for (var i=0; i < CCNProtocolDTagsStrings.length; ++i) {
2689 if ((null != CCNProtocolDTagsStrings[i]) && (CCNProtocolDTagsStrings[i] == tagName)) {
2690 return i;
2691 }
2692 }
2693 if (CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT == tagName) {
2694 return CCNProtocolDTags.CCNProtocolDataUnit;
2695 }
2696 return null;
2697};
2698
2699/*
2700 * If Content is a string, then encode as utf8 and write UDATA.
2701 */
2702BinaryXMLEncoder.prototype.writeElement = function(
2703 //long
2704 tag,
2705 //byte[]
2706 Content,
2707 //TreeMap<String, String>
2708 attributes
2709 ) {
2710 this.writeStartElement(tag, attributes);
2711 // Will omit if 0-length
2712
2713 if(typeof Content === 'number') {
2714 if(LOG>4) console.log('GOING TO WRITE THE NUMBER .charCodeAt(0) ' + Content.toString().charCodeAt(0) );
2715 if(LOG>4) console.log('GOING TO WRITE THE NUMBER ' + Content.toString() );
2716 if(LOG>4) console.log('type of number is ' + typeof Content.toString() );
2717
2718 this.writeUString(Content.toString());
2719 //whatever
2720 }
2721 else if(typeof Content === 'string'){
2722 if(LOG>4) console.log('GOING TO WRITE THE STRING ' + Content );
2723 if(LOG>4) console.log('type of STRING is ' + typeof Content );
2724
2725 this.writeUString(Content);
2726 }
2727 else{
2728 if(LOG>4) console.log('GOING TO WRITE A BLOB ' + Content );
2729
2730 this.writeBlob(Content);
2731 }
2732
2733 this.writeEndElement();
2734}
2735
2736
2737
2738var TypeAndVal = function TypeAndVal(_type,_val) {
2739 this.type = _type;
2740 this.val = _val;
2741
2742};
2743
2744
2745BinaryXMLEncoder.prototype.encodeTypeAndVal = function(
2746 //int
2747 type,
2748 //long
2749 val
2750 ) {
2751
2752 if(LOG>4) console.log('Encoding type '+ type+ ' and value '+ val);
2753
2754 if(LOG>4) console.log('OFFSET IS ' + this.offset);
2755
2756 if ((type > XML_UDATA) || (type < 0) || (val < 0)) {
2757 throw new Error("Tag and value must be positive, and tag valid.");
2758 }
2759
2760 // Encode backwards. Calculate how many bytes we need:
2761 var numEncodingBytes = this.numEncodingBytes(val);
Jeff Thompson96978b42012-12-29 21:59:54 -08002762 this.ostream.ensureLength(this.offset + numEncodingBytes);
Wentao Shang0e291c82012-12-02 23:36:29 -08002763
2764 // Bottom 4 bits of val go in last byte with tag.
Jeff Thompson96978b42012-12-29 21:59:54 -08002765 this.ostream.array[this.offset + numEncodingBytes - 1] =
Wentao Shang0e291c82012-12-02 23:36:29 -08002766 //(byte)
2767 (BYTE_MASK &
2768 (((XML_TT_MASK & type) |
2769 ((XML_TT_VAL_MASK & val) << XML_TT_BITS))) |
2770 XML_TT_NO_MORE); // set top bit for last byte
Jeff Thompson96978b42012-12-29 21:59:54 -08002771 val = val >>> XML_TT_VAL_BITS;
Wentao Shang0e291c82012-12-02 23:36:29 -08002772
2773 // Rest of val goes into preceding bytes, 7 bits per byte, top bit
2774 // is "more" flag.
2775 var i = this.offset + numEncodingBytes - 2;
2776 while ((0 != val) && (i >= this.offset)) {
Jeff Thompson96978b42012-12-29 21:59:54 -08002777 this.ostream.array[i] = //(byte)
Wentao Shang0e291c82012-12-02 23:36:29 -08002778 (BYTE_MASK & (val & XML_REG_VAL_MASK)); // leave top bit unset
2779 val = val >>> XML_REG_VAL_BITS;
2780 --i;
2781 }
2782 if (val != 0) {
2783 throw new Error( "This should not happen: miscalculated encoding");
2784 //Log.warning(Log.FAC_ENCODING, "This should not happen: miscalculated encoding length, have " + val + " left.");
2785 }
2786 this.offset+= numEncodingBytes;
2787
2788 return numEncodingBytes;
2789};
2790
2791/*
2792 * Encode ustring as utf8.
2793 */
2794BinaryXMLEncoder.prototype.encodeUString = function(
2795 //String
2796 ustring,
2797 //byte
2798 type) {
2799
2800 if (null == ustring)
2801 return;
2802 if (type == XML_TAG || type == XML_ATTR && ustring.length == 0)
2803 return;
2804
2805 if(LOG>3) console.log("The string to write is ");
2806 if(LOG>3) console.log(ustring);
2807
2808 var strBytes = DataUtils.stringToUtf8Array(ustring);
2809
2810 this.encodeTypeAndVal(type,
2811 (((type == XML_TAG) || (type == XML_ATTR)) ?
2812 (strBytes.length-1) :
2813 strBytes.length));
2814
2815 if(LOG>3) console.log("THE string to write is ");
2816
2817 if(LOG>3) console.log(strBytes);
2818
Jeff Thompson96978b42012-12-29 21:59:54 -08002819 this.writeString(strBytes);
Wentao Shang0e291c82012-12-02 23:36:29 -08002820 this.offset+= strBytes.length;
2821};
2822
2823
2824
2825BinaryXMLEncoder.prototype.encodeBlob = function(
2826 //Uint8Array
2827 blob,
2828 //int
2829 length) {
2830
2831
2832 if (null == blob)
2833 return;
2834
2835 if(LOG>4) console.log('LENGTH OF XML_BLOB IS '+length);
2836
2837 /*blobCopy = new Array(blob.Length);
2838
2839 for (i = 0; i < blob.length; i++) //in InStr.ToCharArray())
2840 {
2841 blobCopy[i] = blob[i];
2842 }*/
2843
2844 this.encodeTypeAndVal(XML_BLOB, length);
2845
Jeff Thompson96978b42012-12-29 21:59:54 -08002846 this.writeBlobArray(blob);
Wentao Shang0e291c82012-12-02 23:36:29 -08002847 this.offset += length;
2848};
2849
2850var ENCODING_LIMIT_1_BYTE = ((1 << (XML_TT_VAL_BITS)) - 1);
2851var ENCODING_LIMIT_2_BYTES = ((1 << (XML_TT_VAL_BITS + XML_REG_VAL_BITS)) - 1);
2852var ENCODING_LIMIT_3_BYTES = ((1 << (XML_TT_VAL_BITS + 2 * XML_REG_VAL_BITS)) - 1);
2853
2854BinaryXMLEncoder.prototype.numEncodingBytes = function(
2855 //long
2856 x) {
2857 if (x <= ENCODING_LIMIT_1_BYTE) return (1);
2858 if (x <= ENCODING_LIMIT_2_BYTES) return (2);
2859 if (x <= ENCODING_LIMIT_3_BYTES) return (3);
2860
2861 var numbytes = 1;
2862
2863 // Last byte gives you XML_TT_VAL_BITS
2864 // Remainder each give you XML_REG_VAL_BITS
2865 x = x >>> XML_TT_VAL_BITS;
2866 while (x != 0) {
2867 numbytes++;
2868 x = x >>> XML_REG_VAL_BITS;
2869 }
2870 return (numbytes);
2871};
2872
2873BinaryXMLEncoder.prototype.writeDateTime = function(
2874 //String
2875 tag,
2876 //CCNTime
2877 dateTime) {
2878
2879 if(LOG>4)console.log('ENCODING DATE with LONG VALUE');
2880 if(LOG>4)console.log(dateTime.msec);
2881
2882 //var binarydate = DataUtils.unsignedLongToByteArray( Math.round((dateTime.msec/1000) * 4096) );
2883
2884
2885 //parse to hex
2886 var binarydate = Math.round((dateTime.msec/1000) * 4096).toString(16) ;
2887
2888 //HACK
2889 var binarydate = DataUtils.toNumbers( '0'.concat(binarydate,'0')) ;
2890
2891
2892 if(LOG>4)console.log('ENCODING DATE with BINARY VALUE');
2893 if(LOG>4)console.log(binarydate);
2894 if(LOG>4)console.log('ENCODING DATE with BINARY VALUE(HEX)');
2895 if(LOG>4)console.log(DataUtils.toHex(binarydate));
2896
2897 this.writeElement(tag, binarydate);
2898};
2899
Jeff Thompson96978b42012-12-29 21:59:54 -08002900// This does not update this.offset.
2901BinaryXMLEncoder.prototype.writeString = function(input) {
Wentao Shang0e291c82012-12-02 23:36:29 -08002902
2903 if(typeof input === 'string'){
2904 //console.log('went here');
2905 if(LOG>4) console.log('GOING TO WRITE A STRING');
2906 if(LOG>4) console.log(input);
2907
Jeff Thompson96978b42012-12-29 21:59:54 -08002908 this.ostream.ensureLength(this.offset + input.length);
2909 for (var i = 0; i < input.length; i++) {
Wentao Shang0e291c82012-12-02 23:36:29 -08002910 if(LOG>4) console.log('input.charCodeAt(i)=' + input.charCodeAt(i));
Jeff Thompson96978b42012-12-29 21:59:54 -08002911 this.ostream.array[this.offset + i] = (input.charCodeAt(i));
Wentao Shang0e291c82012-12-02 23:36:29 -08002912 }
2913 }
2914 else{
2915 if(LOG>4) console.log('GOING TO WRITE A STRING IN BINARY FORM');
2916 if(LOG>4) console.log(input);
2917
2918 this.writeBlobArray(input);
2919 }
2920 /*
2921 else if(typeof input === 'object'){
2922
2923 }
2924 */
2925};
2926
2927
2928BinaryXMLEncoder.prototype.writeBlobArray = function(
2929 //Uint8Array
Jeff Thompson96978b42012-12-29 21:59:54 -08002930 blob) {
Wentao Shang0e291c82012-12-02 23:36:29 -08002931
2932 if(LOG>4) console.log('GOING TO WRITE A BLOB');
2933
Wentao Shang0e291c82012-12-02 23:36:29 -08002934 this.ostream.set(blob, this.offset);
2935};
2936
2937
2938BinaryXMLEncoder.prototype.getReducedOstream = function() {
2939 return this.ostream.subarray(0, this.offset);
2940};
2941
Wentao Shangbd63e462012-12-03 16:19:33 -08002942/**
Wentao Shang0e291c82012-12-02 23:36:29 -08002943 * This class is used to decode ccnb binary elements (blob, type/value pairs).
2944 *
2945 * @author: Meki Cheraoui
2946 * See COPYING for copyright and distribution information.
2947 */
2948
2949var XML_EXT = 0x00;
2950
2951var XML_TAG = 0x01;
2952
2953var XML_DTAG = 0x02;
2954
2955var XML_ATTR = 0x03;
2956
2957var XML_DATTR = 0x04;
2958
2959var XML_BLOB = 0x05;
2960
2961var XML_UDATA = 0x06;
2962
2963var XML_CLOSE = 0x0;
2964
2965var XML_SUBTYPE_PROCESSING_INSTRUCTIONS = 16;
2966
2967
2968var XML_TT_BITS = 3;
2969var XML_TT_MASK = ((1 << XML_TT_BITS) - 1);
2970var XML_TT_VAL_BITS = XML_TT_BITS + 1;
2971var XML_TT_VAL_MASK = ((1 << (XML_TT_VAL_BITS)) - 1);
2972var XML_REG_VAL_BITS = 7;
2973var XML_REG_VAL_MASK = ((1 << XML_REG_VAL_BITS) - 1);
2974var XML_TT_NO_MORE = (1 << XML_REG_VAL_BITS); // 0x80
2975var BYTE_MASK = 0xFF;
2976var LONG_BYTES = 8;
2977var LONG_BITS = 64;
2978
2979var bits_11 = 0x0000007FF;
2980var bits_18 = 0x00003FFFF;
2981var bits_32 = 0x0FFFFFFFF;
2982
2983
2984
2985//returns a string
2986tagToString = function(/*long*/ tagVal) {
2987 if ((tagVal >= 0) && (tagVal < CCNProtocolDTagsStrings.length)) {
2988 return CCNProtocolDTagsStrings[tagVal];
2989 } else if (tagVal == CCNProtocolDTags.CCNProtocolDataUnit) {
2990 return CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT;
2991 }
2992 return null;
2993};
2994
2995//returns a Long
2996stringToTag = function(/*String*/ tagName) {
2997 // the slow way, but right now we don't care.... want a static lookup for the forward direction
2998 for (var i=0; i < CCNProtocolDTagsStrings.length; ++i) {
2999 if ((null != CCNProtocolDTagsStrings[i]) && (CCNProtocolDTagsStrings[i] == tagName)) {
3000 return i;
3001 }
3002 }
3003 if (CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT == tagName) {
3004 return CCNProtocolDTags.CCNProtocolDataUnit;
3005 }
3006 return null;
3007};
3008
3009//console.log(stringToTag(64));
3010var BinaryXMLDecoder = function BinaryXMLDecoder(istream){
3011 var MARK_LEN=512;
3012 var DEBUG_MAX_LEN = 32768;
3013
3014 this.istream = istream;
3015 this.offset = 0;
3016};
3017
3018BinaryXMLDecoder.prototype.readAttributes = function(
3019 //TreeMap<String,String>
3020 attributes){
3021
3022 if (null == attributes) {
3023 return;
3024 }
3025
3026 try {
3027
3028 //this.TypeAndVal
3029 var nextTV = this.peekTypeAndVal();
3030
3031 while ((null != nextTV) && ((XML_ATTR == nextTV.type()) ||
3032 (XML_DATTR == nextTV.type()))) {
3033
3034 //this.TypeAndVal
3035 var thisTV = this.decodeTypeAndVal();
3036
3037 var attributeName = null;
3038 if (XML_ATTR == thisTV.type()) {
3039
3040 attributeName = this.decodeUString(thisTV.val()+1);
3041
3042 } else if (XML_DATTR == thisTV.type()) {
3043 // DKS TODO are attributes same or different dictionary?
3044 attributeName = tagToString(thisTV.val());
3045 if (null == attributeName) {
3046 throw new ContentDecodingException(new Error("Unknown DATTR value" + thisTV.val()));
3047 }
3048 }
3049
3050 var attributeValue = this.decodeUString();
3051
3052 attributes.put(attributeName, attributeValue);
3053
3054 nextTV = this.peekTypeAndVal();
3055 }
3056
3057 } catch ( e) {
3058
3059 throw new ContentDecodingException(new Error("readStartElement", e));
3060 }
3061};
3062
3063
3064BinaryXMLDecoder.prototype.initializeDecoding = function() {
3065 //if (!this.istream.markSupported()) {
3066 //throw new IllegalArgumentException(this.getClass().getName() + ": input stream must support marking!");
3067 //}
3068}
3069
3070BinaryXMLDecoder.prototype.readStartDocument = function(){
3071 // Currently no start document in binary encoding.
3072 }
3073
3074BinaryXMLDecoder.prototype.readEndDocument = function() {
3075 // Currently no end document in binary encoding.
3076 };
3077
3078BinaryXMLDecoder.prototype.readStartElement = function(
3079 //String
3080 startTag,
3081 //TreeMap<String, String>
3082 attributes) {
3083
3084
3085 //NOT SURE
3086 //if(typeof startTag == 'number')
3087 //startTag = tagToString(startTag);
3088
3089 //TypeAndVal
3090 tv = this.decodeTypeAndVal();
3091
3092 if (null == tv) {
3093 throw new ContentDecodingException(new Error("Expected start element: " + startTag + " got something not a tag."));
3094 }
3095
3096 //String
3097 var decodedTag = null;
3098 //console.log(tv);
3099 //console.log(typeof tv);
3100
3101 //console.log(XML_TAG);
3102 if (tv.type() == XML_TAG) {
3103 //console.log('got here');
3104 //Log.info(Log.FAC_ENCODING, "Unexpected: got tag in readStartElement; looking for tag " + startTag + " got length: " + (int)tv.val()+1);
3105 // Tag value represents length-1 as tags can never be empty.
3106 var valval ;
3107 if(typeof tv.val() == 'string'){
3108 valval = (parseInt(tv.val())) + 1;
3109 }
3110 else
3111 valval = (tv.val())+ 1;
3112
3113 //console.log('valval is ' +valval);
3114
3115 decodedTag = this.decodeUString(valval);
3116
3117 } else if (tv.type() == XML_DTAG) {
3118 //console.log('gothere');
3119 //console.log(tv.val());
3120 //decodedTag = tagToString(tv.val());
3121 //console.log()
3122 decodedTag = tv.val();
3123 }
3124
3125 //console.log(decodedTag);
3126 //console.log('startTag is '+startTag);
3127
3128
3129 if ((null == decodedTag) || decodedTag != startTag ) {
3130 console.log('expecting '+ startTag + ' but got '+ decodedTag);
3131 throw new ContentDecodingException(new Error("Expected start element: " + startTag + " got: " + decodedTag + "(" + tv.val() + ")"));
3132 }
3133
3134 // DKS: does not read attributes out of stream if caller doesn't
3135 // ask for them. Should possibly peek and skip over them regardless.
3136 // TODO: fix this
3137 if (null != attributes) {
3138 readAttributes(attributes);
3139 }
3140 }
3141
3142
3143BinaryXMLDecoder.prototype.readAttributes = function(
3144 //TreeMap<String,String>
3145 attributes) {
3146
3147 if (null == attributes) {
3148 return;
3149 }
3150
3151 try {
3152 // Now need to get attributes.
3153 //TypeAndVal
3154 var nextTV = this.peekTypeAndVal();
3155
3156 while ((null != nextTV) && ((XML_ATTR == nextTV.type()) ||
3157 (XML_DATTR == nextTV.type()))) {
3158
3159 // Decode this attribute. First, really read the type and value.
3160 //this.TypeAndVal
3161 var thisTV = this.decodeTypeAndVal();
3162
3163 //String
3164 var attributeName = null;
3165 if (XML_ATTR == thisTV.type()) {
3166 // Tag value represents length-1 as attribute names cannot be empty.
3167 var valval ;
3168 if(typeof tv.val() == 'string'){
3169 valval = (parseInt(tv.val())) + 1;
3170 }
3171 else
3172 valval = (tv.val())+ 1;
3173
3174 attributeName = this.decodeUString(valval);
3175
3176 } else if (XML_DATTR == thisTV.type()) {
3177 // DKS TODO are attributes same or different dictionary?
3178 attributeName = tagToString(thisTV.val());
3179 if (null == attributeName) {
3180 throw new ContentDecodingException(new Error("Unknown DATTR value" + thisTV.val()));
3181 }
3182 }
3183 // Attribute values are always UDATA
3184 //String
3185 var attributeValue = this.decodeUString();
3186
3187 //
3188 attributes.push([attributeName, attributeValue]);
3189
3190 nextTV = this.peekTypeAndVal();
3191 }
3192 } catch ( e) {
3193 throw new ContentDecodingException(new Error("readStartElement", e));
3194 }
3195};
3196
3197//returns a string
3198BinaryXMLDecoder.prototype.peekStartElementAsString = function() {
3199 //this.istream.mark(MARK_LEN);
3200
3201 //String
3202 var decodedTag = null;
3203 var previousOffset = this.offset;
3204 try {
3205 // Have to distinguish genuine errors from wrong tags. Could either use
3206 // a special exception subtype, or redo the work here.
3207 //this.TypeAndVal
3208 var tv = this.decodeTypeAndVal();
3209
3210 if (null != tv) {
3211
3212 if (tv.type() == XML_TAG) {
3213 /*if (tv.val()+1 > DEBUG_MAX_LEN) {
3214 throw new ContentDecodingException(new Error("Decoding error: length " + tv.val()+1 + " longer than expected maximum length!")(;
3215 }*/
3216
3217 // Tag value represents length-1 as tags can never be empty.
3218 var valval ;
3219 if(typeof tv.val() == 'string'){
3220 valval = (parseInt(tv.val())) + 1;
3221 }
3222 else
3223 valval = (tv.val())+ 1;
3224
3225 decodedTag = this.decodeUString(valval);
3226
3227 //Log.info(Log.FAC_ENCODING, "Unexpected: got text tag in peekStartElement; length: " + valval + " decoded tag = " + decodedTag);
3228
3229 } else if (tv.type() == XML_DTAG) {
3230 decodedTag = tagToString(tv.val());
3231 }
3232
3233 } // else, not a type and val, probably an end element. rewind and return false.
3234
3235 } catch ( e) {
3236
3237 } finally {
3238 try {
3239 this.offset = previousOffset;
3240 } catch ( e) {
3241 Log.logStackTrace(Log.FAC_ENCODING, Level.WARNING, e);
3242 throw new ContentDecodingException(new Error("Cannot reset stream! " + e.getMessage(), e));
3243 }
3244 }
3245 return decodedTag;
3246};
3247
3248BinaryXMLDecoder.prototype.peekStartElement = function(
3249 //String
3250 startTag) {
3251 //String
3252 if(typeof startTag == 'string'){
3253 var decodedTag = this.peekStartElementAsString();
3254
3255 if ((null != decodedTag) && decodedTag == startTag) {
3256 return true;
3257 }
3258 return false;
3259 }
3260 else if(typeof startTag == 'number'){
3261 var decodedTag = this.peekStartElementAsLong();
3262 if ((null != decodedTag) && decodedTag == startTag) {
3263 return true;
3264 }
3265 return false;
3266 }
3267 else{
3268 throw new ContentDecodingException(new Error("SHOULD BE STRING OR NUMBER"));
3269 }
3270}
3271//returns Long
3272BinaryXMLDecoder.prototype.peekStartElementAsLong = function() {
3273 //this.istream.mark(MARK_LEN);
3274
3275 //Long
3276 var decodedTag = null;
3277
3278 var previousOffset = this.offset;
3279
3280 try {
3281 // Have to distinguish genuine errors from wrong tags. Could either use
3282 // a special exception subtype, or redo the work here.
3283 //this.TypeAndVal
3284 var tv = this.decodeTypeAndVal();
3285
3286 if (null != tv) {
3287
3288 if (tv.type() == XML_TAG) {
3289 if (tv.val()+1 > DEBUG_MAX_LEN) {
3290 throw new ContentDecodingException(new Error("Decoding error: length " + tv.val()+1 + " longer than expected maximum length!"));
3291 }
3292
3293 var valval ;
3294 if(typeof tv.val() == 'string'){
3295 valval = (parseInt(tv.val())) + 1;
3296 }
3297 else
3298 valval = (tv.val())+ 1;
3299
3300 // Tag value represents length-1 as tags can never be empty.
3301 //String
3302 var strTag = this.decodeUString(valval);
3303
3304 decodedTag = stringToTag(strTag);
3305
3306 //Log.info(Log.FAC_ENCODING, "Unexpected: got text tag in peekStartElement; length: " + valval + " decoded tag = " + decodedTag);
3307
3308 } else if (tv.type() == XML_DTAG) {
3309 decodedTag = tv.val();
3310 }
3311
3312 } // else, not a type and val, probably an end element. rewind and return false.
3313
3314 } catch ( e) {
3315
3316 } finally {
3317 try {
3318 //this.istream.reset();
3319 this.offset = previousOffset;
3320 } catch ( e) {
3321 Log.logStackTrace(Log.FAC_ENCODING, Level.WARNING, e);
3322 throw new Error("Cannot reset stream! " + e.getMessage(), e);
3323 }
3324 }
3325 return decodedTag;
3326 };
3327
3328
3329// returns a byte[]
3330BinaryXMLDecoder.prototype.readBinaryElement = function(
3331 //long
3332 startTag,
3333 //TreeMap<String, String>
3334 attributes){
3335 //byte []
3336 var blob = null;
3337
3338 this.readStartElement(startTag, attributes);
3339 blob = this.readBlob();
3340
3341 return blob;
3342};
3343
3344
3345BinaryXMLDecoder.prototype.readEndElement = function(){
3346 if(LOG>4)console.log('this.offset is '+this.offset);
3347
3348 var next = this.istream[this.offset];
3349
3350 this.offset++;
3351 //read();
3352
3353 if(LOG>4)console.log('XML_CLOSE IS '+XML_CLOSE);
3354 if(LOG>4)console.log('next is '+next);
3355
3356 if (next != XML_CLOSE) {
3357 console.log("Expected end element, got: " + next);
3358 throw new ContentDecodingException(new Error("Expected end element, got: " + next));
3359 }
3360 };
3361
3362
3363//String
3364BinaryXMLDecoder.prototype.readUString = function(){
3365 //String
3366 var ustring = this.decodeUString();
3367 this.readEndElement();
3368 return ustring;
3369
3370 };
3371
3372
3373//returns a byte[]
3374BinaryXMLDecoder.prototype.readBlob = function() {
3375 //byte []
3376
3377 var blob = this.decodeBlob();
3378 this.readEndElement();
3379 return blob;
3380
3381 };
3382
3383
3384//CCNTime
3385BinaryXMLDecoder.prototype.readDateTime = function(
3386 //long
3387 startTag) {
3388 //byte []
3389
3390 var byteTimestamp = this.readBinaryElement(startTag);
3391
3392 //var lontimestamp = DataUtils.byteArrayToUnsignedLong(byteTimestamp);
3393
3394 byteTimestamp = DataUtils.toHex(byteTimestamp);
3395
3396
3397 byteTimestamp = parseInt(byteTimestamp, 16);
3398
3399 var lontimestamp = (byteTimestamp/ 4096) * 1000;
3400
3401 //if(lontimestamp<0) lontimestamp = - lontimestamp;
3402
3403 if(LOG>3) console.log('DECODED DATE WITH VALUE');
3404 if(LOG>3) console.log(lontimestamp);
3405
3406
3407 //CCNTime
3408 var timestamp = new CCNTime(lontimestamp);
3409 //timestamp.setDateBinary(byteTimestamp);
3410
3411 if (null == timestamp) {
3412 throw new ContentDecodingException(new Error("Cannot parse timestamp: " + DataUtils.printHexBytes(byteTimestamp)));
3413 }
3414 return timestamp;
3415};
3416
3417BinaryXMLDecoder.prototype.decodeTypeAndVal = function() {
3418
3419 /*int*/var type = -1;
3420 /*long*/var val = 0;
3421 /*boolean*/var more = true;
3422
3423 do {
3424
3425 var next = this.istream[this.offset ];
3426
3427
3428 if (next < 0) {
3429 return null;
3430 }
3431
3432 if ((0 == next) && (0 == val)) {
3433 return null;
3434 }
3435
3436 more = (0 == (next & XML_TT_NO_MORE));
3437
3438 if (more) {
3439 val = val << XML_REG_VAL_BITS;
3440 val |= (next & XML_REG_VAL_MASK);
3441 } else {
3442
3443 type = next & XML_TT_MASK;
3444 val = val << XML_TT_VAL_BITS;
3445 val |= ((next >>> XML_TT_BITS) & XML_TT_VAL_MASK);
3446 }
3447
3448 this.offset++;
3449
3450 } while (more);
3451
3452 if(LOG>3)console.log('TYPE is '+ type + ' VAL is '+ val);
3453
3454 return new TypeAndVal(type, val);
3455};
3456
3457
3458
3459//TypeAndVal
3460BinaryXMLDecoder.peekTypeAndVal = function() {
3461 //TypeAndVal
3462 var tv = null;
3463
3464 //this.istream.mark(LONG_BYTES*2);
3465
3466 var previousOffset = this.offset;
3467
3468 try {
3469 tv = this.decodeTypeAndVal();
3470 } finally {
3471 //this.istream.reset();
3472 this.offset = previousOffset;
3473 }
3474
3475 return tv;
3476};
3477
3478
3479//Uint8Array
3480BinaryXMLDecoder.prototype.decodeBlob = function(
3481 //int
3482 blobLength) {
3483
3484 if(null == blobLength){
3485 //TypeAndVal
3486 var tv = this.decodeTypeAndVal();
3487
3488 var valval ;
3489
3490 if(typeof tv.val() == 'string'){
3491 valval = (parseInt(tv.val()));
3492 }
3493 else
3494 valval = (tv.val());
3495
3496 //console.log('valval here is ' + valval);
3497 return this.decodeBlob(valval);
3498 }
3499
3500 //
3501 //Uint8Array
3502 var bytes = this.istream.subarray(this.offset, this.offset+ blobLength);
3503 this.offset += blobLength;
3504
3505 return bytes;
3506};
3507
3508var count =0;
3509
3510//String
3511BinaryXMLDecoder.prototype.decodeUString = function(
3512 //int
3513 byteLength) {
3514
3515 /*
3516 console.log('COUNT IS '+count);
3517 console.log('INPUT BYTELENGTH IS '+byteLength);
3518 count++;
3519 if(null == byteLength|| undefined == byteLength){
3520 console.log("!!!!");
3521 tv = this.decodeTypeAndVal();
3522 var valval ;
3523 if(typeof tv.val() == 'string'){
3524 valval = (parseInt(tv.val()));
3525 }
3526 else
3527 valval = (tv.val());
3528
3529 if(LOG>4) console.log('valval is ' + valval);
3530 byteLength= this.decodeUString(valval);
3531
3532 //if(LOG>4) console.log('byte Length found in type val is '+ byteLength.charCodeAt(0));
3533 byteLength = parseInt(byteLength);
3534
3535
3536 //byteLength = byteLength.charCodeAt(0);
3537 //if(LOG>4) console.log('byte Length found in type val is '+ byteLength);
3538 }
3539 if(LOG>4)console.log('byteLength is '+byteLength);
3540 if(LOG>4)console.log('type of byteLength is '+typeof byteLength);
3541
3542 stringBytes = this.decodeBlob(byteLength);
3543
3544 //console.log('String bytes are '+ stringBytes);
3545 //console.log('stringBytes);
3546
3547 if(LOG>4)console.log('byteLength is '+byteLength);
3548 if(LOG>4)console.log('this.offset is '+this.offset);
3549
3550 tempBuffer = this.istream.slice(this.offset, this.offset+byteLength);
3551 if(LOG>4)console.log('TEMPBUFFER IS' + tempBuffer);
3552 if(LOG>4)console.log( tempBuffer);
3553
3554 if(LOG>4)console.log('ADDING to offset value' + byteLength);
3555 this.offset+= byteLength;
3556 //if(LOG>3)console.log('read the String' + tempBuffer.toString('ascii'));
3557 //return tempBuffer.toString('ascii');//
3558
3559
3560 //if(LOG>3)console.log( 'STRING READ IS '+ DataUtils.getUTF8StringFromBytes(stringBytes) ) ;
3561 //if(LOG>3)console.log( 'STRING READ IS '+ DataUtils.getUTF8StringFromBytes(tempBuffer) ) ;
3562 //if(LOG>3)console.log(DataUtils.getUTF8StringFromBytes(tempBuffer) ) ;
3563 //return DataUtils.getUTF8StringFromBytes(tempBuffer);
3564
3565 if(LOG>3)console.log( 'STRING READ IS '+ DataUtils.toString(stringBytes) ) ;
3566 if(LOG>3)console.log( 'TYPE OF STRING READ IS '+ typeof DataUtils.toString(stringBytes) ) ;
3567
3568 return DataUtils.toString(stringBytes);*/
3569
3570 if(null == byteLength ){
3571 var tempStreamPosition = this.offset;
3572
3573 //TypeAndVal
3574 var tv = this.decodeTypeAndVal();
3575
3576 if(LOG>3)console.log('TV is '+tv);
3577 if(LOG>3)console.log(tv);
3578
3579 if(LOG>3)console.log('Type of TV is '+typeof tv);
3580
3581 if ((null == tv) || (XML_UDATA != tv.type())) { // if we just have closers left, will get back null
3582 //if (Log.isLoggable(Log.FAC_ENCODING, Level.FINEST))
3583 //Log.finest(Log.FAC_ENCODING, "Expected UDATA, got " + ((null == tv) ? " not a tag " : tv.type()) + ", assuming elided 0-length blob.");
3584
3585 this.offset = tempStreamPosition;
3586
3587 return "";
3588 }
3589
3590 return this.decodeUString(tv.val());
3591 }
3592 else{
3593 //byte []
3594 var stringBytes = this.decodeBlob(byteLength);
3595
3596 //return DataUtils.getUTF8StringFromBytes(stringBytes);
3597 return DataUtils.toString(stringBytes);
3598
3599 }
3600};
3601
3602
3603
3604
3605//OBject containg a pair of type and value
3606var TypeAndVal = function TypeAndVal(_type,_val) {
3607 this.t = _type;
3608 this.v = _val;
3609};
3610
3611TypeAndVal.prototype.type = function(){
3612 return this.t;
3613};
3614
3615TypeAndVal.prototype.val = function(){
3616 return this.v;
3617};
3618
3619
3620
3621
3622BinaryXMLDecoder.prototype.readIntegerElement =function(
3623 //String
3624 startTag) {
3625
3626 //String
3627 if(LOG>4) console.log('READING INTEGER '+ startTag);
3628 if(LOG>4) console.log('TYPE OF '+ typeof startTag);
3629
3630 var strVal = this.readUTF8Element(startTag);
3631
3632 return parseInt(strVal);
3633};
3634
3635
3636BinaryXMLDecoder.prototype.readUTF8Element =function(
3637 //String
3638 startTag,
3639 //TreeMap<String, String>
3640 attributes) {
3641 //throws Error where name == "ContentDecodingException"
3642
3643 this.readStartElement(startTag, attributes); // can't use getElementText, can't get attributes
3644 //String
3645 var strElementText = this.readUString();
3646 return strElementText;
3647};
3648
3649
3650/*
3651 * Set the offset into the input, used for the next read.
3652 */
3653BinaryXMLDecoder.prototype.seek = function(
3654 //int
3655 offset) {
3656 this.offset = offset;
3657}
3658
3659/*
3660 * Call with: throw new ContentDecodingException(new Error("message")).
3661 */
3662function ContentDecodingException(error) {
3663 this.message = error.message;
3664 // Copy lineNumber, etc. from where new Error was called.
3665 for (var prop in error)
3666 this[prop] = error[prop];
3667}
3668ContentDecodingException.prototype = new Error();
3669ContentDecodingException.prototype.name = "ContentDecodingException";
3670
Wentao Shangbd63e462012-12-03 16:19:33 -08003671/**
Wentao Shang0e291c82012-12-02 23:36:29 -08003672 * This class uses BinaryXMLDecoder to follow the structure of a ccnb binary element to
3673 * determine its end.
3674 *
3675 * @author: Jeff Thompson
3676 * See COPYING for copyright and distribution information.
3677 */
3678
3679var BinaryXMLStructureDecoder = function BinaryXMLDecoder() {
3680 this.gotElementEnd = false;
3681 this.offset = 0;
3682 this.level = 0;
3683 this.state = BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE;
3684 this.headerLength = 0;
3685 this.useHeaderBuffer = false;
Jeff Thompson96978b42012-12-29 21:59:54 -08003686 this.headerBuffer = new DynamicUint8Array(5);
Wentao Shang0e291c82012-12-02 23:36:29 -08003687 this.nBytesToRead = 0;
3688};
3689
3690BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE = 0;
3691BinaryXMLStructureDecoder.READ_BYTES = 1;
3692
3693/*
3694 * Continue scanning input starting from this.offset. If found the end of the element
3695 * which started at offset 0 then return true, else false.
3696 * If this returns false, you should read more into input and call again.
3697 * You have to pass in input each time because the array could be reallocated.
3698 * This throws an exception for badly formed ccnb.
3699 */
3700BinaryXMLStructureDecoder.prototype.findElementEnd = function(
3701 // Uint8Array
3702 input)
3703{
3704 if (this.gotElementEnd)
3705 // Someone is calling when we already got the end.
3706 return true;
3707
3708 var decoder = new BinaryXMLDecoder(input);
3709
3710 while (true) {
3711 if (this.offset >= input.length)
3712 // All the cases assume we have some input.
3713 return false;
Wentao Shang2b740e62012-12-07 00:02:53 -08003714
Wentao Shang0e291c82012-12-02 23:36:29 -08003715 switch (this.state) {
3716 case BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE:
3717 // First check for XML_CLOSE.
3718 if (this.headerLength == 0 && input[this.offset] == XML_CLOSE) {
3719 ++this.offset;
3720 // Close the level.
3721 --this.level;
3722 if (this.level == 0)
3723 // Finished.
3724 return true;
3725 if (this.level < 0)
3726 throw new Error("BinaryXMLStructureDecoder: Unexepected close tag at offset " +
3727 (this.offset - 1));
3728
3729 // Get ready for the next header.
3730 this.startHeader();
3731 break;
3732 }
3733
3734 var startingHeaderLength = this.headerLength;
3735 while (true) {
3736 if (this.offset >= input.length) {
3737 // We can't get all of the header bytes from this input. Save in headerBuffer.
3738 this.useHeaderBuffer = true;
3739 var nNewBytes = this.headerLength - startingHeaderLength;
Jeff Thompson96978b42012-12-29 21:59:54 -08003740 this.headerBuffer.set
Wentao Shang0e291c82012-12-02 23:36:29 -08003741 (input.subarray(this.offset - nNewBytes, nNewBytes), startingHeaderLength);
3742
3743 return false;
3744 }
3745 var headerByte = input[this.offset++];
3746 ++this.headerLength;
3747 if (headerByte & XML_TT_NO_MORE)
3748 // Break and read the header.
3749 break;
3750 }
3751
3752 var typeAndVal;
3753 if (this.useHeaderBuffer) {
3754 // Copy the remaining bytes into headerBuffer.
3755 nNewBytes = this.headerLength - startingHeaderLength;
Jeff Thompson96978b42012-12-29 21:59:54 -08003756 this.headerBuffer.set
Wentao Shang0e291c82012-12-02 23:36:29 -08003757 (input.subarray(this.offset - nNewBytes, nNewBytes), startingHeaderLength);
3758
Jeff Thompson96978b42012-12-29 21:59:54 -08003759 typeAndVal = new BinaryXMLDecoder(this.headerBuffer.array).decodeTypeAndVal();
Wentao Shang0e291c82012-12-02 23:36:29 -08003760 }
3761 else {
3762 // We didn't have to use the headerBuffer.
3763 decoder.seek(this.offset - this.headerLength);
3764 typeAndVal = decoder.decodeTypeAndVal();
3765 }
3766
3767 if (typeAndVal == null)
3768 throw new Error("BinaryXMLStructureDecoder: Can't read header starting at offset " +
3769 (this.offset - this.headerLength));
3770
3771 // Set the next state based on the type.
3772 var type = typeAndVal.t;
3773 if (type == XML_DATTR)
3774 // We already consumed the item. READ_HEADER_OR_CLOSE again.
3775 // ccnb has rules about what must follow an attribute, but we are just scanning.
3776 this.startHeader();
3777 else if (type == XML_DTAG || type == XML_EXT) {
3778 // Start a new level and READ_HEADER_OR_CLOSE again.
3779 ++this.level;
3780 this.startHeader();
3781 }
3782 else if (type == XML_TAG || type == XML_ATTR) {
3783 if (type == XML_TAG)
3784 // Start a new level and read the tag.
3785 ++this.level;
3786 // Minimum tag or attribute length is 1.
3787 this.nBytesToRead = typeAndVal.v + 1;
3788 this.state = BinaryXMLStructureDecoder.READ_BYTES;
3789 // ccnb has rules about what must follow an attribute, but we are just scanning.
3790 }
3791 else if (type == XML_BLOB || type == XML_UDATA) {
3792 this.nBytesToRead = typeAndVal.v;
3793 this.state = BinaryXMLStructureDecoder.READ_BYTES;
3794 }
3795 else
3796 throw new Error("BinaryXMLStructureDecoder: Unrecognized header type " + type);
3797 break;
3798
3799 case BinaryXMLStructureDecoder.READ_BYTES:
3800 var nRemainingBytes = input.length - this.offset;
3801 if (nRemainingBytes < this.nBytesToRead) {
3802 // Need more.
3803 this.offset += nRemainingBytes;
3804 this.nBytesToRead -= nRemainingBytes;
3805 return false;
3806 }
3807 // Got the bytes. Read a new header or close.
3808 this.offset += this.nBytesToRead;
3809 this.startHeader();
3810 break;
3811
3812 default:
3813 // We don't expect this to happen.
3814 throw new Error("BinaryXMLStructureDecoder: Unrecognized state " + this.state);
3815 }
3816 }
3817};
3818
3819/*
3820 * Set the state to READ_HEADER_OR_CLOSE and set up to start reading the header
3821 */
3822BinaryXMLStructureDecoder.prototype.startHeader = function() {
3823 this.headerLength = 0;
3824 this.useHeaderBuffer = false;
3825 this.state = BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE;
3826}
3827
3828/*
3829 * Set the offset into the input, used for the next read.
3830 */
3831BinaryXMLStructureDecoder.prototype.seek = function(
3832 //int
3833 offset) {
3834 this.offset = offset;
3835}
Jeff Thompson96978b42012-12-29 21:59:54 -08003836/**
Wentao Shang0e291c82012-12-02 23:36:29 -08003837 * This class contains utilities to help parse the data
3838 * author: Meki Cheraoui, Jeff Thompson
3839 * See COPYING for copyright and distribution information.
3840 */
3841
3842var DataUtils = function DataUtils(){
3843
3844
3845};
3846
3847
3848/*
3849 * NOTE THIS IS CURRENTLY NOT BEHING USED
3850 *
3851 */
3852
3853DataUtils.keyStr = "ABCDEFGHIJKLMNOP" +
3854 "QRSTUVWXYZabcdef" +
3855 "ghijklmnopqrstuv" +
3856 "wxyz0123456789+/" +
3857 "=";
3858
3859
3860/**
3861 * Raw String to Base 64
3862 */
3863DataUtils.stringtoBase64=function stringtoBase64(input) {
3864 input = escape(input);
3865 var output = "";
3866 var chr1, chr2, chr3 = "";
3867 var enc1, enc2, enc3, enc4 = "";
3868 var i = 0;
3869
3870 do {
3871 chr1 = input.charCodeAt(i++);
3872 chr2 = input.charCodeAt(i++);
3873 chr3 = input.charCodeAt(i++);
3874
3875 enc1 = chr1 >> 2;
3876 enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
3877 enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
3878 enc4 = chr3 & 63;
3879
3880 if (isNaN(chr2)) {
3881 enc3 = enc4 = 64;
3882 } else if (isNaN(chr3)) {
3883 enc4 = 64;
3884 }
3885
3886 output = output +
3887 DataUtils.keyStr.charAt(enc1) +
3888 DataUtils.keyStr.charAt(enc2) +
3889 DataUtils.keyStr.charAt(enc3) +
3890 DataUtils.keyStr.charAt(enc4);
3891 chr1 = chr2 = chr3 = "";
3892 enc1 = enc2 = enc3 = enc4 = "";
3893 } while (i < input.length);
3894
3895 return output;
3896 }
3897
3898/**
3899 * Base 64 to Raw String
3900 */
3901DataUtils.base64toString = function base64toString(input) {
3902 var output = "";
3903 var chr1, chr2, chr3 = "";
3904 var enc1, enc2, enc3, enc4 = "";
3905 var i = 0;
3906
3907 // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
3908 var base64test = /[^A-Za-z0-9\+\/\=]/g;
3909 /* Test for invalid characters. */
3910 if (base64test.exec(input)) {
3911 alert("There were invalid base64 characters in the input text.\n" +
3912 "Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\n" +
3913 "Expect errors in decoding.");
3914 }
3915
3916 input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
3917
3918 do {
3919 enc1 = DataUtils.keyStr.indexOf(input.charAt(i++));
3920 enc2 = DataUtils.keyStr.indexOf(input.charAt(i++));
3921 enc3 = DataUtils.keyStr.indexOf(input.charAt(i++));
3922 enc4 = DataUtils.keyStr.indexOf(input.charAt(i++));
3923
3924 chr1 = (enc1 << 2) | (enc2 >> 4);
3925 chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
3926 chr3 = ((enc3 & 3) << 6) | enc4;
3927
3928 output = output + String.fromCharCode(chr1);
3929
3930 if (enc3 != 64) {
3931 output = output + String.fromCharCode(chr2);
3932 }
3933 if (enc4 != 64) {
3934 output = output + String.fromCharCode(chr3);
3935 }
3936
3937 chr1 = chr2 = chr3 = "";
3938 enc1 = enc2 = enc3 = enc4 = "";
3939
3940 } while (i < input.length);
3941
3942 return unescape(output);
3943 };
3944
3945//byte []
3946
3947/**
3948 * NOT WORKING!!!!!
3949 *
3950 * Unsiged Long Number to Byte Array
3951 */
3952
3953 /*
3954DataUtils.unsignedLongToByteArray= function( value) {
3955
3956 if(LOG>4)console.log('INPUT IS '+value);
3957
3958 if( 0 == value )
3959 return [0];
3960
3961 if( 0 <= value && value <= 0x00FF ) {
3962 //byte []
3963 var bb = new Array(1);
3964 bb[0] = (value & 0x00FF);
3965 return bb;
3966 }
3967
3968 if(LOG>4) console.log('type of value is '+typeof value);
3969 if(LOG>4) console.log('value is '+value);
3970 //byte []
3971 var out = null;
3972 //int
3973 var offset = -1;
3974 for(var i = 7; i >=0; --i) {
3975 //byte
3976 console.log(i);
3977 console.log('value is '+value);
3978 console.log('(value >> (i * 8)) '+ (value >> (i * 8)) );
3979 console.log(' ((value >> (i * 8)) & 0xFF) '+ ((value >> (i * 8)) & 0xFF) );
3980
3981 var b = ((value >> (i * 8)) & 0xFF) ;
3982
3983 if(LOG>4) console.log('b is '+b);
3984
3985 if( out == null && b != 0 ) {
3986 //out = new byte[i+1];
3987 out = new Array(i+1);
3988 offset = i;
3989 }
3990
3991 if( out != null )
3992 out[ offset - i ] = b;
3993 }
3994 if(LOG>4)console.log('OUTPUT IS ');
3995 if(LOG>4)console.log(out);
3996 return out;
3997}
3998*/
3999
4000/**
4001 * NOT WORKING!!!!!
4002 *
4003 * Unsiged Long Number to Byte Array
4004 *//*
4005DataUtils.byteArrayToUnsignedLong = function(//final byte []
4006 src) {
4007 if(LOG>4) console.log('INPUT IS ');
4008 if(LOG>4) console.log(src);
4009
4010 var value = 0;
4011 for(var i = 0; i < src.length; i++) {
4012 value = value << 8;
4013 // Java will assume the byte is signed, so extend it and trim it.
4014
4015
4016 var b = ((src[i]) & 0xFF );
4017 value |= b;
4018 }
4019
4020 if(LOG>4) console.log('OUTPUT IS ');
4021
4022 if(LOG>4) console.log(value);
4023
4024 return value;
4025 }*/
4026
4027
4028/**
4029 * Hex String to Byte Array
4030 */
4031 //THIS IS NOT WORKING
4032/*
4033DataUtils.HexStringtoByteArray = function(str) {
4034 var byteArray = [];
4035 for (var i = 0; i < str.length; i++)
4036 if (str.charCodeAt(i) <= 0x7F)
4037 byteArray.push(str.charCodeAt(i));
4038 else {
4039 var h = encodeURIComponent(str.charAt(i)).substr(1).split('%');
4040 for (var j = 0; j < h.length; j++)
4041 byteArray.push(parseInt(h[j], 16));
4042 }
4043 return byteArray;
4044};
4045*/
4046
4047/**
4048 * Uint8Array to Hex String
4049 */
4050//http://ejohn.org/blog/numbers-hex-and-colors/
4051DataUtils.toHex = function(args){
4052 if (LOG>4) console.log('ABOUT TO CONVERT '+ args);
4053 //console.log(args);
4054 var ret = "";
4055 for ( var i = 0; i < args.length; i++ )
4056 ret += (args[i] < 16 ? "0" : "") + args[i].toString(16);
4057 if (LOG>4) console.log('Converted to: ' + ret);
4058 return ret; //.toUpperCase();
4059}
4060
4061/**
4062 * Raw string to hex string.
4063 */
4064DataUtils.stringToHex = function(args){
4065 var ret = "";
4066 for (var i = 0; i < args.length; ++i) {
4067 var value = args.charCodeAt(i);
4068 ret += (value < 16 ? "0" : "") + value.toString(16);
4069 }
4070 return ret;
4071}
4072
4073/**
4074 * Uint8Array to raw string.
4075 */
4076DataUtils.toString = function(args){
4077 //console.log(arguments);
4078 var ret = "";
4079 for ( var i = 0; i < args.length; i++ )
4080 ret += String.fromCharCode(args[i]);
4081 return ret;
4082}
4083
4084/**
4085 * Hex String to Uint8Array.
4086 */
4087DataUtils.toNumbers = function(str) {
4088 if (typeof str == 'string') {
4089 var ret = new Uint8Array(Math.floor(str.length / 2));
4090 var i = 0;
4091 str.replace(/(..)/g, function(str) {
4092 ret[i++] = parseInt(str, 16);
4093 });
4094 return ret;
4095 }
4096}
4097
4098/**
4099 * Hex String to raw string.
4100 */
4101DataUtils.hexToRawString = function(str) {
4102 if(typeof str =='string') {
4103 var ret = "";
4104 str.replace(/(..)/g, function(s) {
4105 ret += String.fromCharCode(parseInt(s, 16));
4106 });
4107 return ret;
4108 }
4109}
4110
4111/**
4112 * Raw String to Uint8Array.
4113 */
Jeff Thompson1a338f82012-12-29 17:07:04 -08004114DataUtils.toNumbersFromString = function(str) {
Wentao Shang0e291c82012-12-02 23:36:29 -08004115 var bytes = new Uint8Array(str.length);
4116 for(var i=0;i<str.length;i++)
4117 bytes[i] = str.charCodeAt(i);
4118 return bytes;
4119}
4120
4121/*
4122 * Encode str as utf8 and return as Uint8Array.
4123 * TODO: Use TextEncoder when available.
4124 */
4125DataUtils.stringToUtf8Array = function(str) {
4126 return DataUtils.toNumbersFromString(str2rstr_utf8(str));
4127}
4128
4129/*
4130 * arrays is an array of Uint8Array. Return a new Uint8Array which is the concatenation of all.
4131 */
4132DataUtils.concatArrays = function(arrays) {
4133 var totalLength = 0;
4134 for (var i = 0; i < arrays.length; ++i)
4135 totalLength += arrays[i].length;
4136
4137 var result = new Uint8Array(totalLength);
4138 var offset = 0;
4139 for (var i = 0; i < arrays.length; ++i) {
4140 result.set(arrays[i], offset);
4141 offset += arrays[i].length;
4142 }
4143 return result;
4144
4145}
4146
4147// TODO: Take Uint8Array and use TextDecoder when available.
4148DataUtils.decodeUtf8 = function (utftext) {
4149 var string = "";
4150 var i = 0;
4151 var c = 0;
4152 var c1 = 0;
4153 var c2 = 0;
4154
4155 while ( i < utftext.length ) {
4156
4157 c = utftext.charCodeAt(i);
4158
4159 if (c < 128) {
4160 string += String.fromCharCode(c);
4161 i++;
4162 }
4163 else if((c > 191) && (c < 224)) {
4164 c2 = utftext.charCodeAt(i+1);
4165 string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
4166 i += 2;
4167 }
4168 else {
4169 c2 = utftext.charCodeAt(i+1);
4170 var c3 = utftext.charCodeAt(i+2);
4171 string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
4172 i += 3;
4173 }
4174
4175 }
4176
4177 return string;
4178 };
4179
4180//NOT WORKING
4181/*
4182DataUtils.getUTF8StringFromBytes = function(bytes) {
4183
4184 bytes = toString(bytes);
4185
4186 var ix = 0;
4187
4188 if( bytes.slice(0,3) == "\xEF\xBB\xBF") {
4189 ix = 3;
4190 }
4191
4192 var string = "";
4193 for( ; ix < bytes.length; ix++ ) {
4194 var byte1 = bytes[ix].charCodeAt(0);
4195 if( byte1 < 0x80 ) {
4196 string += String.fromCharCode(byte1);
4197 } else if( byte1 >= 0xC2 && byte1 < 0xE0 ) {
4198 var byte2 = bytes[++ix].charCodeAt(0);
4199 string += String.fromCharCode(((byte1&0x1F)<<6) + (byte2&0x3F));
4200 } else if( byte1 >= 0xE0 && byte1 < 0xF0 ) {
4201 var byte2 = bytes[++ix].charCodeAt(0);
4202 var byte3 = bytes[++ix].charCodeAt(0);
4203 string += String.fromCharCode(((byte1&0xFF)<<12) + ((byte2&0x3F)<<6) + (byte3&0x3F));
4204 } else if( byte1 >= 0xF0 && byte1 < 0xF5) {
4205 var byte2 = bytes[++ix].charCodeAt(0);
4206 var byte3 = bytes[++ix].charCodeAt(0);
4207 var byte4 = bytes[++ix].charCodeAt(0);
4208 var codepoint = ((byte1&0x07)<<18) + ((byte2&0x3F)<<12)+ ((byte3&0x3F)<<6) + (byte4&0x3F);
4209 codepoint -= 0x10000;
4210 string += String.fromCharCode(
4211 (codepoint>>10) + 0xD800,
4212 (codepoint&0x3FF) + 0xDC00
4213 );
4214 }
4215 }
4216
4217 return string;
4218}*/
4219
4220/**
4221 * Return true if a1 and a2 are the same length with equal elements.
4222 */
4223DataUtils.arraysEqual = function(a1, a2){
4224 if (a1.length != a2.length)
4225 return false;
4226
4227 for (var i = 0; i < a1.length; ++i) {
4228 if (a1[i] != a2[i])
4229 return false;
4230 }
4231
4232 return true;
4233};
4234
4235/*
4236 * Convert the big endian Uint8Array to an unsigned int.
4237 * Don't check for overflow.
4238 */
4239DataUtils.bigEndianToUnsignedInt = function(bytes) {
4240 var result = 0;
4241 for (var i = 0; i < bytes.length; ++i) {
4242 result <<= 8;
4243 result += bytes[i];
4244 }
4245 return result;
4246};
4247
4248/*
4249 * Convert the int value to a new big endian Uint8Array and return.
4250 * If value is 0 or negative, return Uint8Array(0).
4251 */
4252DataUtils.nonNegativeIntToBigEndian = function(value) {
4253 value = Math.round(value);
4254 if (value <= 0)
4255 return new Uint8Array(0);
4256
4257 // Assume value is not over 64 bits.
4258 var size = 8;
4259 var result = new Uint8Array(size);
4260 var i = 0;
4261 while (value != 0) {
4262 ++i;
4263 result[size - i] = value & 0xff;
4264 value >>= 8;
4265 }
4266 return result.subarray(size - i, size);
4267};
Jeff Thompson3dfddaa2012-12-16 17:55:47 -08004268
4269/*
4270 * Modify array to randomly shuffle the elements.
4271 */
4272DataUtils.shuffle = function(array) {
4273 for (var i = array.length - 1; i >= 1; --i) {
4274 // j is from 0 to i.
4275 var j = Math.floor(Math.random() * (i + 1));
4276 var temp = array[i];
4277 array[i] = array[j];
4278 array[j] = temp;
4279 }
4280}
Wentao Shangbd63e462012-12-03 16:19:33 -08004281/**
Wentao Shang0e291c82012-12-02 23:36:29 -08004282 * This file contains utilities to help encode and decode NDN objects.
4283 * author: Meki Cheraoui
4284 * See COPYING for copyright and distribution information.
4285 */
4286
4287function encodeToHexInterest(interest){
4288 return DataUtils.toHex(encodeToBinaryInterest(interest));
4289}
4290
4291
4292function encodeToBinaryInterest(interest) {
4293 var enc = new BinaryXMLEncoder();
4294 interest.to_ccnb(enc);
4295
4296 return enc.getReducedOstream();
4297}
4298
4299
4300function encodeToHexContentObject(co){
4301 return DataUtils.toHex(encodeToBinaryContentObject(co));
4302}
4303
4304function encodeToBinaryContentObject(co){
4305 var enc = new BinaryXMLEncoder();
4306 co.to_ccnb(enc);
4307
4308 return enc.getReducedOstream();
4309}
4310
4311function encodeForwardingEntry(co){
4312 var enc = new BinaryXMLEncoder();
4313
4314 co.to_ccnb(enc);
4315
4316 var bytes = enc.getReducedOstream();
4317
4318 return bytes;
4319
4320
4321}
4322
4323
4324
4325function decodeHexFaceInstance(result){
4326
4327 var numbers = DataUtils.toNumbers(result);
4328
4329
4330 decoder = new BinaryXMLDecoder(numbers);
4331
4332 if(LOG>3)console.log('DECODING HEX FACE INSTANCE \n'+numbers);
4333
4334 var faceInstance = new FaceInstance();
4335
4336 faceInstance.from_ccnb(decoder);
4337
4338 return faceInstance;
4339
4340}
4341
4342
4343
4344function decodeHexInterest(result){
4345 var numbers = DataUtils.toNumbers(result);
4346
4347 decoder = new BinaryXMLDecoder(numbers);
4348
4349 if(LOG>3)console.log('DECODING HEX INTERST \n'+numbers);
4350
4351 var interest = new Interest();
4352
4353 interest.from_ccnb(decoder);
4354
4355 return interest;
4356
4357}
4358
4359
4360
4361function decodeHexContentObject(result){
4362 var numbers = DataUtils.toNumbers(result);
4363
4364 decoder = new BinaryXMLDecoder(numbers);
4365
4366 if(LOG>3)console.log('DECODED HEX CONTENT OBJECT \n'+numbers);
4367
4368 co = new ContentObject();
4369
4370 co.from_ccnb(decoder);
4371
4372 return co;
4373
4374}
4375
4376
4377
4378function decodeHexForwardingEntry(result){
4379 var numbers = DataUtils.toNumbers(result);
4380
4381 decoder = new BinaryXMLDecoder(numbers);
4382
4383 if(LOG>3)console.log('DECODED HEX FORWARDING ENTRY \n'+numbers);
4384
4385 forwardingEntry = new ForwardingEntry();
4386
4387 forwardingEntry.from_ccnb(decoder);
4388
4389 return forwardingEntry;
4390
4391}
4392
Jeff Thompson68fccd62012-12-29 17:38:23 -08004393/*
4394 * Decode the Uint8Array which holds SubjectPublicKeyInfo and return an RSAKey.
4395 */
4396function decodeSubjectPublicKeyInfo(array) {
4397 var hex = DataUtils.toHex(array).toLowerCase();
4398 var a = _x509_getPublicKeyHexArrayFromCertHex(hex, _x509_getSubjectPublicKeyPosFromCertHex(hex, 0));
4399 var rsaKey = new RSAKey();
4400 rsaKey.setPublic(a[0], a[1]);
4401 return rsaKey;
4402}
4403
Wentao Shang0e291c82012-12-02 23:36:29 -08004404/* Return a user friendly HTML string with the contents of co.
4405 This also outputs to console.log.
4406 */
4407function contentObjectToHtml(/* ContentObject */ co) {
4408 var output ="";
4409
4410 if(co==-1)
4411 output+= "NO CONTENT FOUND"
4412 else if (co==-2)
4413 output+= "CONTENT NAME IS EMPTY"
4414 else{
4415 if(co.name!=null && co.name.components!=null){
4416 output+= "NAME: " + co.name.to_uri();
4417
4418 output+= "<br />";
4419 output+= "<br />";
4420 }
4421
4422 if(co.content !=null){
4423 output += "CONTENT(ASCII): "+ DataUtils.toString(co.content);
4424
4425 output+= "<br />";
4426 output+= "<br />";
4427 }
4428 if(co.content !=null){
4429 output += "CONTENT(hex): "+ DataUtils.toHex(co.content);
4430
4431 output+= "<br />";
4432 output+= "<br />";
4433 }
4434 if(co.signature !=null && co.signature.signature!=null){
4435 output += "SIGNATURE(hex): "+ DataUtils.toHex(co.signature.signature);
4436
4437 output+= "<br />";
4438 output+= "<br />";
4439 }
4440 if(co.signedInfo !=null && co.signedInfo.publisher!=null && co.signedInfo.publisher.publisherPublicKeyDigest!=null){
4441 output += "Publisher Public Key Digest(hex): "+ DataUtils.toHex(co.signedInfo.publisher.publisherPublicKeyDigest);
4442
4443 output+= "<br />";
4444 output+= "<br />";
4445 }
4446 if(co.signedInfo !=null && co.signedInfo.timestamp!=null){
4447 var d = new Date();
4448 d.setTime( co.signedInfo.timestamp.msec );
4449
4450 var bytes = [217, 185, 12, 225, 217, 185, 12, 225];
4451
4452 output += "TimeStamp: "+d;
4453 output+= "<br />";
4454 output += "TimeStamp(number): "+ co.signedInfo.timestamp.msec;
4455
4456 output+= "<br />";
4457 }
4458 if(co.signedInfo !=null && co.signedInfo.finalBlockID!=null){
4459 output += "FinalBlockID: "+ DataUtils.toHex(co.signedInfo.finalBlockID);
4460 output+= "<br />";
4461 }
4462 if(co.signedInfo!=null && co.signedInfo.locator!=null && co.signedInfo.locator.certificate!=null){
Jeff Thompson68fccd62012-12-29 17:38:23 -08004463 var certificateHex = DataUtils.toHex(co.signedInfo.locator.certificate).toLowerCase();
Wentao Shang0e291c82012-12-02 23:36:29 -08004464 var signature = DataUtils.toHex(co.signature.signature).toLowerCase();
4465 var input = DataUtils.toString(co.rawSignatureData);
4466
Jeff Thompson68fccd62012-12-29 17:38:23 -08004467 output += "Hex Certificate: "+ certificateHex ;
Wentao Shang0e291c82012-12-02 23:36:29 -08004468
4469 output+= "<br />";
4470 output+= "<br />";
4471
Wentao Shang0e291c82012-12-02 23:36:29 -08004472 var x509 = new X509();
Jeff Thompson68fccd62012-12-29 17:38:23 -08004473 x509.readCertHex(certificateHex);
Jeff Thompson253cab42012-12-29 17:48:40 -08004474 output += "Public key (hex) modulus: " + x509.subjectPublicKeyRSA.n.toString(16) + "<br/>";
4475 output += "exponent: " + x509.subjectPublicKeyRSA.e.toString(16) + "<br/>";
4476 output += "<br/>";
Wentao Shang0e291c82012-12-02 23:36:29 -08004477
Wentao Shang0e291c82012-12-02 23:36:29 -08004478 var result = x509.subjectPublicKeyRSA.verifyByteArray(co.rawSignatureData, signature);
4479 if(LOG>2) console.log('result is '+result);
4480
4481 var n = x509.subjectPublicKeyRSA.n;
4482 var e = x509.subjectPublicKeyRSA.e;
4483
4484 if(LOG>2) console.log('PUBLIC KEY n after is ');
4485 if(LOG>2) console.log(n);
4486
4487 if(LOG>2) console.log('EXPONENT e after is ');
4488 if(LOG>2) console.log(e);
4489
Wentao Shang0e291c82012-12-02 23:36:29 -08004490 if(result)
Jeff Thompson68fccd62012-12-29 17:38:23 -08004491 output += 'SIGNATURE VALID';
Wentao Shang0e291c82012-12-02 23:36:29 -08004492 else
Jeff Thompson68fccd62012-12-29 17:38:23 -08004493 output += 'SIGNATURE INVALID';
Wentao Shang0e291c82012-12-02 23:36:29 -08004494
4495 //output += "VALID: "+ toHex(co.signedInfo.locator.publicKey);
4496
4497 output+= "<br />";
4498 output+= "<br />";
4499
4500 //if(LOG>4) console.log('str'[1]);
4501 }
4502 if(co.signedInfo!=null && co.signedInfo.locator!=null && co.signedInfo.locator.publicKey!=null){
Wentao Shang0e291c82012-12-02 23:36:29 -08004503 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
Jeff Thompson68fccd62012-12-29 17:38:23 -08004508 output += "Public key: " + publickeyHex;
Wentao Shang0e291c82012-12-02 23:36:29 -08004509
4510 output+= "<br />";
4511 output+= "<br />";
4512
4513 if(LOG>2) console.log(" ContentName + SignedInfo + Content = "+input);
Wentao Shang0e291c82012-12-02 23:36:29 -08004514 if(LOG>2) console.log(" PublicKeyHex = "+publickeyHex );
4515 if(LOG>2) console.log(" PublicKeyString = "+publickeyString );
4516
4517 if(LOG>2) console.log(" Signature "+signature );
4518
4519 if(LOG>2) console.log(" Signature NOW IS" );
4520
4521 if(LOG>2) console.log(co.signature.signature);
Jeff Thompson68fccd62012-12-29 17:38:23 -08004522
4523 var rsakey = decodeSubjectPublicKeyInfo(co.signedInfo.locator.publicKey);
Wentao Shang0e291c82012-12-02 23:36:29 -08004524
Jeff Thompson68fccd62012-12-29 17:38:23 -08004525 output += "Public key (hex) modulus: " + rsakey.n.toString(16) + "<br/>";
4526 output += "exponent: " + rsakey.e.toString(16) + "<br/>";
4527 output += "<br/>";
4528
Wentao Shang0e291c82012-12-02 23:36:29 -08004529 var result = rsakey.verifyByteArray(co.rawSignatureData,signature);
4530 // var result = rsakey.verifyString(input, signature);
4531
Wentao Shang2b740e62012-12-07 00:02:53 -08004532 if(LOG>2) console.log('PUBLIC KEY n after is ');
4533 if(LOG>2) console.log(rsakey.n);
Wentao Shang0e291c82012-12-02 23:36:29 -08004534
Wentao Shang2b740e62012-12-07 00:02:53 -08004535 if(LOG>2) console.log('EXPONENT e after is ');
4536 if(LOG>2) console.log(rsakey.e);
Wentao Shang0e291c82012-12-02 23:36:29 -08004537
4538 if(result)
4539 output += 'SIGNATURE VALID';
4540 else
4541 output += 'SIGNATURE INVALID';
4542
4543 //output += "VALID: "+ toHex(co.signedInfo.locator.publicKey);
4544
4545 output+= "<br />";
4546 output+= "<br />";
4547
4548 //if(LOG>4) console.log('str'[1]);
4549 }
4550 }
4551
4552 return output;
4553}
Jeff Thompson1a338f82012-12-29 17:07:04 -08004554
4555
Wentao Shangbd63e462012-12-03 16:19:33 -08004556/**
Wentao Shang0e291c82012-12-02 23:36:29 -08004557 * @author: Meki Cheraoui
4558 * See COPYING for copyright and distribution information.
4559 */
4560
4561var KeyManager = function KeyManager(){
4562
4563
4564//Certificate
4565
4566this.certificate = 'MIIBmzCCAQQCCQC32FyQa61S7jANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwd'+
4567
4568'heGVsY2R2MB4XDTEyMDQyODIzNDQzN1oXDTEyMDUyODIzNDQzN1owEjEQMA4GA1'+
4569
4570'UEAxMHYXhlbGNkdjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4X0wp9goq'+
4571
4572'xuECxdULcr2IHr9Ih4Iaypg0Wy39URIup8/CLzQmdsh3RYqd55hqonu5VTTpH3i'+
4573
4574'MLx6xZDVJAZ8OJi7pvXcQ2C4Re2kjL2c8SanI0RfDhlS1zJadfr1VhRPmpivcYa'+
4575
4576'wJ4aFuOLAi+qHFxtN7lhcGCgpW1OV60oXd58CAwEAATANBgkqhkiG9w0BAQUFAA'+
4577
4578'OBgQDLOrA1fXzSrpftUB5Ro6DigX1Bjkf7F5Bkd69hSVp+jYeJFBBlsILQAfSxU'+
4579
4580'ZPQtD+2Yc3iCmSYNyxqu9PcufDRJlnvB7PG29+L3y9lR37tetzUV9eTscJ7rdp8'+
4581
4582'Wt6AzpW32IJ/54yKNfP7S6ZIoIG+LP6EIxq6s8K1MXRt8uBJKw==';
4583
4584
4585//this.publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhfTCn2CirG4QLF1QtyvYgev0iHghrKmDRbLf1REi6nz8IvNCZ2yHdFip3nmGqie7lVNOkfeIwvHrFkNUkBnw4mLum9dxDYLhF7aSMvZzxJqcjRF8OGVLXMlp1+vVWFE+amK9xhrAnhoW44sCL6ocXG03uWFwYKClbU5XrShd3nwIDAQAB';
4586this.publicKey ='30819F300D06092A864886F70D010101050003818D0030818902818100E17D30A7D828AB1B840B17542DCAF6207AFD221E086B2A60D16CB7F54448BA9F3F08BCD099DB21DD162A779E61AA89EEE554D3A47DE230BC7AC590D524067C3898BBA6F5DC4360B845EDA48CBD9CF126A723445F0E1952D7325A75FAF556144F9A98AF7186B0278685B8E2C08BEA87171B4DEE585C1828295B5395EB4A17779F0203010001';
4587//Private Key
4588
4589this.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';
4590
4591
4592/*
4593 this.certificate =
4594 'MIIBvTCCASYCCQD55fNzc0WF7TANBgkqhkiG9w0BAQUFADAjMQswCQYDVQQGEwJK'+
4595 'UDEUMBIGA1UEChMLMDAtVEVTVC1SU0EwHhcNMTAwNTI4MDIwODUxWhcNMjAwNTI1'+
4596 'MDIwODUxWjAjMQswCQYDVQQGEwJKUDEUMBIGA1UEChMLMDAtVEVTVC1SU0EwgZ8w'+
4597 'DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANGEYXtfgDRlWUSDn3haY4NVVQiKI9Cz'+
4598 'Thoua9+DxJuiseyzmBBe7Roh1RPqdvmtOHmEPbJ+kXZYhbozzPRbFGHCJyBfCLzQ'+
4599 'fVos9/qUQ88u83b0SFA2MGmQWQAlRtLy66EkR4rDRwTj2DzR4EEXgEKpIvo8VBs/'+
4600 '3+sHLF3ESgAhAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAEZ6mXFFq3AzfaqWHmCy1'+
4601 'ARjlauYAa8ZmUFnLm0emg9dkVBJ63aEqARhtok6bDQDzSJxiLpCEF6G4b/Nv/M/M'+
4602 'LyhP+OoOTmETMegAVQMq71choVJyOFE5BtQa6M/lCHEOya5QUfoRF2HF9EjRF44K'+
4603 '3OK+u3ivTSj3zwjtpudY5Xo=';
4604
4605 this.privateKey =
4606 'MIICWwIBAAKBgQDRhGF7X4A0ZVlEg594WmODVVUIiiPQs04aLmvfg8SborHss5gQ'+
4607 'Xu0aIdUT6nb5rTh5hD2yfpF2WIW6M8z0WxRhwicgXwi80H1aLPf6lEPPLvN29EhQ'+
4608 'NjBpkFkAJUbS8uuhJEeKw0cE49g80eBBF4BCqSL6PFQbP9/rByxdxEoAIQIDAQAB'+
4609 'AoGAA9/q3Zk6ib2GFRpKDLO/O2KMnAfR+b4XJ6zMGeoZ7Lbpi3MW0Nawk9ckVaX0'+
4610 'ZVGqxbSIX5Cvp/yjHHpww+QbUFrw/gCjLiiYjM9E8C3uAF5AKJ0r4GBPl4u8K4bp'+
4611 'bXeSxSB60/wPQFiQAJVcA5xhZVzqNuF3EjuKdHsw+dk+dPECQQDubX/lVGFgD/xY'+
4612 'uchz56Yc7VHX+58BUkNSewSzwJRbcueqknXRWwj97SXqpnYfKqZq78dnEF10SWsr'+
4613 '/NMKi+7XAkEA4PVqDv/OZAbWr4syXZNv/Mpl4r5suzYMMUD9U8B2JIRnrhmGZPzL'+
4614 'x23N9J4hEJ+Xh8tSKVc80jOkrvGlSv+BxwJAaTOtjA3YTV+gU7Hdza53sCnSw/8F'+
4615 'YLrgc6NOJtYhX9xqdevbyn1lkU0zPr8mPYg/F84m6MXixm2iuSz8HZoyzwJARi2p'+
4616 'aYZ5/5B2lwroqnKdZBJMGKFpUDn7Mb5hiSgocxnvMkv6NjT66Xsi3iYakJII9q8C'+
4617 'Ma1qZvT/cigmdbAh7wJAQNXyoizuGEltiSaBXx4H29EdXNYWDJ9SS5f070BRbAIl'+
4618 'dqRh3rcNvpY6BKJqFapda1DjdcncZECMizT/GMrc1w==';
4619
4620 */
4621};
4622
4623
4624KeyManager.prototype.verify = function verify(message,signature){
4625
4626 var input = message;
4627
4628 var _PEM_X509CERT_STRING_ = this.certificate;
4629
4630 var x509 = new X509();
4631
4632 x509.readCertPEM(_PEM_X509CERT_STRING_);
4633
4634 var result = x509.subjectPublicKeyRSA.verifyString(input, signature);
4635
4636 return result;
4637};
4638
4639KeyManager.prototype.sign= function sign(message){
4640
4641 var input = message;
4642
4643 var _PEM_PRIVATE_KEY_STRING_ = this.privateKey;
4644
4645 var rsa = new RSAKey();
4646
4647 rsa.readPrivateKeyFromPEMString(_PEM_PRIVATE_KEY_STRING_);
4648
4649 var hSig = rsa.signString(input, "sha256");
4650
4651 return hSig;
4652
4653};
4654
4655
4656
4657var globalKeyManager = new KeyManager();
4658//var KeyPair = { "public" : "PUBLIC KEY" , "private" : "PRIVATE KEY" };
4659
4660
4661/*
4662 * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined
4663 * in FIPS 180-2
4664 * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
4665 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
4666 * Distributed under the BSD License
4667 * See http://pajhome.org.uk/crypt/md5 for details.
4668 * Also http://anmar.eu.org/projects/jssha2/
4669 */
4670
4671/*
4672 * Configurable variables. You may need to tweak these to be compatible with
4673 * the server-side, but the defaults work in most cases.
4674 */
4675var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
4676var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
4677
4678/*
4679 * These are the functions you'll usually want to call
4680 * They take string arguments and return either hex or base-64 encoded strings
4681 */
4682
4683//@author axelcdv
4684/**
4685 * Computes the Sha-256 hash of the given byte array
4686 * @param {byte[]}
4687 * @return the hex string corresponding to the Sha-256 hash of the byte array
4688 */
4689function hex_sha256_from_bytes(byteArray){
4690 return rstr2hex(binb2rstr(binb_sha256( byteArray2binb(byteArray), byteArray.length * 8)));
4691}
4692
4693function hex_sha256(s) { return rstr2hex(rstr_sha256(str2rstr_utf8(s))); }
4694function b64_sha256(s) { return rstr2b64(rstr_sha256(str2rstr_utf8(s))); }
4695function any_sha256(s, e) { return rstr2any(rstr_sha256(str2rstr_utf8(s)), e); }
4696function hex_hmac_sha256(k, d)
4697 { return rstr2hex(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d))); }
4698function b64_hmac_sha256(k, d)
4699 { return rstr2b64(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d))); }
4700function any_hmac_sha256(k, d, e)
4701 { return rstr2any(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
4702
4703
4704/*
4705 function hex_sha256(s) { return rstr2hex(rstr_sha256(s)); }
4706function b64_sha256(s) { return rstr2b64(rstr_sha256(s)); }
4707function any_sha256(s, e) { return rstr2any(rstr_sha256(s), e); }
4708function hex_hmac_sha256(k, d)
4709 { return rstr2hex(rstr_hmac_sha256(str2rstr_utf8(k), d)); }
4710function b64_hmac_sha256(k, d)
4711 { return rstr2b64(rstr_hmac_sha256(str2rstr_utf8(k), d)); }
4712function any_hmac_sha256(k, d, e)
4713 { return rstr2any(rstr_hmac_sha256(str2rstr_utf8(k), d), e); }
4714*/
4715
4716/*
4717 * Perform a simple self-test to see if the VM is working
4718 */
4719function sha256_vm_test()
4720{
4721 return hex_sha256("abc").toLowerCase() ==
4722 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad";
4723}
4724
4725/**
4726 * Calculate the sha256 of a raw string
4727 * @param s: the raw string
4728 */
4729function rstr_sha256(s)
4730{
4731 return binb2rstr(binb_sha256(rstr2binb(s), s.length * 8));
4732}
4733
4734/**
4735 * Calculate the HMAC-sha256 of a key and some data (raw strings)
4736 */
4737function rstr_hmac_sha256(key, data)
4738{
4739 var bkey = rstr2binb(key);
4740 if(bkey.length > 16) bkey = binb_sha256(bkey, key.length * 8);
4741
4742 var ipad = Array(16), opad = Array(16);
4743 for(var i = 0; i < 16; i++)
4744 {
4745 ipad[i] = bkey[i] ^ 0x36363636;
4746 opad[i] = bkey[i] ^ 0x5C5C5C5C;
4747 }
4748
4749 var hash = binb_sha256(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
4750 return binb2rstr(binb_sha256(opad.concat(hash), 512 + 256));
4751}
4752
4753/**
4754 * Convert a raw string to a hex string
4755 */
4756function rstr2hex(input)
4757{
4758 try { hexcase } catch(e) { hexcase=0; }
4759 var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
4760 var output = "";
4761 var x;
4762 for(var i = 0; i < input.length; i++)
4763 {
4764 x = input.charCodeAt(i);
4765 output += hex_tab.charAt((x >>> 4) & 0x0F)
4766 + hex_tab.charAt( x & 0x0F);
4767 }
4768 return output;
4769}
4770
4771/*
4772 * Convert a raw string to a base-64 string
4773 */
4774function rstr2b64(input)
4775{
4776 try { b64pad } catch(e) { b64pad=''; }
4777 var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4778 var output = "";
4779 var len = input.length;
4780 for(var i = 0; i < len; i += 3)
4781 {
4782 var triplet = (input.charCodeAt(i) << 16)
4783 | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
4784 | (i + 2 < len ? input.charCodeAt(i+2) : 0);
4785 for(var j = 0; j < 4; j++)
4786 {
4787 if(i * 8 + j * 6 > input.length * 8) output += b64pad;
4788 else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
4789 }
4790 }
4791 return output;
4792}
4793
4794/*
4795 * Convert a raw string to an arbitrary string encoding
4796 */
4797function rstr2any(input, encoding)
4798{
4799 var divisor = encoding.length;
4800 var remainders = Array();
4801 var i, q, x, quotient;
4802
4803 /* Convert to an array of 16-bit big-endian values, forming the dividend */
4804 var dividend = Array(Math.ceil(input.length / 2));
4805 for(i = 0; i < dividend.length; i++)
4806 {
4807 dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
4808 }
4809
4810 /*
4811 * Repeatedly perform a long division. The binary array forms the dividend,
4812 * the length of the encoding is the divisor. Once computed, the quotient
4813 * forms the dividend for the next step. We stop when the dividend is zero.
4814 * All remainders are stored for later use.
4815 */
4816 while(dividend.length > 0)
4817 {
4818 quotient = Array();
4819 x = 0;
4820 for(i = 0; i < dividend.length; i++)
4821 {
4822 x = (x << 16) + dividend[i];
4823 q = Math.floor(x / divisor);
4824 x -= q * divisor;
4825 if(quotient.length > 0 || q > 0)
4826 quotient[quotient.length] = q;
4827 }
4828 remainders[remainders.length] = x;
4829 dividend = quotient;
4830 }
4831
4832 /* Convert the remainders to the output string */
4833 var output = "";
4834 for(i = remainders.length - 1; i >= 0; i--)
4835 output += encoding.charAt(remainders[i]);
4836
4837 /* Append leading zero equivalents */
4838 var full_length = Math.ceil(input.length * 8 /
4839 (Math.log(encoding.length) / Math.log(2)))
4840 for(i = output.length; i < full_length; i++)
4841 output = encoding[0] + output;
4842
4843 return output;
4844}
4845
4846/*
4847 * Encode a string as utf-8.
4848 * For efficiency, this assumes the input is valid utf-16.
4849 */
4850function str2rstr_utf8(input)
4851{
4852 var output = "";
4853 var i = -1;
4854 var x, y;
4855
4856 while(++i < input.length)
4857 {
4858 /* Decode utf-16 surrogate pairs */
4859 x = input.charCodeAt(i);
4860 y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
4861 if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
4862 {
4863 x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
4864 i++;
4865 }
4866
4867 /* Encode output as utf-8 */
4868 if(x <= 0x7F)
4869 output += String.fromCharCode(x);
4870 else if(x <= 0x7FF)
4871 output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
4872 0x80 | ( x & 0x3F));
4873 else if(x <= 0xFFFF)
4874 output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
4875 0x80 | ((x >>> 6 ) & 0x3F),
4876 0x80 | ( x & 0x3F));
4877 else if(x <= 0x1FFFFF)
4878 output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
4879 0x80 | ((x >>> 12) & 0x3F),
4880 0x80 | ((x >>> 6 ) & 0x3F),
4881 0x80 | ( x & 0x3F));
4882 }
4883 return output;
4884}
4885
4886/*
4887 * Encode a string as utf-16
4888 */
4889function str2rstr_utf16le(input)
4890{
4891 var output = "";
4892 for(var i = 0; i < input.length; i++)
4893 output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
4894 (input.charCodeAt(i) >>> 8) & 0xFF);
4895 return output;
4896}
4897
4898function str2rstr_utf16be(input)
4899{
4900 var output = "";
4901 for(var i = 0; i < input.length; i++)
4902 output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
4903 input.charCodeAt(i) & 0xFF);
4904 return output;
4905}
4906
4907/**
4908 * Convert a raw string to an array of big-endian words
4909 * Characters >255 have their high-byte silently ignored.
4910 */
4911function rstr2binb(input)
4912{
4913 //console.log('Raw string comming is '+input);
4914 var output = Array(input.length >> 2);
Wentao Shangc0311e52012-12-03 10:38:23 -08004915 /* JavaScript automatically zeroizes a new array.
Wentao Shang0e291c82012-12-02 23:36:29 -08004916 for(var i = 0; i < output.length; i++)
4917 output[i] = 0;
Wentao Shangc0311e52012-12-03 10:38:23 -08004918 */
Wentao Shang0e291c82012-12-02 23:36:29 -08004919 for(var i = 0; i < input.length * 8; i += 8)
4920 output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
4921 return output;
4922}
4923
4924/**
4925 * @author axelcdv
4926 * Convert a byte array to an array of big-endian words
4927 * @param {byte[]} input
4928 * @return the array of big-endian words
4929 */
4930function byteArray2binb(input){
4931 //console.log("Byte array coming is " + input);
4932 var output = Array(input.length >> 2);
Wentao Shangc0311e52012-12-03 10:38:23 -08004933 /* JavaScript automatically zeroizes a new array.
Wentao Shang0e291c82012-12-02 23:36:29 -08004934 for(var i = 0; i < output.length; i++)
4935 output[i] = 0;
Wentao Shangc0311e52012-12-03 10:38:23 -08004936 */
Wentao Shang0e291c82012-12-02 23:36:29 -08004937 for(var i = 0; i < input.length * 8; i += 8)
4938 output[i>>5] |= (input[i / 8] & 0xFF) << (24 - i % 32);
4939 return output;
4940}
4941
4942/*
4943 * Convert an array of big-endian words to a string
4944 */
4945function binb2rstr(input)
4946{
4947 var output = "";
4948 for(var i = 0; i < input.length * 32; i += 8)
4949 output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
4950 return output;
4951}
4952
4953/*
4954 * Main sha256 function, with its support functions
4955 */
4956function sha256_S (X, n) {return ( X >>> n ) | (X << (32 - n));}
4957function sha256_R (X, n) {return ( X >>> n );}
4958function sha256_Ch(x, y, z) {return ((x & y) ^ ((~x) & z));}
4959function sha256_Maj(x, y, z) {return ((x & y) ^ (x & z) ^ (y & z));}
4960function sha256_Sigma0256(x) {return (sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22));}
4961function sha256_Sigma1256(x) {return (sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25));}
4962function sha256_Gamma0256(x) {return (sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3));}
4963function sha256_Gamma1256(x) {return (sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10));}
4964function sha256_Sigma0512(x) {return (sha256_S(x, 28) ^ sha256_S(x, 34) ^ sha256_S(x, 39));}
4965function sha256_Sigma1512(x) {return (sha256_S(x, 14) ^ sha256_S(x, 18) ^ sha256_S(x, 41));}
4966function sha256_Gamma0512(x) {return (sha256_S(x, 1) ^ sha256_S(x, 8) ^ sha256_R(x, 7));}
4967function sha256_Gamma1512(x) {return (sha256_S(x, 19) ^ sha256_S(x, 61) ^ sha256_R(x, 6));}
4968
4969var sha256_K = new Array
4970(
4971 1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993,
4972 -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987,
4973 1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522,
4974 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986,
4975 -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585,
4976 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291,
4977 1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885,
4978 -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344,
4979 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218,
4980 1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872,
4981 -1866530822, -1538233109, -1090935817, -965641998
4982);
4983
4984function binb_sha256(m, l)
4985{
4986 var HASH = new Array(1779033703, -1150833019, 1013904242, -1521486534,
4987 1359893119, -1694144372, 528734635, 1541459225);
4988 var W = new Array(64);
Wentao Shang0e291c82012-12-02 23:36:29 -08004989
4990 /* append padding */
4991 m[l >> 5] |= 0x80 << (24 - l % 32);
4992 m[((l + 64 >> 9) << 4) + 15] = l;
Wentao Shangc0311e52012-12-03 10:38:23 -08004993
4994 for(var offset = 0; offset < m.length; offset += 16)
4995 processBlock_sha256(m, offset, HASH, W);
Wentao Shang0e291c82012-12-02 23:36:29 -08004996
Wentao Shangc0311e52012-12-03 10:38:23 -08004997 return HASH;
4998}
4999
5000/*
5001 * Process a block of 16 4-byte words in m starting at offset and update HASH.
5002 * offset must be a multiple of 16 and less than m.length. W is a scratchpad Array(64).
5003 */
5004function processBlock_sha256(m, offset, HASH, W) {
5005 var a, b, c, d, e, f, g, h;
5006 var j, T1, T2;
5007
Wentao Shang0e291c82012-12-02 23:36:29 -08005008 a = HASH[0];
5009 b = HASH[1];
5010 c = HASH[2];
5011 d = HASH[3];
5012 e = HASH[4];
5013 f = HASH[5];
5014 g = HASH[6];
5015 h = HASH[7];
5016
5017 for(j = 0; j < 64; j++)
5018 {
Wentao Shangc0311e52012-12-03 10:38:23 -08005019 if (j < 16) W[j] = m[j + offset];
Wentao Shang0e291c82012-12-02 23:36:29 -08005020 else W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]),
5021 sha256_Gamma0256(W[j - 15])), W[j - 16]);
5022
5023 T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)),
5024 sha256_K[j]), W[j]);
5025 T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
5026 h = g;
5027 g = f;
5028 f = e;
5029 e = safe_add(d, T1);
5030 d = c;
5031 c = b;
5032 b = a;
5033 a = safe_add(T1, T2);
5034 }
5035
5036 HASH[0] = safe_add(a, HASH[0]);
5037 HASH[1] = safe_add(b, HASH[1]);
5038 HASH[2] = safe_add(c, HASH[2]);
5039 HASH[3] = safe_add(d, HASH[3]);
5040 HASH[4] = safe_add(e, HASH[4]);
5041 HASH[5] = safe_add(f, HASH[5]);
5042 HASH[6] = safe_add(g, HASH[6]);
5043 HASH[7] = safe_add(h, HASH[7]);
Wentao Shang0e291c82012-12-02 23:36:29 -08005044}
5045
5046function safe_add (x, y)
5047{
5048 var lsw = (x & 0xFFFF) + (y & 0xFFFF);
5049 var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
5050 return (msw << 16) | (lsw & 0xFFFF);
5051}
Wentao Shangc0311e52012-12-03 10:38:23 -08005052
5053/*
5054 * Create a Sha256, call update(data) multiple times, then call finalize().
5055 */
5056var Sha256 = function Sha256() {
5057 this.W = new Array(64);
5058 this.hash = new Array(1779033703, -1150833019, 1013904242, -1521486534,
5059 1359893119, -1694144372, 528734635, 1541459225);
5060 this.nTotalBytes = 0;
5061 this.buffer = new Uint8Array(16 * 4);
5062 this.nBufferBytes = 0;
5063}
5064
5065/*
5066 * Update the hash with data, which is Uint8Array.
5067 */
5068Sha256.prototype.update = function(data) {
5069 this.nTotalBytes += data.length;
5070
5071 if (this.nBufferBytes > 0) {
5072 // Fill up the buffer and process it first.
5073 var bytesNeeded = this.buffer.length - this.nBufferBytes;
5074 if (data.length < bytesNeeded) {
5075 this.buffer.set(data, this.nBufferBytes);
5076 this.nBufferBytes += data.length;
5077 return;
5078 }
5079 else {
5080 this.buffer.set(data.subarray(0, bytesNeeded), this.nBufferBytes);
5081 processBlock_sha256(byteArray2binb(this.buffer), 0, this.hash, this.W);
5082 this.nBufferBytes = 0;
5083 // Consume the bytes from data.
5084 data = data.subarray(bytesNeeded, data.length);
5085 if (data.length == 0)
5086 return;
5087 }
5088 }
5089
5090 // 2^6 is 16 * 4.
5091 var nBlocks = data.length >> 6;
5092 if (nBlocks > 0) {
5093 var nBytes = nBlocks * 16 * 4;
5094 var m = byteArray2binb(data.subarray(0, nBytes));
5095 for(var offset = 0; offset < m.length; offset += 16)
5096 processBlock_sha256(m, offset, this.hash, this.W);
5097
5098 data = data.subarray(nBytes, data.length);
5099 }
5100
5101 if (data.length > 0) {
5102 // Save the remainder in the buffer.
5103 this.buffer.set(data);
5104 this.nBufferBytes = data.length;
5105 }
5106}
5107
5108/*
5109 * Finalize the hash and return the result as Uint8Array.
5110 * Only call this once. Return values on subsequent calls are undefined.
5111 */
5112Sha256.prototype.finalize = function() {
5113 var m = byteArray2binb(this.buffer.subarray(0, this.nBufferBytes));
5114 /* append padding */
5115 var l = this.nBufferBytes * 8;
5116 m[l >> 5] |= 0x80 << (24 - l % 32);
5117 m[((l + 64 >> 9) << 4) + 15] = this.nTotalBytes * 8;
5118
5119 for(var offset = 0; offset < m.length; offset += 16)
5120 processBlock_sha256(m, offset, this.hash, this.W);
5121
5122 return Sha256.binb2Uint8Array(this.hash);
5123}
5124
5125/*
5126 * Convert an array of big-endian words to Uint8Array.
5127 */
5128Sha256.binb2Uint8Array = function(input)
5129{
5130 var output = new Uint8Array(input.length * 4);
5131 var iOutput = 0;
5132 for (var i = 0; i < input.length * 32; i += 8)
5133 output[iOutput++] = (input[i>>5] >>> (24 - i % 32)) & 0xFF;
5134 return output;
5135}
Wentao Shang0e291c82012-12-02 23:36:29 -08005136var b64map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
5137var b64pad="=";
5138
5139function hex2b64(h) {
5140 var i;
5141 var c;
5142 var ret = "";
5143 for(i = 0; i+3 <= h.length; i+=3) {
5144 c = parseInt(h.substring(i,i+3),16);
5145 ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63);
5146 }
5147 if(i+1 == h.length) {
5148 c = parseInt(h.substring(i,i+1),16);
5149 ret += b64map.charAt(c << 2);
5150 }
5151 else if(i+2 == h.length) {
5152 c = parseInt(h.substring(i,i+2),16);
5153 ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4);
5154 }
5155 while((ret.length & 3) > 0) ret += b64pad;
5156 return ret;
5157}
5158
5159// convert a base64 string to hex
5160function b64tohex(s) {
5161 var ret = ""
5162 var i;
5163 var k = 0; // b64 state, 0-3
5164 var slop;
5165 for(i = 0; i < s.length; ++i) {
5166 if(s.charAt(i) == b64pad) break;
5167 v = b64map.indexOf(s.charAt(i));
5168 if(v < 0) continue;
5169 if(k == 0) {
5170 ret += int2char(v >> 2);
5171 slop = v & 3;
5172 k = 1;
5173 }
5174 else if(k == 1) {
5175 ret += int2char((slop << 2) | (v >> 4));
5176 slop = v & 0xf;
5177 k = 2;
5178 }
5179 else if(k == 2) {
5180 ret += int2char(slop);
5181 ret += int2char(v >> 2);
5182 slop = v & 3;
5183 k = 3;
5184 }
5185 else {
5186 ret += int2char((slop << 2) | (v >> 4));
5187 ret += int2char(v & 0xf);
5188 k = 0;
5189 }
5190 }
5191 if(k == 1)
5192 ret += int2char(slop << 2);
5193 return ret;
5194}
5195
5196// convert a base64 string to a byte/number array
5197function b64toBA(s) {
5198 //piggyback on b64tohex for now, optimize later
5199 var h = b64tohex(s);
5200 var i;
5201 var a = new Array();
5202 for(i = 0; 2*i < h.length; ++i) {
5203 a[i] = parseInt(h.substring(2*i,2*i+2),16);
5204 }
5205 return a;
5206}
5207// Depends on jsbn.js and rng.js
5208
5209// Version 1.1: support utf-8 encoding in pkcs1pad2
5210
5211// convert a (hex) string to a bignum object
5212function parseBigInt(str,r) {
5213 return new BigInteger(str,r);
5214}
5215
5216function linebrk(s,n) {
5217 var ret = "";
5218 var i = 0;
5219 while(i + n < s.length) {
5220 ret += s.substring(i,i+n) + "\n";
5221 i += n;
5222 }
5223 return ret + s.substring(i,s.length);
5224}
5225
5226function byte2Hex(b) {
5227 if(b < 0x10)
5228 return "0" + b.toString(16);
5229 else
5230 return b.toString(16);
5231}
5232
5233/**
5234 * PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint
5235 * @param s: the string to encode
5236 * @param n: the size in byte
5237 */
5238function pkcs1pad2(s,n) {
5239 if(n < s.length + 11) { // TODO: fix for utf-8
5240 alert("Message too long for RSA");
5241 return null;
5242 }
5243 var ba = new Array();
5244 var i = s.length - 1;
5245 while(i >= 0 && n > 0) {
5246 var c = s.charCodeAt(i--);
5247 if(c < 128) { // encode using utf-8
5248 ba[--n] = c;
5249 }
5250 else if((c > 127) && (c < 2048)) {
5251 ba[--n] = (c & 63) | 128;
5252 ba[--n] = (c >> 6) | 192;
5253 }
5254 else {
5255 ba[--n] = (c & 63) | 128;
5256 ba[--n] = ((c >> 6) & 63) | 128;
5257 ba[--n] = (c >> 12) | 224;
5258 }
5259 }
5260 ba[--n] = 0;
5261 var rng = new SecureRandom();
5262 var x = new Array();
5263 while(n > 2) { // random non-zero pad
5264 x[0] = 0;
5265 while(x[0] == 0) rng.nextBytes(x);
5266 ba[--n] = x[0];
5267 }
5268 ba[--n] = 2;
5269 ba[--n] = 0;
5270 return new BigInteger(ba);
5271}
5272
5273/**
5274 * "empty" RSA key constructor
5275 * @returns {RSAKey}
5276 */
5277function RSAKey() {
5278 this.n = null;
5279 this.e = 0;
5280 this.d = null;
5281 this.p = null;
5282 this.q = null;
5283 this.dmp1 = null;
5284 this.dmq1 = null;
5285 this.coeff = null;
5286}
5287
5288/**
5289 * Set the public key fields N and e from hex strings
5290 * @param N
5291 * @param E
5292 * @returns {RSASetPublic}
5293 */
5294function RSASetPublic(N,E) {
5295 if(N != null && E != null && N.length > 0 && E.length > 0) {
5296 this.n = parseBigInt(N,16);
5297 this.e = parseInt(E,16);
5298 }
5299 else
5300 alert("Invalid RSA public key");
5301}
5302
5303/**
5304 * Perform raw public operation on "x": return x^e (mod n)
5305 * @param x
5306 * @returns x^e (mod n)
5307 */
5308function RSADoPublic(x) {
5309 return x.modPowInt(this.e, this.n);
5310}
5311
5312/**
5313 * Return the PKCS#1 RSA encryption of "text" as an even-length hex string
5314 */
5315function RSAEncrypt(text) {
5316 var m = pkcs1pad2(text,(this.n.bitLength()+7)>>3);
5317 if(m == null) return null;
5318 var c = this.doPublic(m);
5319 if(c == null) return null;
5320 var h = c.toString(16);
5321 if((h.length & 1) == 0) return h; else return "0" + h;
5322}
5323
5324// Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string
5325//function RSAEncryptB64(text) {
5326// var h = this.encrypt(text);
5327// if(h) return hex2b64(h); else return null;
5328//}
5329
5330// protected
5331RSAKey.prototype.doPublic = RSADoPublic;
5332
5333// public
5334RSAKey.prototype.setPublic = RSASetPublic;
5335RSAKey.prototype.encrypt = RSAEncrypt;
5336//RSAKey.prototype.encrypt_b64 = RSAEncryptB64;
5337// Depends on rsa.js and jsbn2.js
5338
5339// Version 1.1: support utf-8 decoding in pkcs1unpad2
5340
5341// Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext
5342function pkcs1unpad2(d,n) {
5343 var b = d.toByteArray();
5344 var i = 0;
5345 while(i < b.length && b[i] == 0) ++i;
5346 if(b.length-i != n-1 || b[i] != 2)
5347 return null;
5348 ++i;
5349 while(b[i] != 0)
5350 if(++i >= b.length) return null;
5351 var ret = "";
5352 while(++i < b.length) {
5353 var c = b[i] & 255;
5354 if(c < 128) { // utf-8 decode
5355 ret += String.fromCharCode(c);
5356 }
5357 else if((c > 191) && (c < 224)) {
5358 ret += String.fromCharCode(((c & 31) << 6) | (b[i+1] & 63));
5359 ++i;
5360 }
5361 else {
5362 ret += String.fromCharCode(((c & 15) << 12) | ((b[i+1] & 63) << 6) | (b[i+2] & 63));
5363 i += 2;
5364 }
5365 }
5366 return ret;
5367}
5368
5369// Set the private key fields N, e, and d from hex strings
5370function RSASetPrivate(N,E,D) {
5371 if(N != null && E != null && N.length > 0 && E.length > 0) {
5372 this.n = parseBigInt(N,16);
5373 this.e = parseInt(E,16);
5374 this.d = parseBigInt(D,16);
5375 }
5376 else
5377 alert("Invalid RSA private key");
5378}
5379
5380// Set the private key fields N, e, d and CRT params from hex strings
5381function RSASetPrivateEx(N,E,D,P,Q,DP,DQ,C) {
5382 if(N != null && E != null && N.length > 0 && E.length > 0) {
5383 this.n = parseBigInt(N,16);
5384 this.e = parseInt(E,16);
5385 this.d = parseBigInt(D,16);
5386 this.p = parseBigInt(P,16);
5387 this.q = parseBigInt(Q,16);
5388 this.dmp1 = parseBigInt(DP,16);
5389 this.dmq1 = parseBigInt(DQ,16);
5390 this.coeff = parseBigInt(C,16);
5391 }
5392 else
5393 alert("Invalid RSA private key");
5394}
5395
5396/**
5397 * Generate a new random private key B bits long, using public expt E
5398 */
5399function RSAGenerate(B,E) {
5400 var rng = new SecureRandom();
5401 var qs = B>>1;
5402 this.e = parseInt(E,16);
5403 var ee = new BigInteger(E,16);
5404 for(;;) {
5405 for(;;) {
5406 this.p = new BigInteger(B-qs,1,rng);
5407 if(this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.p.isProbablePrime(10)) break;
5408 }
5409 for(;;) {
5410 this.q = new BigInteger(qs,1,rng);
5411 if(this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.q.isProbablePrime(10)) break;
5412 }
5413 if(this.p.compareTo(this.q) <= 0) {
5414 var t = this.p;
5415 this.p = this.q;
5416 this.q = t;
5417 }
5418 var p1 = this.p.subtract(BigInteger.ONE); // p1 = p - 1
5419 var q1 = this.q.subtract(BigInteger.ONE); // q1 = q - 1
5420 var phi = p1.multiply(q1);
5421 if(phi.gcd(ee).compareTo(BigInteger.ONE) == 0) {
5422 this.n = this.p.multiply(this.q); // this.n = p * q
5423 this.d = ee.modInverse(phi); // this.d =
5424 this.dmp1 = this.d.mod(p1); // this.dmp1 = d mod (p - 1)
5425 this.dmq1 = this.d.mod(q1); // this.dmq1 = d mod (q - 1)
5426 this.coeff = this.q.modInverse(this.p); // this.coeff = (q ^ -1) mod p
5427 break;
5428 }
5429 }
5430}
5431
5432/**
5433 * Perform raw private operation on "x": return x^d (mod n)
5434 * @return x^d (mod n)
5435 */
5436function RSADoPrivate(x) {
5437 if(this.p == null || this.q == null)
5438 return x.modPow(this.d, this.n);
5439
5440 // TODO: re-calculate any missing CRT params
5441 var xp = x.mod(this.p).modPow(this.dmp1, this.p); // xp=cp?
5442 var xq = x.mod(this.q).modPow(this.dmq1, this.q); // xq=cq?
5443
5444 while(xp.compareTo(xq) < 0)
5445 xp = xp.add(this.p);
5446 // NOTE:
5447 // xp.subtract(xq) => cp -cq
5448 // xp.subtract(xq).multiply(this.coeff).mod(this.p) => (cp - cq) * u mod p = h
5449 // xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq) => cq + (h * q) = M
5450 return xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq);
5451}
5452
5453// Return the PKCS#1 RSA decryption of "ctext".
5454// "ctext" is an even-length hex string and the output is a plain string.
5455function RSADecrypt(ctext) {
5456 var c = parseBigInt(ctext, 16);
5457 var m = this.doPrivate(c);
5458 if(m == null) return null;
5459 return pkcs1unpad2(m, (this.n.bitLength()+7)>>3);
5460}
5461
5462// Return the PKCS#1 RSA decryption of "ctext".
5463// "ctext" is a Base64-encoded string and the output is a plain string.
5464//function RSAB64Decrypt(ctext) {
5465// var h = b64tohex(ctext);
5466// if(h) return this.decrypt(h); else return null;
5467//}
5468
5469// protected
5470RSAKey.prototype.doPrivate = RSADoPrivate;
5471
5472// public
5473RSAKey.prototype.setPrivate = RSASetPrivate;
5474RSAKey.prototype.setPrivateEx = RSASetPrivateEx;
5475RSAKey.prototype.generate = RSAGenerate;
5476RSAKey.prototype.decrypt = RSADecrypt;
5477//RSAKey.prototype.b64_decrypt = RSAB64Decrypt;
5478/*! rsapem-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
5479 */
5480//
5481// rsa-pem.js - adding function for reading/writing PKCS#1 PEM private key
5482// to RSAKey class.
5483//
5484// version: 1.1 (2012-May-10)
5485//
5486// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
5487//
5488// This software is licensed under the terms of the MIT License.
5489// http://kjur.github.com/jsrsasign/license/
5490//
5491// The above copyright and license notice shall be
5492// included in all copies or substantial portions of the Software.
5493//
5494//
5495// Depends on:
5496//
5497//
5498//
5499// _RSApem_pemToBase64(sPEM)
5500//
5501// removing PEM header, PEM footer and space characters including
5502// new lines from PEM formatted RSA private key string.
5503//
5504
5505function _rsapem_pemToBase64(sPEMPrivateKey) {
5506 var s = sPEMPrivateKey;
5507 s = s.replace("-----BEGIN RSA PRIVATE KEY-----", "");
5508 s = s.replace("-----END RSA PRIVATE KEY-----", "");
5509 s = s.replace(/[ \n]+/g, "");
5510 return s;
5511}
5512
5513function _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey) {
5514 var a = new Array();
5515 var v1 = ASN1HEX.getStartPosOfV_AtObj(hPrivateKey, 0);
5516 var n1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, v1);
5517 var e1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, n1);
5518 var d1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, e1);
5519 var p1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, d1);
5520 var q1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, p1);
5521 var dp1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, q1);
5522 var dq1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dp1);
5523 var co1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dq1);
5524 a.push(v1, n1, e1, d1, p1, q1, dp1, dq1, co1);
5525 return a;
5526}
5527
5528function _rsapem_getHexValueArrayOfChildrenFromHex(hPrivateKey) {
5529 var posArray = _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey);
5530 var v = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[0]);
5531 var n = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[1]);
5532 var e = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[2]);
5533 var d = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[3]);
5534 var p = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[4]);
5535 var q = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[5]);
5536 var dp = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[6]);
5537 var dq = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[7]);
5538 var co = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[8]);
5539 var a = new Array();
5540 a.push(v, n, e, d, p, q, dp, dq, co);
5541 return a;
5542}
5543
5544/**
5545 * read PKCS#1 private key from a string
5546 * @name readPrivateKeyFromPEMString
5547 * @memberOf RSAKey#
5548 * @function
5549 * @param {String} keyPEM string of PKCS#1 private key.
5550 */
5551function _rsapem_readPrivateKeyFromPEMString(keyPEM) {
5552 var keyB64 = _rsapem_pemToBase64(keyPEM);
5553 var keyHex = b64tohex(keyB64) // depends base64.js
5554 var a = _rsapem_getHexValueArrayOfChildrenFromHex(keyHex);
5555 this.setPrivateEx(a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]);
5556}
5557
5558RSAKey.prototype.readPrivateKeyFromPEMString = _rsapem_readPrivateKeyFromPEMString;
5559/*! rsasign-1.2.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
5560 */
5561//
5562// rsa-sign.js - adding signing functions to RSAKey class.
5563//
5564//
5565// version: 1.2.1 (08 May 2012)
5566//
5567// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
5568//
5569// This software is licensed under the terms of the MIT License.
5570// http://kjur.github.com/jsrsasign/license/
5571//
5572// The above copyright and license notice shall be
5573// included in all copies or substantial portions of the Software.
5574
5575//
5576// Depends on:
5577// function sha1.hex(s) of sha1.js
5578// jsbn.js
5579// jsbn2.js
5580// rsa.js
5581// rsa2.js
5582//
5583
5584// keysize / pmstrlen
5585// 512 / 128
5586// 1024 / 256
5587// 2048 / 512
5588// 4096 / 1024
5589
5590/**
5591 * @property {Dictionary} _RSASIGN_DIHEAD
5592 * @description Array of head part of hexadecimal DigestInfo value for hash algorithms.
5593 * You can add any DigestInfo hash algorith for signing.
5594 * See PKCS#1 v2.1 spec (p38).
5595 */
5596var _RSASIGN_DIHEAD = [];
5597_RSASIGN_DIHEAD['sha1'] = "3021300906052b0e03021a05000414";
5598_RSASIGN_DIHEAD['sha256'] = "3031300d060960864801650304020105000420";
5599_RSASIGN_DIHEAD['sha384'] = "3041300d060960864801650304020205000430";
5600_RSASIGN_DIHEAD['sha512'] = "3051300d060960864801650304020305000440";
5601_RSASIGN_DIHEAD['md2'] = "3020300c06082a864886f70d020205000410";
5602_RSASIGN_DIHEAD['md5'] = "3020300c06082a864886f70d020505000410";
5603_RSASIGN_DIHEAD['ripemd160'] = "3021300906052b2403020105000414";
5604
5605/**
5606 * @property {Dictionary} _RSASIGN_HASHHEXFUNC
5607 * @description Array of functions which calculate hash and returns it as hexadecimal.
5608 * You can add any hash algorithm implementations.
5609 */
5610var _RSASIGN_HASHHEXFUNC = [];
5611_RSASIGN_HASHHEXFUNC['sha1'] = function(s){return hex_sha1(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
5612_RSASIGN_HASHHEXFUNC['sha256'] = function(s){return hex_sha256(s);} // http://pajhome.org.uk/crypt/md5/md5.html
5613_RSASIGN_HASHHEXFUNC['sha512'] = function(s){return hex_sha512(s);} // http://pajhome.org.uk/crypt/md5/md5.html
5614_RSASIGN_HASHHEXFUNC['md5'] = function(s){return hex_md5(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
5615_RSASIGN_HASHHEXFUNC['ripemd160'] = function(s){return hex_rmd160(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
5616
5617//@author axelcdv
5618var _RSASIGN_HASHBYTEFUNC = [];
5619_RSASIGN_HASHBYTEFUNC['sha256'] = function(byteArray){return hex_sha256_from_bytes(byteArray);};
5620
5621//_RSASIGN_HASHHEXFUNC['sha1'] = function(s){return sha1.hex(s);} // http://user1.matsumoto.ne.jp/~goma/js/hash.html
5622//_RSASIGN_HASHHEXFUNC['sha256'] = function(s){return sha256.hex;} // http://user1.matsumoto.ne.jp/~goma/js/hash.html
5623
5624var _RE_HEXDECONLY = new RegExp("");
5625_RE_HEXDECONLY.compile("[^0-9a-f]", "gi");
5626
5627// ========================================================================
5628// Signature Generation
5629// ========================================================================
5630
5631function _rsasign_getHexPaddedDigestInfoForString(s, keySize, hashAlg) {
5632 var pmStrLen = keySize / 4;
5633 var hashFunc = _RSASIGN_HASHHEXFUNC[hashAlg];
5634 var sHashHex = hashFunc(s);
5635
5636 var sHead = "0001";
5637 var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex;
5638 var sMid = "";
5639 var fLen = pmStrLen - sHead.length - sTail.length;
5640 for (var i = 0; i < fLen; i += 2) {
5641 sMid += "ff";
5642 }
5643 sPaddedMessageHex = sHead + sMid + sTail;
5644 return sPaddedMessageHex;
5645}
5646
5647
5648//@author: Meki Cheraoui
5649function _rsasign_getHexPaddedDigestInfoForStringHEX(s, keySize, hashAlg) {
5650 var pmStrLen = keySize / 4;
5651 var hashFunc = _RSASIGN_HASHHEXFUNC[hashAlg];
5652 var sHashHex = hashFunc(s);
5653
5654 var sHead = "0001";
5655 var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex;
5656 var sMid = "";
5657 var fLen = pmStrLen - sHead.length - sTail.length;
5658 for (var i = 0; i < fLen; i += 2) {
5659 sMid += "ff";
5660 }
5661 sPaddedMessageHex = sHead + sMid + sTail;
5662 return sPaddedMessageHex;
5663}
5664
5665/**
5666 * Apply padding, then computes the hash of the given byte array, according to the key size and with the hash algorithm
5667 * @param byteArray (byte[])
5668 * @param keySize (int)
5669 * @param hashAlg the hash algorithm to apply (string)
5670 * @return the hash of byteArray
5671 */
5672function _rsasign_getHexPaddedDigestInfoForByteArray(byteArray, keySize, hashAlg){
5673 var pmStrLen = keySize / 4;
5674 var hashFunc = _RSASIGN_HASHBYTEFUNC[hashAlg];
5675 var sHashHex = hashFunc(byteArray); //returns hex hash
5676
5677 var sHead = "0001";
5678 var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex;
5679 var sMid = "";
5680 var fLen = pmStrLen - sHead.length - sTail.length;
5681 for (var i = 0; i < fLen; i += 2) {
5682 sMid += "ff";
5683 }
5684 sPaddedMessageHex = sHead + sMid + sTail;
5685 return sPaddedMessageHex;
5686}
5687
5688function _zeroPaddingOfSignature(hex, bitLength) {
5689 var s = "";
5690 var nZero = bitLength / 4 - hex.length;
5691 for (var i = 0; i < nZero; i++) {
5692 s = s + "0";
5693 }
5694 return s + hex;
5695}
5696
5697/**
5698 * sign for a message string with RSA private key.<br/>
5699 * @name signString
5700 * @memberOf RSAKey#
5701 * @function
5702 * @param {String} s message string to be signed.
5703 * @param {String} hashAlg hash algorithm name for signing.<br/>
5704 * @return returns hexadecimal string of signature value.
5705 */
5706function _rsasign_signString(s, hashAlg) {
5707 //alert("this.n.bitLength() = " + this.n.bitLength());
5708 var hPM = _rsasign_getHexPaddedDigestInfoForString(s, this.n.bitLength(), hashAlg);
5709 var biPaddedMessage = parseBigInt(hPM, 16);
5710 var biSign = this.doPrivate(biPaddedMessage);
5711 var hexSign = biSign.toString(16);
5712 return _zeroPaddingOfSignature(hexSign, this.n.bitLength());
5713}
5714
5715//@author: ucla-cs
5716function _rsasign_signStringHEX(s, hashAlg) {
5717 //alert("this.n.bitLength() = " + this.n.bitLength());
5718 var hPM = _rsasign_getHexPaddedDigestInfoForString(s, this.n.bitLength(), hashAlg);
5719 var biPaddedMessage = parseBigInt(hPM, 16);
5720 var biSign = this.doPrivate(biPaddedMessage);
5721 var hexSign = biSign.toString(16);
5722 return _zeroPaddingOfSignature(hexSign, this.n.bitLength());
5723}
5724
5725
5726/**
5727 * Sign a message byteArray with an RSA private key
5728 * @name signByteArray
5729 * @memberOf RSAKey#
5730 * @function
5731 * @param {byte[]} byteArray
5732 * @param {Sring} hashAlg the hash algorithm to apply
5733 * @param {RSAKey} rsa key to sign with: hack because the context is lost here
5734 * @return hexadecimal string of signature value
5735 */
5736function _rsasign_signByteArray(byteArray, hashAlg, rsaKey) {
5737 var hPM = _rsasign_getHexPaddedDigestInfoForByteArray(byteArray, rsaKey.n.bitLength(), hashAlg); ///hack because the context is lost here
5738 var biPaddedMessage = parseBigInt(hPM, 16);
5739 var biSign = rsaKey.doPrivate(biPaddedMessage); //hack because the context is lost here
5740 var hexSign = biSign.toString(16);
5741 return _zeroPaddingOfSignature(hexSign, rsaKey.n.bitLength()); //hack because the context is lost here
5742}
5743
5744/**
5745 * Sign a byte array with the Sha-256 algorithm
5746 * @param {byte[]} byteArray
5747 * @return hexadecimal string of signature value
5748 */
5749function _rsasign_signByteArrayWithSHA256(byteArray){
5750 return _rsasign_signByteArray(byteArray, 'sha256', this); //Hack because the context is lost in the next function
5751}
5752
5753
5754function _rsasign_signStringWithSHA1(s) {
5755 return _rsasign_signString(s, 'sha1');
5756}
5757
5758function _rsasign_signStringWithSHA256(s) {
5759 return _rsasign_signString(s, 'sha256');
5760}
5761
5762// ========================================================================
5763// Signature Verification
5764// ========================================================================
5765
5766function _rsasign_getDecryptSignatureBI(biSig, hN, hE) {
5767 var rsa = new RSAKey();
5768 rsa.setPublic(hN, hE);
5769 var biDecryptedSig = rsa.doPublic(biSig);
5770 return biDecryptedSig;
5771}
5772
5773function _rsasign_getHexDigestInfoFromSig(biSig, hN, hE) {
5774 var biDecryptedSig = _rsasign_getDecryptSignatureBI(biSig, hN, hE);
5775 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
5776 return hDigestInfo;
5777}
5778
5779function _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo) {
5780 for (var algName in _RSASIGN_DIHEAD) {
5781 var head = _RSASIGN_DIHEAD[algName];
5782 var len = head.length;
5783 if (hDigestInfo.substring(0, len) == head) {
5784 var a = [algName, hDigestInfo.substring(len)];
5785 return a;
5786 }
5787 }
5788 return [];
5789}
5790
5791function _rsasign_verifySignatureWithArgs(sMsg, biSig, hN, hE) {
5792 var hDigestInfo = _rsasign_getHexDigestInfoFromSig(biSig, hN, hE);
5793 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
5794 if (digestInfoAry.length == 0) return false;
5795 var algName = digestInfoAry[0];
5796 var diHashValue = digestInfoAry[1];
5797 var ff = _RSASIGN_HASHHEXFUNC[algName];
5798 var msgHashValue = ff(sMsg);
5799 return (diHashValue == msgHashValue);
5800}
5801
5802function _rsasign_verifyHexSignatureForMessage(hSig, sMsg) {
5803 var biSig = parseBigInt(hSig, 16);
5804 var result = _rsasign_verifySignatureWithArgs(sMsg, biSig,
5805 this.n.toString(16),
5806 this.e.toString(16));
5807 return result;
5808}
5809
5810/**
5811 * verifies a sigature for a message string with RSA public key.<br/>
5812 * @name verifyString
5813 * @memberOf RSAKey#
5814 * @function
5815 * @param {String} sMsg message string to be verified.
5816 * @param {String} hSig hexadecimal string of siganture.<br/>
5817 * non-hexadecimal charactors including new lines will be ignored.
5818 * @return returns 1 if valid, otherwise 0
5819 */
5820function _rsasign_verifyString(sMsg, hSig) {
5821 hSig = hSig.replace(_RE_HEXDECONLY, '');
5822
5823 if(LOG>3)console.log('n is '+this.n);
5824 if(LOG>3)console.log('e is '+this.e);
5825
5826 if (hSig.length != this.n.bitLength() / 4) return 0;
5827 hSig = hSig.replace(/[ \n]+/g, "");
5828 var biSig = parseBigInt(hSig, 16);
5829 var biDecryptedSig = this.doPublic(biSig);
5830 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
5831 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
5832
5833 if (digestInfoAry.length == 0) return false;
5834 var algName = digestInfoAry[0];
5835 var diHashValue = digestInfoAry[1];
5836 var ff = _RSASIGN_HASHHEXFUNC[algName];
5837 var msgHashValue = ff(sMsg);
5838 return (diHashValue == msgHashValue);
5839}
5840
5841/**
5842 * verifies a sigature for a message byte array with RSA public key.<br/>
5843 * @name verifyByteArray
5844 * @memberOf RSAKey#
5845 * @function
5846 * @param {byte[]} byteArray message byte array to be verified.
5847 * @param {String} hSig hexadecimal string of signature.<br/>
5848 * non-hexadecimal charactors including new lines will be ignored.
5849 * @return returns 1 if valid, otherwise 0
5850 */
5851function _rsasign_verifyByteArray(byteArray, hSig) {
5852 hSig = hSig.replace(_RE_HEXDECONLY, '');
5853
5854 if(LOG>3)console.log('n is '+this.n);
5855 if(LOG>3)console.log('e is '+this.e);
5856
5857 if (hSig.length != this.n.bitLength() / 4) return 0;
5858 hSig = hSig.replace(/[ \n]+/g, "");
5859 var biSig = parseBigInt(hSig, 16);
5860 var biDecryptedSig = this.doPublic(biSig);
5861 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
5862 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
5863
5864 if (digestInfoAry.length == 0) return false;
5865 var algName = digestInfoAry[0];
5866 var diHashValue = digestInfoAry[1];
5867 var ff = _RSASIGN_HASHBYTEFUNC[algName];
5868 var msgHashValue = ff(byteArray);
5869 return (diHashValue == msgHashValue);
5870}
5871
5872RSAKey.prototype.signString = _rsasign_signString;
5873
5874RSAKey.prototype.signByteArray = _rsasign_signByteArray; //@author axelcdv
5875RSAKey.prototype.signByteArrayWithSHA256 = _rsasign_signByteArrayWithSHA256; //@author axelcdv
5876
5877RSAKey.prototype.signStringWithSHA1 = _rsasign_signStringWithSHA1;
5878RSAKey.prototype.signStringWithSHA256 = _rsasign_signStringWithSHA256;
5879RSAKey.prototype.sign = _rsasign_signString;
5880RSAKey.prototype.signWithSHA1 = _rsasign_signStringWithSHA1;
5881RSAKey.prototype.signWithSHA256 = _rsasign_signStringWithSHA256;
5882
5883
5884/*RSAKey.prototype.signStringHEX = _rsasign_signStringHEX;
5885RSAKey.prototype.signStringWithSHA1HEX = _rsasign_signStringWithSHA1HEX;
5886RSAKey.prototype.signStringWithSHA256HEX = _rsasign_signStringWithSHA256HEX;
5887RSAKey.prototype.signHEX = _rsasign_signStringHEX;
5888RSAKey.prototype.signWithSHA1HEX = _rsasign_signStringWithSHA1HEX;
5889RSAKey.prototype.signWithSHA256HEX = _rsasign_signStringWithSHA256HEX;
5890*/
5891
5892RSAKey.prototype.verifyByteArray = _rsasign_verifyByteArray;
5893RSAKey.prototype.verifyString = _rsasign_verifyString;
5894RSAKey.prototype.verifyHexSignatureForMessage = _rsasign_verifyHexSignatureForMessage;
5895RSAKey.prototype.verify = _rsasign_verifyString;
5896RSAKey.prototype.verifyHexSignatureForByteArrayMessage = _rsasign_verifyHexSignatureForMessage;
5897
5898/*
5899RSAKey.prototype.verifyStringHEX = _rsasign_verifyStringHEX;
5900RSAKey.prototype.verifyHexSignatureForMessageHEX = _rsasign_verifyHexSignatureForMessageHEX;
5901RSAKey.prototype.verifyHEX = _rsasign_verifyStringHEX;
5902RSAKey.prototype.verifyHexSignatureForByteArrayMessageHEX = _rsasign_verifyHexSignatureForMessageHEX;
5903*/
5904
5905
5906/**
5907 * @name RSAKey
5908 * @class
5909 * @description Tom Wu's RSA Key class and extension
5910 */
5911/*! asn1hex-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
5912 */
5913//
5914// asn1hex.js - Hexadecimal represented ASN.1 string library
5915//
5916// version: 1.1 (09-May-2012)
5917//
5918// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
5919//
5920// This software is licensed under the terms of the MIT License.
5921// http://kjur.github.com/jsrsasign/license/
5922//
5923// The above copyright and license notice shall be
5924// included in all copies or substantial portions of the Software.
5925//
5926// Depends on:
5927//
5928
5929// MEMO:
5930// f('3082025b02...', 2) ... 82025b ... 3bytes
5931// f('020100', 2) ... 01 ... 1byte
5932// f('0203001...', 2) ... 03 ... 1byte
5933// f('02818003...', 2) ... 8180 ... 2bytes
5934// f('3080....0000', 2) ... 80 ... -1
5935//
5936// Requirements:
5937// - ASN.1 type octet length MUST be 1.
5938// (i.e. ASN.1 primitives like SET, SEQUENCE, INTEGER, OCTETSTRING ...)
5939// -
5940/**
5941 * get byte length for ASN.1 L(length) bytes
5942 * @name getByteLengthOfL_AtObj
5943 * @memberOf ASN1HEX
5944 * @function
5945 * @param {String} s hexadecimal string of ASN.1 DER encoded data
5946 * @param {Number} pos string index
5947 * @return byte length for ASN.1 L(length) bytes
5948 */
5949function _asnhex_getByteLengthOfL_AtObj(s, pos) {
5950 if (s.substring(pos + 2, pos + 3) != '8') return 1;
5951 var i = parseInt(s.substring(pos + 3, pos + 4));
5952 if (i == 0) return -1; // length octet '80' indefinite length
5953 if (0 < i && i < 10) return i + 1; // including '8?' octet;
5954 return -2; // malformed format
5955}
5956
5957
5958/**
5959 * get hexadecimal string for ASN.1 L(length) bytes
5960 * @name getHexOfL_AtObj
5961 * @memberOf ASN1HEX
5962 * @function
5963 * @param {String} s hexadecimal string of ASN.1 DER encoded data
5964 * @param {Number} pos string index
5965 * @return {String} hexadecimal string for ASN.1 L(length) bytes
5966 */
5967function _asnhex_getHexOfL_AtObj(s, pos) {
5968 var len = _asnhex_getByteLengthOfL_AtObj(s, pos);
5969 if (len < 1) return '';
5970 return s.substring(pos + 2, pos + 2 + len * 2);
5971}
5972
5973//
5974// getting ASN.1 length value at the position 'idx' of
5975// hexa decimal string 's'.
5976//
5977// f('3082025b02...', 0) ... 82025b ... ???
5978// f('020100', 0) ... 01 ... 1
5979// f('0203001...', 0) ... 03 ... 3
5980// f('02818003...', 0) ... 8180 ... 128
5981/**
5982 * get integer value of ASN.1 length for ASN.1 data
5983 * @name getIntOfL_AtObj
5984 * @memberOf ASN1HEX
5985 * @function
5986 * @param {String} s hexadecimal string of ASN.1 DER encoded data
5987 * @param {Number} pos string index
5988 * @return ASN.1 L(length) integer value
5989 */
5990function _asnhex_getIntOfL_AtObj(s, pos) {
5991 var hLength = _asnhex_getHexOfL_AtObj(s, pos);
5992 if (hLength == '') return -1;
5993 var bi;
5994 if (parseInt(hLength.substring(0, 1)) < 8) {
5995 bi = parseBigInt(hLength, 16);
5996 } else {
5997 bi = parseBigInt(hLength.substring(2), 16);
5998 }
5999 return bi.intValue();
6000}
6001
6002/**
6003 * get ASN.1 value starting string position for ASN.1 object refered by index 'idx'.
6004 * @name getStartPosOfV_AtObj
6005 * @memberOf ASN1HEX
6006 * @function
6007 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6008 * @param {Number} pos string index
6009 */
6010function _asnhex_getStartPosOfV_AtObj(s, pos) {
6011 var l_len = _asnhex_getByteLengthOfL_AtObj(s, pos);
6012 if (l_len < 0) return l_len;
6013 return pos + (l_len + 1) * 2;
6014}
6015
6016/**
6017 * get hexadecimal string of ASN.1 V(value)
6018 * @name getHexOfV_AtObj
6019 * @memberOf ASN1HEX
6020 * @function
6021 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6022 * @param {Number} pos string index
6023 * @return {String} hexadecimal string of ASN.1 value.
6024 */
6025function _asnhex_getHexOfV_AtObj(s, pos) {
6026 var pos1 = _asnhex_getStartPosOfV_AtObj(s, pos);
6027 var len = _asnhex_getIntOfL_AtObj(s, pos);
6028 return s.substring(pos1, pos1 + len * 2);
6029}
6030
6031/**
6032 * get hexadecimal string of ASN.1 TLV at
6033 * @name getHexOfTLV_AtObj
6034 * @memberOf ASN1HEX
6035 * @function
6036 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6037 * @param {Number} pos string index
6038 * @return {String} hexadecimal string of ASN.1 TLV.
6039 * @since 1.1
6040 */
6041function _asnhex_getHexOfTLV_AtObj(s, pos) {
6042 var hT = s.substr(pos, 2);
6043 var hL = _asnhex_getHexOfL_AtObj(s, pos);
6044 var hV = _asnhex_getHexOfV_AtObj(s, pos);
6045 return hT + hL + hV;
6046}
6047
6048/**
6049 * get next sibling starting index for ASN.1 object string
6050 * @name getPosOfNextSibling_AtObj
6051 * @memberOf ASN1HEX
6052 * @function
6053 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6054 * @param {Number} pos string index
6055 * @return next sibling starting index for ASN.1 object string
6056 */
6057function _asnhex_getPosOfNextSibling_AtObj(s, pos) {
6058 var pos1 = _asnhex_getStartPosOfV_AtObj(s, pos);
6059 var len = _asnhex_getIntOfL_AtObj(s, pos);
6060 return pos1 + len * 2;
6061}
6062
6063/**
6064 * get array of indexes of child ASN.1 objects
6065 * @name getPosArrayOfChildren_AtObj
6066 * @memberOf ASN1HEX
6067 * @function
6068 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6069 * @param {Number} start string index of ASN.1 object
6070 * @return {Array of Number} array of indexes for childen of ASN.1 objects
6071 */
6072function _asnhex_getPosArrayOfChildren_AtObj(h, pos) {
6073 var a = new Array();
6074 var p0 = _asnhex_getStartPosOfV_AtObj(h, pos);
6075 a.push(p0);
6076
6077 var len = _asnhex_getIntOfL_AtObj(h, pos);
6078 var p = p0;
6079 var k = 0;
6080 while (1) {
6081 var pNext = _asnhex_getPosOfNextSibling_AtObj(h, p);
6082 if (pNext == null || (pNext - p0 >= (len * 2))) break;
6083 if (k >= 200) break;
6084
6085 a.push(pNext);
6086 p = pNext;
6087
6088 k++;
6089 }
6090
6091 return a;
6092}
6093
6094/**
6095 * get string index of nth child object of ASN.1 object refered by h, idx
6096 * @name getNthChildIndex_AtObj
6097 * @memberOf ASN1HEX
6098 * @function
6099 * @param {String} h hexadecimal string of ASN.1 DER encoded data
6100 * @param {Number} idx start string index of ASN.1 object
6101 * @param {Number} nth for child
6102 * @return {Number} string index of nth child.
6103 * @since 1.1
6104 */
6105function _asnhex_getNthChildIndex_AtObj(h, idx, nth) {
6106 var a = _asnhex_getPosArrayOfChildren_AtObj(h, idx);
6107 return a[nth];
6108}
6109
6110// ========== decendant methods ==============================
6111
6112/**
6113 * get string index of nth child object of ASN.1 object refered by h, idx
6114 * @name getDecendantIndexByNthList
6115 * @memberOf ASN1HEX
6116 * @function
6117 * @param {String} h hexadecimal string of ASN.1 DER encoded data
6118 * @param {Number} currentIndex start string index of ASN.1 object
6119 * @param {Array of Number} nthList array list of nth
6120 * @return {Number} string index refered by nthList
6121 * @since 1.1
6122 */
6123function _asnhex_getDecendantIndexByNthList(h, currentIndex, nthList) {
6124 if (nthList.length == 0) {
6125 return currentIndex;
6126 }
6127 var firstNth = nthList.shift();
6128 var a = _asnhex_getPosArrayOfChildren_AtObj(h, currentIndex);
6129 return _asnhex_getDecendantIndexByNthList(h, a[firstNth], nthList);
6130}
6131
6132/**
6133 * get hexadecimal string of ASN.1 TLV refered by current index and nth index list.
6134 * @name getDecendantHexTLVByNthList
6135 * @memberOf ASN1HEX
6136 * @function
6137 * @param {String} h hexadecimal string of ASN.1 DER encoded data
6138 * @param {Number} currentIndex start string index of ASN.1 object
6139 * @param {Array of Number} nthList array list of nth
6140 * @return {Number} hexadecimal string of ASN.1 TLV refered by nthList
6141 * @since 1.1
6142 */
6143function _asnhex_getDecendantHexTLVByNthList(h, currentIndex, nthList) {
6144 var idx = _asnhex_getDecendantIndexByNthList(h, currentIndex, nthList);
6145 return _asnhex_getHexOfTLV_AtObj(h, idx);
6146}
6147
6148/**
6149 * get hexadecimal string of ASN.1 V refered by current index and nth index list.
6150 * @name getDecendantHexVByNthList
6151 * @memberOf ASN1HEX
6152 * @function
6153 * @param {String} h hexadecimal string of ASN.1 DER encoded data
6154 * @param {Number} currentIndex start string index of ASN.1 object
6155 * @param {Array of Number} nthList array list of nth
6156 * @return {Number} hexadecimal string of ASN.1 V refered by nthList
6157 * @since 1.1
6158 */
6159function _asnhex_getDecendantHexVByNthList(h, currentIndex, nthList) {
6160 var idx = _asnhex_getDecendantIndexByNthList(h, currentIndex, nthList);
6161 return _asnhex_getHexOfV_AtObj(h, idx);
6162}
6163
6164// ========== class definition ==============================
6165
6166/**
6167 * ASN.1 DER encoded hexadecimal string utility class
6168 * @class ASN.1 DER encoded hexadecimal string utility class
6169 * @author Kenji Urushima
6170 * @version 1.1 (09 May 2012)
6171 * @see <a href="http://kjur.github.com/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a>
6172 * @since 1.1
6173 */
6174function ASN1HEX() {
6175 return ASN1HEX;
6176}
6177
6178ASN1HEX.getByteLengthOfL_AtObj = _asnhex_getByteLengthOfL_AtObj;
6179ASN1HEX.getHexOfL_AtObj = _asnhex_getHexOfL_AtObj;
6180ASN1HEX.getIntOfL_AtObj = _asnhex_getIntOfL_AtObj;
6181ASN1HEX.getStartPosOfV_AtObj = _asnhex_getStartPosOfV_AtObj;
6182ASN1HEX.getHexOfV_AtObj = _asnhex_getHexOfV_AtObj;
6183ASN1HEX.getHexOfTLV_AtObj = _asnhex_getHexOfTLV_AtObj;
6184ASN1HEX.getPosOfNextSibling_AtObj = _asnhex_getPosOfNextSibling_AtObj;
6185ASN1HEX.getPosArrayOfChildren_AtObj = _asnhex_getPosArrayOfChildren_AtObj;
6186ASN1HEX.getNthChildIndex_AtObj = _asnhex_getNthChildIndex_AtObj;
6187ASN1HEX.getDecendantIndexByNthList = _asnhex_getDecendantIndexByNthList;
6188ASN1HEX.getDecendantHexVByNthList = _asnhex_getDecendantHexVByNthList;
6189ASN1HEX.getDecendantHexTLVByNthList = _asnhex_getDecendantHexTLVByNthList;
Jeff Thompson1a338f82012-12-29 17:07:04 -08006190/*! x509-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
6191 */
6192//
6193// x509.js - X509 class to read subject public key from certificate.
6194//
6195// version: 1.1 (10-May-2012)
6196//
6197// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
6198//
6199// This software is licensed under the terms of the MIT License.
6200// http://kjur.github.com/jsrsasign/license
6201//
6202// The above copyright and license notice shall be
6203// included in all copies or substantial portions of the Software.
6204//
6205
6206// Depends:
6207// base64.js
6208// rsa.js
6209// asn1hex.js
6210
6211function _x509_pemToBase64(sCertPEM) {
6212 var s = sCertPEM;
6213 s = s.replace("-----BEGIN CERTIFICATE-----", "");
6214 s = s.replace("-----END CERTIFICATE-----", "");
6215 s = s.replace(/[ \n]+/g, "");
6216 return s;
6217}
6218
6219function _x509_pemToHex(sCertPEM) {
6220 var b64Cert = _x509_pemToBase64(sCertPEM);
6221 var hCert = b64tohex(b64Cert);
6222 return hCert;
6223}
6224
6225function _x509_getHexTbsCertificateFromCert(hCert) {
6226 var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0);
6227 return pTbsCert;
6228}
6229
6230// NOTE: privateKeyUsagePeriod field of X509v2 not supported.
6231// NOTE: v1 and v3 supported
6232function _x509_getSubjectPublicKeyInfoPosFromCertHex(hCert) {
6233 var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0);
6234 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pTbsCert);
6235 if (a.length < 1) return -1;
6236 if (hCert.substring(a[0], a[0] + 10) == "a003020102") { // v3
6237 if (a.length < 6) return -1;
6238 return a[6];
6239 } else {
6240 if (a.length < 5) return -1;
6241 return a[5];
6242 }
6243}
6244
6245// NOTE: Without BITSTRING encapsulation.
6246// If pInfo is supplied, it is the position in hCert of the SubjectPublicKeyInfo.
6247function _x509_getSubjectPublicKeyPosFromCertHex(hCert, pInfo) {
6248 if (pInfo == null)
6249 pInfo = _x509_getSubjectPublicKeyInfoPosFromCertHex(hCert);
6250 if (pInfo == -1) return -1;
6251 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pInfo);
6252
6253 if (a.length != 2) return -1;
6254 var pBitString = a[1];
6255 if (hCert.substring(pBitString, pBitString + 2) != '03') return -1;
6256 var pBitStringV = ASN1HEX.getStartPosOfV_AtObj(hCert, pBitString);
6257
6258 if (hCert.substring(pBitStringV, pBitStringV + 2) != '00') return -1;
6259 return pBitStringV + 2;
6260}
6261
6262// If p is supplied, it is the public key position in hCert.
6263function _x509_getPublicKeyHexArrayFromCertHex(hCert, p) {
6264 if (p == null)
6265 p = _x509_getSubjectPublicKeyPosFromCertHex(hCert);
6266 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, p);
6267 //var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a[3]);
6268 if(LOG>4){
6269 console.log('a is now');
6270 console.log(a);
6271 }
6272
6273 //if (a.length != 2) return [];
6274 if (a.length < 2) return [];
6275
6276 var hN = ASN1HEX.getHexOfV_AtObj(hCert, a[0]);
6277 var hE = ASN1HEX.getHexOfV_AtObj(hCert, a[1]);
6278 if (hN != null && hE != null) {
6279 return [hN, hE];
6280 } else {
6281 return [];
6282 }
6283}
6284
6285function _x509_getPublicKeyHexArrayFromCertPEM(sCertPEM) {
6286 var hCert = _x509_pemToHex(sCertPEM);
6287 var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
6288 return a;
6289}
6290
6291// ===== get basic fields from hex =====================================
6292/**
6293 * get hexadecimal string of serialNumber field of certificate.<br/>
6294 * @name getSerialNumberHex
6295 * @memberOf X509#
6296 * @function
6297 */
6298function _x509_getSerialNumberHex() {
6299 return ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 1]);
6300}
6301
6302/**
6303 * get hexadecimal string of issuer field of certificate.<br/>
6304 * @name getIssuerHex
6305 * @memberOf X509#
6306 * @function
6307 */
6308function _x509_getIssuerHex() {
6309 return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]);
6310}
6311
6312/**
6313 * get string of issuer field of certificate.<br/>
6314 * @name getIssuerString
6315 * @memberOf X509#
6316 * @function
6317 */
6318function _x509_getIssuerString() {
6319 return _x509_hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]));
6320}
6321
6322/**
6323 * get hexadecimal string of subject field of certificate.<br/>
6324 * @name getSubjectHex
6325 * @memberOf X509#
6326 * @function
6327 */
6328function _x509_getSubjectHex() {
6329 return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]);
6330}
6331
6332/**
6333 * get string of subject field of certificate.<br/>
6334 * @name getSubjectString
6335 * @memberOf X509#
6336 * @function
6337 */
6338function _x509_getSubjectString() {
6339 return _x509_hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]));
6340}
6341
6342/**
6343 * get notBefore field string of certificate.<br/>
6344 * @name getNotBefore
6345 * @memberOf X509#
6346 * @function
6347 */
6348function _x509_getNotBefore() {
6349 var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 0]);
6350 s = s.replace(/(..)/g, "%$1");
6351 s = decodeURIComponent(s);
6352 return s;
6353}
6354
6355/**
6356 * get notAfter field string of certificate.<br/>
6357 * @name getNotAfter
6358 * @memberOf X509#
6359 * @function
6360 */
6361function _x509_getNotAfter() {
6362 var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 1]);
6363 s = s.replace(/(..)/g, "%$1");
6364 s = decodeURIComponent(s);
6365 return s;
6366}
6367
6368// ===== read certificate =====================================
6369
6370_x509_DN_ATTRHEX = {
6371 "0603550406": "C",
6372 "060355040a": "O",
6373 "060355040b": "OU",
6374 "0603550403": "CN",
6375 "0603550405": "SN",
6376 "0603550408": "ST",
6377 "0603550407": "L" };
6378
6379function _x509_hex2dn(hDN) {
6380 var s = "";
6381 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hDN, 0);
6382 for (var i = 0; i < a.length; i++) {
6383 var hRDN = ASN1HEX.getHexOfTLV_AtObj(hDN, a[i]);
6384 s = s + "/" + _x509_hex2rdn(hRDN);
6385 }
6386 return s;
6387}
6388
6389function _x509_hex2rdn(hRDN) {
6390 var hType = ASN1HEX.getDecendantHexTLVByNthList(hRDN, 0, [0, 0]);
6391 var hValue = ASN1HEX.getDecendantHexVByNthList(hRDN, 0, [0, 1]);
6392 var type = "";
6393 try { type = _x509_DN_ATTRHEX[hType]; } catch (ex) { type = hType; }
6394 hValue = hValue.replace(/(..)/g, "%$1");
6395 var value = decodeURIComponent(hValue);
6396 return type + "=" + value;
6397}
6398
6399// ===== read certificate =====================================
6400
6401
6402/**
6403 * read PEM formatted X.509 certificate from string.<br/>
6404 * @name readCertPEM
6405 * @memberOf X509#
6406 * @function
6407 * @param {String} sCertPEM string for PEM formatted X.509 certificate
6408 */
6409function _x509_readCertPEM(sCertPEM) {
6410 var hCert = _x509_pemToHex(sCertPEM);
6411 var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
6412 if(LOG>4){
6413 console.log('HEX VALUE IS ' + hCert);
6414 console.log('type of a' + typeof a);
6415 console.log('a VALUE IS ');
6416 console.log(a);
6417 console.log('a[0] VALUE IS ' + a[0]);
6418 console.log('a[1] VALUE IS ' + a[1]);
6419 }
6420 var rsa = new RSAKey();
6421 rsa.setPublic(a[0], a[1]);
6422 this.subjectPublicKeyRSA = rsa;
6423 this.subjectPublicKeyRSA_hN = a[0];
6424 this.subjectPublicKeyRSA_hE = a[1];
6425 this.hex = hCert;
6426}
6427
6428/**
6429 * read hex formatted X.509 certificate from string.
6430 * @name readCertHex
6431 * @memberOf X509#
6432 * @function
6433 * @param {String} hCert string for hex formatted X.509 certificate
6434 */
6435function _x509_readCertHex(hCert) {
6436 hCert = hCert.toLowerCase();
6437 var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
6438 var rsa = new RSAKey();
6439 rsa.setPublic(a[0], a[1]);
6440 this.subjectPublicKeyRSA = rsa;
6441 this.subjectPublicKeyRSA_hN = a[0];
6442 this.subjectPublicKeyRSA_hE = a[1];
6443 this.hex = hCert;
6444}
6445
6446function _x509_readCertPEMWithoutRSAInit(sCertPEM) {
6447 var hCert = _x509_pemToHex(sCertPEM);
6448 var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
6449 this.subjectPublicKeyRSA.setPublic(a[0], a[1]);
6450 this.subjectPublicKeyRSA_hN = a[0];
6451 this.subjectPublicKeyRSA_hE = a[1];
6452 this.hex = hCert;
6453}
6454
6455/**
6456 * X.509 certificate class.<br/>
6457 * @class X.509 certificate class
6458 * @property {RSAKey} subjectPublicKeyRSA Tom Wu's RSAKey object
6459 * @property {String} subjectPublicKeyRSA_hN hexadecimal string for modulus of RSA public key
6460 * @property {String} subjectPublicKeyRSA_hE hexadecimal string for public exponent of RSA public key
6461 * @property {String} hex hexacedimal string for X.509 certificate.
6462 * @author Kenji Urushima
6463 * @version 1.0.1 (08 May 2012)
6464 * @see <a href="http://kjur.github.com/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a>
6465 */
6466function X509() {
6467 this.subjectPublicKeyRSA = null;
6468 this.subjectPublicKeyRSA_hN = null;
6469 this.subjectPublicKeyRSA_hE = null;
6470 this.hex = null;
6471}
6472
6473X509.prototype.readCertPEM = _x509_readCertPEM;
6474X509.prototype.readCertHex = _x509_readCertHex;
6475X509.prototype.readCertPEMWithoutRSAInit = _x509_readCertPEMWithoutRSAInit;
6476X509.prototype.getSerialNumberHex = _x509_getSerialNumberHex;
6477X509.prototype.getIssuerHex = _x509_getIssuerHex;
6478X509.prototype.getSubjectHex = _x509_getSubjectHex;
6479X509.prototype.getIssuerString = _x509_getIssuerString;
6480X509.prototype.getSubjectString = _x509_getSubjectString;
6481X509.prototype.getNotBefore = _x509_getNotBefore;
6482X509.prototype.getNotAfter = _x509_getNotAfter;
6483
Wentao Shang0e291c82012-12-02 23:36:29 -08006484// Copyright (c) 2005 Tom Wu
6485// All Rights Reserved.
6486// See "LICENSE" for details.
6487
6488// Basic JavaScript BN library - subset useful for RSA encryption.
6489
6490// Bits per digit
6491var dbits;
6492
6493// JavaScript engine analysis
6494var canary = 0xdeadbeefcafe;
6495var j_lm = ((canary&0xffffff)==0xefcafe);
6496
6497// (public) Constructor
6498function BigInteger(a,b,c) {
6499 if(a != null)
6500 if("number" == typeof a) this.fromNumber(a,b,c);
6501 else if(b == null && "string" != typeof a) this.fromString(a,256);
6502 else this.fromString(a,b);
6503}
6504
6505// return new, unset BigInteger
6506function nbi() { return new BigInteger(null); }
6507
6508// am: Compute w_j += (x*this_i), propagate carries,
6509// c is initial carry, returns final carry.
6510// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
6511// We need to select the fastest one that works in this environment.
6512
6513// am1: use a single mult and divide to get the high bits,
6514// max digit bits should be 26 because
6515// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
6516function am1(i,x,w,j,c,n) {
6517 while(--n >= 0) {
6518 var v = x*this[i++]+w[j]+c;
6519 c = Math.floor(v/0x4000000);
6520 w[j++] = v&0x3ffffff;
6521 }
6522 return c;
6523}
6524// am2 avoids a big mult-and-extract completely.
6525// Max digit bits should be <= 30 because we do bitwise ops
6526// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
6527function am2(i,x,w,j,c,n) {
6528 var xl = x&0x7fff, xh = x>>15;
6529 while(--n >= 0) {
6530 var l = this[i]&0x7fff;
6531 var h = this[i++]>>15;
6532 var m = xh*l+h*xl;
6533 l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff);
6534 c = (l>>>30)+(m>>>15)+xh*h+(c>>>30);
6535 w[j++] = l&0x3fffffff;
6536 }
6537 return c;
6538}
6539// Alternately, set max digit bits to 28 since some
6540// browsers slow down when dealing with 32-bit numbers.
6541function am3(i,x,w,j,c,n) {
6542 var xl = x&0x3fff, xh = x>>14;
6543 while(--n >= 0) {
6544 var l = this[i]&0x3fff;
6545 var h = this[i++]>>14;
6546 var m = xh*l+h*xl;
6547 l = xl*l+((m&0x3fff)<<14)+w[j]+c;
6548 c = (l>>28)+(m>>14)+xh*h;
6549 w[j++] = l&0xfffffff;
6550 }
6551 return c;
6552}
6553if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
6554 BigInteger.prototype.am = am2;
6555 dbits = 30;
6556}
6557else if(j_lm && (navigator.appName != "Netscape")) {
6558 BigInteger.prototype.am = am1;
6559 dbits = 26;
6560}
6561else { // Mozilla/Netscape seems to prefer am3
6562 BigInteger.prototype.am = am3;
6563 dbits = 28;
6564}
6565
6566BigInteger.prototype.DB = dbits;
6567BigInteger.prototype.DM = ((1<<dbits)-1);
6568BigInteger.prototype.DV = (1<<dbits);
6569
6570var BI_FP = 52;
6571BigInteger.prototype.FV = Math.pow(2,BI_FP);
6572BigInteger.prototype.F1 = BI_FP-dbits;
6573BigInteger.prototype.F2 = 2*dbits-BI_FP;
6574
6575// Digit conversions
6576var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
6577var BI_RC = new Array();
6578var rr,vv;
6579rr = "0".charCodeAt(0);
6580for(vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
6581rr = "a".charCodeAt(0);
6582for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
6583rr = "A".charCodeAt(0);
6584for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
6585
6586function int2char(n) { return BI_RM.charAt(n); }
6587function intAt(s,i) {
6588 var c = BI_RC[s.charCodeAt(i)];
6589 return (c==null)?-1:c;
6590}
6591
6592// (protected) copy this to r
6593function bnpCopyTo(r) {
6594 for(var i = this.t-1; i >= 0; --i) r[i] = this[i];
6595 r.t = this.t;
6596 r.s = this.s;
6597}
6598
6599// (protected) set from integer value x, -DV <= x < DV
6600function bnpFromInt(x) {
6601 this.t = 1;
6602 this.s = (x<0)?-1:0;
6603 if(x > 0) this[0] = x;
6604 else if(x < -1) this[0] = x+DV;
6605 else this.t = 0;
6606}
6607
6608// return bigint initialized to value
6609function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
6610
6611// (protected) set from string and radix
6612function bnpFromString(s,b) {
6613 var k;
6614 if(b == 16) k = 4;
6615 else if(b == 8) k = 3;
6616 else if(b == 256) k = 8; // byte array
6617 else if(b == 2) k = 1;
6618 else if(b == 32) k = 5;
6619 else if(b == 4) k = 2;
6620 else { this.fromRadix(s,b); return; }
6621 this.t = 0;
6622 this.s = 0;
6623 var i = s.length, mi = false, sh = 0;
6624 while(--i >= 0) {
6625 var x = (k==8)?s[i]&0xff:intAt(s,i);
6626 if(x < 0) {
6627 if(s.charAt(i) == "-") mi = true;
6628 continue;
6629 }
6630 mi = false;
6631 if(sh == 0)
6632 this[this.t++] = x;
6633 else if(sh+k > this.DB) {
6634 this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<<sh;
6635 this[this.t++] = (x>>(this.DB-sh));
6636 }
6637 else
6638 this[this.t-1] |= x<<sh;
6639 sh += k;
6640 if(sh >= this.DB) sh -= this.DB;
6641 }
6642 if(k == 8 && (s[0]&0x80) != 0) {
6643 this.s = -1;
6644 if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh;
6645 }
6646 this.clamp();
6647 if(mi) BigInteger.ZERO.subTo(this,this);
6648}
6649
6650// (protected) clamp off excess high words
6651function bnpClamp() {
6652 var c = this.s&this.DM;
6653 while(this.t > 0 && this[this.t-1] == c) --this.t;
6654}
6655
6656// (public) return string representation in given radix
6657function bnToString(b) {
6658 if(this.s < 0) return "-"+this.negate().toString(b);
6659 var k;
6660 if(b == 16) k = 4;
6661 else if(b == 8) k = 3;
6662 else if(b == 2) k = 1;
6663 else if(b == 32) k = 5;
6664 else if(b == 4) k = 2;
6665 else return this.toRadix(b);
6666 var km = (1<<k)-1, d, m = false, r = "", i = this.t;
6667 var p = this.DB-(i*this.DB)%k;
6668 if(i-- > 0) {
6669 if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); }
6670 while(i >= 0) {
6671 if(p < k) {
6672 d = (this[i]&((1<<p)-1))<<(k-p);
6673 d |= this[--i]>>(p+=this.DB-k);
6674 }
6675 else {
6676 d = (this[i]>>(p-=k))&km;
6677 if(p <= 0) { p += this.DB; --i; }
6678 }
6679 if(d > 0) m = true;
6680 if(m) r += int2char(d);
6681 }
6682 }
6683 return m?r:"0";
6684}
6685
6686// (public) -this
6687function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }
6688
6689// (public) |this|
6690function bnAbs() { return (this.s<0)?this.negate():this; }
6691
6692// (public) return + if this > a, - if this < a, 0 if equal
6693function bnCompareTo(a) {
6694 var r = this.s-a.s;
6695 if(r != 0) return r;
6696 var i = this.t;
6697 r = i-a.t;
6698 if(r != 0) return r;
6699 while(--i >= 0) if((r=this[i]-a[i]) != 0) return r;
6700 return 0;
6701}
6702
6703// returns bit length of the integer x
6704function nbits(x) {
6705 var r = 1, t;
6706 if((t=x>>>16) != 0) { x = t; r += 16; }
6707 if((t=x>>8) != 0) { x = t; r += 8; }
6708 if((t=x>>4) != 0) { x = t; r += 4; }
6709 if((t=x>>2) != 0) { x = t; r += 2; }
6710 if((t=x>>1) != 0) { x = t; r += 1; }
6711 return r;
6712}
6713
6714// (public) return the number of bits in "this"
6715function bnBitLength() {
6716 if(this.t <= 0) return 0;
6717 return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM));
6718}
6719
6720// (protected) r = this << n*DB
6721function bnpDLShiftTo(n,r) {
6722 var i;
6723 for(i = this.t-1; i >= 0; --i) r[i+n] = this[i];
6724 for(i = n-1; i >= 0; --i) r[i] = 0;
6725 r.t = this.t+n;
6726 r.s = this.s;
6727}
6728
6729// (protected) r = this >> n*DB
6730function bnpDRShiftTo(n,r) {
6731 for(var i = n; i < this.t; ++i) r[i-n] = this[i];
6732 r.t = Math.max(this.t-n,0);
6733 r.s = this.s;
6734}
6735
6736// (protected) r = this << n
6737function bnpLShiftTo(n,r) {
6738 var bs = n%this.DB;
6739 var cbs = this.DB-bs;
6740 var bm = (1<<cbs)-1;
6741 var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i;
6742 for(i = this.t-1; i >= 0; --i) {
6743 r[i+ds+1] = (this[i]>>cbs)|c;
6744 c = (this[i]&bm)<<bs;
6745 }
6746 for(i = ds-1; i >= 0; --i) r[i] = 0;
6747 r[ds] = c;
6748 r.t = this.t+ds+1;
6749 r.s = this.s;
6750 r.clamp();
6751}
6752
6753// (protected) r = this >> n
6754function bnpRShiftTo(n,r) {
6755 r.s = this.s;
6756 var ds = Math.floor(n/this.DB);
6757 if(ds >= this.t) { r.t = 0; return; }
6758 var bs = n%this.DB;
6759 var cbs = this.DB-bs;
6760 var bm = (1<<bs)-1;
6761 r[0] = this[ds]>>bs;
6762 for(var i = ds+1; i < this.t; ++i) {
6763 r[i-ds-1] |= (this[i]&bm)<<cbs;
6764 r[i-ds] = this[i]>>bs;
6765 }
6766 if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs;
6767 r.t = this.t-ds;
6768 r.clamp();
6769}
6770
6771// (protected) r = this - a
6772function bnpSubTo(a,r) {
6773 var i = 0, c = 0, m = Math.min(a.t,this.t);
6774 while(i < m) {
6775 c += this[i]-a[i];
6776 r[i++] = c&this.DM;
6777 c >>= this.DB;
6778 }
6779 if(a.t < this.t) {
6780 c -= a.s;
6781 while(i < this.t) {
6782 c += this[i];
6783 r[i++] = c&this.DM;
6784 c >>= this.DB;
6785 }
6786 c += this.s;
6787 }
6788 else {
6789 c += this.s;
6790 while(i < a.t) {
6791 c -= a[i];
6792 r[i++] = c&this.DM;
6793 c >>= this.DB;
6794 }
6795 c -= a.s;
6796 }
6797 r.s = (c<0)?-1:0;
6798 if(c < -1) r[i++] = this.DV+c;
6799 else if(c > 0) r[i++] = c;
6800 r.t = i;
6801 r.clamp();
6802}
6803
6804// (protected) r = this * a, r != this,a (HAC 14.12)
6805// "this" should be the larger one if appropriate.
6806function bnpMultiplyTo(a,r) {
6807 var x = this.abs(), y = a.abs();
6808 var i = x.t;
6809 r.t = i+y.t;
6810 while(--i >= 0) r[i] = 0;
6811 for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t);
6812 r.s = 0;
6813 r.clamp();
6814 if(this.s != a.s) BigInteger.ZERO.subTo(r,r);
6815}
6816
6817// (protected) r = this^2, r != this (HAC 14.16)
6818function bnpSquareTo(r) {
6819 var x = this.abs();
6820 var i = r.t = 2*x.t;
6821 while(--i >= 0) r[i] = 0;
6822 for(i = 0; i < x.t-1; ++i) {
6823 var c = x.am(i,x[i],r,2*i,0,1);
6824 if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) {
6825 r[i+x.t] -= x.DV;
6826 r[i+x.t+1] = 1;
6827 }
6828 }
6829 if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1);
6830 r.s = 0;
6831 r.clamp();
6832}
6833
6834// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
6835// r != q, this != m. q or r may be null.
6836function bnpDivRemTo(m,q,r) {
6837 var pm = m.abs();
6838 if(pm.t <= 0) return;
6839 var pt = this.abs();
6840 if(pt.t < pm.t) {
6841 if(q != null) q.fromInt(0);
6842 if(r != null) this.copyTo(r);
6843 return;
6844 }
6845 if(r == null) r = nbi();
6846 var y = nbi(), ts = this.s, ms = m.s;
6847 var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus
6848 if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); }
6849 else { pm.copyTo(y); pt.copyTo(r); }
6850 var ys = y.t;
6851 var y0 = y[ys-1];
6852 if(y0 == 0) return;
6853 var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0);
6854 var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
6855 var i = r.t, j = i-ys, t = (q==null)?nbi():q;
6856 y.dlShiftTo(j,t);
6857 if(r.compareTo(t) >= 0) {
6858 r[r.t++] = 1;
6859 r.subTo(t,r);
6860 }
6861 BigInteger.ONE.dlShiftTo(ys,t);
6862 t.subTo(y,y); // "negative" y so we can replace sub with am later
6863 while(y.t < ys) y[y.t++] = 0;
6864 while(--j >= 0) {
6865 // Estimate quotient digit
6866 var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);
6867 if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out
6868 y.dlShiftTo(j,t);
6869 r.subTo(t,r);
6870 while(r[i] < --qd) r.subTo(t,r);
6871 }
6872 }
6873 if(q != null) {
6874 r.drShiftTo(ys,q);
6875 if(ts != ms) BigInteger.ZERO.subTo(q,q);
6876 }
6877 r.t = ys;
6878 r.clamp();
6879 if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder
6880 if(ts < 0) BigInteger.ZERO.subTo(r,r);
6881}
6882
6883// (public) this mod a
6884function bnMod(a) {
6885 var r = nbi();
6886 this.abs().divRemTo(a,null,r);
6887 if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r);
6888 return r;
6889}
6890
6891// Modular reduction using "classic" algorithm
6892function Classic(m) { this.m = m; }
6893function cConvert(x) {
6894 if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
6895 else return x;
6896}
6897function cRevert(x) { return x; }
6898function cReduce(x) { x.divRemTo(this.m,null,x); }
6899function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
6900function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
6901
6902Classic.prototype.convert = cConvert;
6903Classic.prototype.revert = cRevert;
6904Classic.prototype.reduce = cReduce;
6905Classic.prototype.mulTo = cMulTo;
6906Classic.prototype.sqrTo = cSqrTo;
6907
6908// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
6909// justification:
6910// xy == 1 (mod m)
6911// xy = 1+km
6912// xy(2-xy) = (1+km)(1-km)
6913// x[y(2-xy)] = 1-k^2m^2
6914// x[y(2-xy)] == 1 (mod m^2)
6915// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
6916// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
6917// JS multiply "overflows" differently from C/C++, so care is needed here.
6918function bnpInvDigit() {
6919 if(this.t < 1) return 0;
6920 var x = this[0];
6921 if((x&1) == 0) return 0;
6922 var y = x&3; // y == 1/x mod 2^2
6923 y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4
6924 y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8
6925 y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16
6926 // last step - calculate inverse mod DV directly;
6927 // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
6928 y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits
6929 // we really want the negative inverse, and -DV < y < DV
6930 return (y>0)?this.DV-y:-y;
6931}
6932
6933// Montgomery reduction
6934function Montgomery(m) {
6935 this.m = m;
6936 this.mp = m.invDigit();
6937 this.mpl = this.mp&0x7fff;
6938 this.mph = this.mp>>15;
6939 this.um = (1<<(m.DB-15))-1;
6940 this.mt2 = 2*m.t;
6941}
6942
6943// xR mod m
6944function montConvert(x) {
6945 var r = nbi();
6946 x.abs().dlShiftTo(this.m.t,r);
6947 r.divRemTo(this.m,null,r);
6948 if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r);
6949 return r;
6950}
6951
6952// x/R mod m
6953function montRevert(x) {
6954 var r = nbi();
6955 x.copyTo(r);
6956 this.reduce(r);
6957 return r;
6958}
6959
6960// x = x/R mod m (HAC 14.32)
6961function montReduce(x) {
6962 while(x.t <= this.mt2) // pad x so am has enough room later
6963 x[x.t++] = 0;
6964 for(var i = 0; i < this.m.t; ++i) {
6965 // faster way of calculating u0 = x[i]*mp mod DV
6966 var j = x[i]&0x7fff;
6967 var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM;
6968 // use am to combine the multiply-shift-add into one call
6969 j = i+this.m.t;
6970 x[j] += this.m.am(0,u0,x,i,0,this.m.t);
6971 // propagate carry
6972 while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; }
6973 }
6974 x.clamp();
6975 x.drShiftTo(this.m.t,x);
6976 if(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
6977}
6978
6979// r = "x^2/R mod m"; x != r
6980function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
6981
6982// r = "xy/R mod m"; x,y != r
6983function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
6984
6985Montgomery.prototype.convert = montConvert;
6986Montgomery.prototype.revert = montRevert;
6987Montgomery.prototype.reduce = montReduce;
6988Montgomery.prototype.mulTo = montMulTo;
6989Montgomery.prototype.sqrTo = montSqrTo;
6990
6991// (protected) true iff this is even
6992function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; }
6993
6994// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
6995function bnpExp(e,z) {
6996 if(e > 0xffffffff || e < 1) return BigInteger.ONE;
6997 var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1;
6998 g.copyTo(r);
6999 while(--i >= 0) {
7000 z.sqrTo(r,r2);
7001 if((e&(1<<i)) > 0) z.mulTo(r2,g,r);
7002 else { var t = r; r = r2; r2 = t; }
7003 }
7004 return z.revert(r);
7005}
7006
7007// (public) this^e % m, 0 <= e < 2^32
7008function bnModPowInt(e,m) {
7009 var z;
7010 if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
7011 return this.exp(e,z);
7012}
7013
7014// protected
7015BigInteger.prototype.copyTo = bnpCopyTo;
7016BigInteger.prototype.fromInt = bnpFromInt;
7017BigInteger.prototype.fromString = bnpFromString;
7018BigInteger.prototype.clamp = bnpClamp;
7019BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
7020BigInteger.prototype.drShiftTo = bnpDRShiftTo;
7021BigInteger.prototype.lShiftTo = bnpLShiftTo;
7022BigInteger.prototype.rShiftTo = bnpRShiftTo;
7023BigInteger.prototype.subTo = bnpSubTo;
7024BigInteger.prototype.multiplyTo = bnpMultiplyTo;
7025BigInteger.prototype.squareTo = bnpSquareTo;
7026BigInteger.prototype.divRemTo = bnpDivRemTo;
7027BigInteger.prototype.invDigit = bnpInvDigit;
7028BigInteger.prototype.isEven = bnpIsEven;
7029BigInteger.prototype.exp = bnpExp;
7030
7031// public
7032BigInteger.prototype.toString = bnToString;
7033BigInteger.prototype.negate = bnNegate;
7034BigInteger.prototype.abs = bnAbs;
7035BigInteger.prototype.compareTo = bnCompareTo;
7036BigInteger.prototype.bitLength = bnBitLength;
7037BigInteger.prototype.mod = bnMod;
7038BigInteger.prototype.modPowInt = bnModPowInt;
7039
7040// "constants"
7041BigInteger.ZERO = nbv(0);
7042BigInteger.ONE = nbv(1);
7043// Copyright (c) 2005-2009 Tom Wu
7044// All Rights Reserved.
7045// See "LICENSE" for details.
7046
7047// Extended JavaScript BN functions, required for RSA private ops.
7048
7049// Version 1.1: new BigInteger("0", 10) returns "proper" zero
7050
7051// (public)
7052function bnClone() { var r = nbi(); this.copyTo(r); return r; }
7053
7054// (public) return value as integer
7055function bnIntValue() {
7056 if(this.s < 0) {
7057 if(this.t == 1) return this[0]-this.DV;
7058 else if(this.t == 0) return -1;
7059 }
7060 else if(this.t == 1) return this[0];
7061 else if(this.t == 0) return 0;
7062 // assumes 16 < DB < 32
7063 return ((this[1]&((1<<(32-this.DB))-1))<<this.DB)|this[0];
7064}
7065
7066// (public) return value as byte
7067function bnByteValue() { return (this.t==0)?this.s:(this[0]<<24)>>24; }
7068
7069// (public) return value as short (assumes DB>=16)
7070function bnShortValue() { return (this.t==0)?this.s:(this[0]<<16)>>16; }
7071
7072// (protected) return x s.t. r^x < DV
7073function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); }
7074
7075// (public) 0 if this == 0, 1 if this > 0
7076function bnSigNum() {
7077 if(this.s < 0) return -1;
7078 else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
7079 else return 1;
7080}
7081
7082// (protected) convert to radix string
7083function bnpToRadix(b) {
7084 if(b == null) b = 10;
7085 if(this.signum() == 0 || b < 2 || b > 36) return "0";
7086 var cs = this.chunkSize(b);
7087 var a = Math.pow(b,cs);
7088 var d = nbv(a), y = nbi(), z = nbi(), r = "";
7089 this.divRemTo(d,y,z);
7090 while(y.signum() > 0) {
7091 r = (a+z.intValue()).toString(b).substr(1) + r;
7092 y.divRemTo(d,y,z);
7093 }
7094 return z.intValue().toString(b) + r;
7095}
7096
7097// (protected) convert from radix string
7098function bnpFromRadix(s,b) {
7099 this.fromInt(0);
7100 if(b == null) b = 10;
7101 var cs = this.chunkSize(b);
7102 var d = Math.pow(b,cs), mi = false, j = 0, w = 0;
7103 for(var i = 0; i < s.length; ++i) {
7104 var x = intAt(s,i);
7105 if(x < 0) {
7106 if(s.charAt(i) == "-" && this.signum() == 0) mi = true;
7107 continue;
7108 }
7109 w = b*w+x;
7110 if(++j >= cs) {
7111 this.dMultiply(d);
7112 this.dAddOffset(w,0);
7113 j = 0;
7114 w = 0;
7115 }
7116 }
7117 if(j > 0) {
7118 this.dMultiply(Math.pow(b,j));
7119 this.dAddOffset(w,0);
7120 }
7121 if(mi) BigInteger.ZERO.subTo(this,this);
7122}
7123
7124// (protected) alternate constructor
7125function bnpFromNumber(a,b,c) {
7126 if("number" == typeof b) {
7127 // new BigInteger(int,int,RNG)
7128 if(a < 2) this.fromInt(1);
7129 else {
7130 this.fromNumber(a,c);
7131 if(!this.testBit(a-1)) // force MSB set
7132 this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this);
7133 if(this.isEven()) this.dAddOffset(1,0); // force odd
7134 while(!this.isProbablePrime(b)) {
7135 this.dAddOffset(2,0);
7136 if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this);
7137 }
7138 }
7139 }
7140 else {
7141 // new BigInteger(int,RNG)
7142 var x = new Array(), t = a&7;
7143 x.length = (a>>3)+1;
7144 b.nextBytes(x);
7145 if(t > 0) x[0] &= ((1<<t)-1); else x[0] = 0;
7146 this.fromString(x,256);
7147 }
7148}
7149
7150// (public) convert to bigendian byte array
7151function bnToByteArray() {
7152 var i = this.t, r = new Array();
7153 r[0] = this.s;
7154 var p = this.DB-(i*this.DB)%8, d, k = 0;
7155 if(i-- > 0) {
7156 if(p < this.DB && (d = this[i]>>p) != (this.s&this.DM)>>p)
7157 r[k++] = d|(this.s<<(this.DB-p));
7158 while(i >= 0) {
7159 if(p < 8) {
7160 d = (this[i]&((1<<p)-1))<<(8-p);
7161 d |= this[--i]>>(p+=this.DB-8);
7162 }
7163 else {
7164 d = (this[i]>>(p-=8))&0xff;
7165 if(p <= 0) { p += this.DB; --i; }
7166 }
7167 if((d&0x80) != 0) d |= -256;
7168 if(k == 0 && (this.s&0x80) != (d&0x80)) ++k;
7169 if(k > 0 || d != this.s) r[k++] = d;
7170 }
7171 }
7172 return r;
7173}
7174
7175function bnEquals(a) { return(this.compareTo(a)==0); }
7176function bnMin(a) { return(this.compareTo(a)<0)?this:a; }
7177function bnMax(a) { return(this.compareTo(a)>0)?this:a; }
7178
7179// (protected) r = this op a (bitwise)
7180function bnpBitwiseTo(a,op,r) {
7181 var i, f, m = Math.min(a.t,this.t);
7182 for(i = 0; i < m; ++i) r[i] = op(this[i],a[i]);
7183 if(a.t < this.t) {
7184 f = a.s&this.DM;
7185 for(i = m; i < this.t; ++i) r[i] = op(this[i],f);
7186 r.t = this.t;
7187 }
7188 else {
7189 f = this.s&this.DM;
7190 for(i = m; i < a.t; ++i) r[i] = op(f,a[i]);
7191 r.t = a.t;
7192 }
7193 r.s = op(this.s,a.s);
7194 r.clamp();
7195}
7196
7197// (public) this & a
7198function op_and(x,y) { return x&y; }
7199function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; }
7200
7201// (public) this | a
7202function op_or(x,y) { return x|y; }
7203function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; }
7204
7205// (public) this ^ a
7206function op_xor(x,y) { return x^y; }
7207function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; }
7208
7209// (public) this & ~a
7210function op_andnot(x,y) { return x&~y; }
7211function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; }
7212
7213// (public) ~this
7214function bnNot() {
7215 var r = nbi();
7216 for(var i = 0; i < this.t; ++i) r[i] = this.DM&~this[i];
7217 r.t = this.t;
7218 r.s = ~this.s;
7219 return r;
7220}
7221
7222// (public) this << n
7223function bnShiftLeft(n) {
7224 var r = nbi();
7225 if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r);
7226 return r;
7227}
7228
7229// (public) this >> n
7230function bnShiftRight(n) {
7231 var r = nbi();
7232 if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r);
7233 return r;
7234}
7235
7236// return index of lowest 1-bit in x, x < 2^31
7237function lbit(x) {
7238 if(x == 0) return -1;
7239 var r = 0;
7240 if((x&0xffff) == 0) { x >>= 16; r += 16; }
7241 if((x&0xff) == 0) { x >>= 8; r += 8; }
7242 if((x&0xf) == 0) { x >>= 4; r += 4; }
7243 if((x&3) == 0) { x >>= 2; r += 2; }
7244 if((x&1) == 0) ++r;
7245 return r;
7246}
7247
7248// (public) returns index of lowest 1-bit (or -1 if none)
7249function bnGetLowestSetBit() {
7250 for(var i = 0; i < this.t; ++i)
7251 if(this[i] != 0) return i*this.DB+lbit(this[i]);
7252 if(this.s < 0) return this.t*this.DB;
7253 return -1;
7254}
7255
7256// return number of 1 bits in x
7257function cbit(x) {
7258 var r = 0;
7259 while(x != 0) { x &= x-1; ++r; }
7260 return r;
7261}
7262
7263// (public) return number of set bits
7264function bnBitCount() {
7265 var r = 0, x = this.s&this.DM;
7266 for(var i = 0; i < this.t; ++i) r += cbit(this[i]^x);
7267 return r;
7268}
7269
7270// (public) true iff nth bit is set
7271function bnTestBit(n) {
7272 var j = Math.floor(n/this.DB);
7273 if(j >= this.t) return(this.s!=0);
7274 return((this[j]&(1<<(n%this.DB)))!=0);
7275}
7276
7277// (protected) this op (1<<n)
7278function bnpChangeBit(n,op) {
7279 var r = BigInteger.ONE.shiftLeft(n);
7280 this.bitwiseTo(r,op,r);
7281 return r;
7282}
7283
7284// (public) this | (1<<n)
7285function bnSetBit(n) { return this.changeBit(n,op_or); }
7286
7287// (public) this & ~(1<<n)
7288function bnClearBit(n) { return this.changeBit(n,op_andnot); }
7289
7290// (public) this ^ (1<<n)
7291function bnFlipBit(n) { return this.changeBit(n,op_xor); }
7292
7293// (protected) r = this + a
7294function bnpAddTo(a,r) {
7295 var i = 0, c = 0, m = Math.min(a.t,this.t);
7296 while(i < m) {
7297 c += this[i]+a[i];
7298 r[i++] = c&this.DM;
7299 c >>= this.DB;
7300 }
7301 if(a.t < this.t) {
7302 c += a.s;
7303 while(i < this.t) {
7304 c += this[i];
7305 r[i++] = c&this.DM;
7306 c >>= this.DB;
7307 }
7308 c += this.s;
7309 }
7310 else {
7311 c += this.s;
7312 while(i < a.t) {
7313 c += a[i];
7314 r[i++] = c&this.DM;
7315 c >>= this.DB;
7316 }
7317 c += a.s;
7318 }
7319 r.s = (c<0)?-1:0;
7320 if(c > 0) r[i++] = c;
7321 else if(c < -1) r[i++] = this.DV+c;
7322 r.t = i;
7323 r.clamp();
7324}
7325
7326// (public) this + a
7327function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; }
7328
7329// (public) this - a
7330function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; }
7331
7332// (public) this * a
7333function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; }
7334
7335// (public) this / a
7336function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; }
7337
7338// (public) this % a
7339function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; }
7340
7341// (public) [this/a,this%a]
7342function bnDivideAndRemainder(a) {
7343 var q = nbi(), r = nbi();
7344 this.divRemTo(a,q,r);
7345 return new Array(q,r);
7346}
7347
7348// (protected) this *= n, this >= 0, 1 < n < DV
7349function bnpDMultiply(n) {
7350 this[this.t] = this.am(0,n-1,this,0,0,this.t);
7351 ++this.t;
7352 this.clamp();
7353}
7354
7355// (protected) this += n << w words, this >= 0
7356function bnpDAddOffset(n,w) {
7357 if(n == 0) return;
7358 while(this.t <= w) this[this.t++] = 0;
7359 this[w] += n;
7360 while(this[w] >= this.DV) {
7361 this[w] -= this.DV;
7362 if(++w >= this.t) this[this.t++] = 0;
7363 ++this[w];
7364 }
7365}
7366
7367// A "null" reducer
7368function NullExp() {}
7369function nNop(x) { return x; }
7370function nMulTo(x,y,r) { x.multiplyTo(y,r); }
7371function nSqrTo(x,r) { x.squareTo(r); }
7372
7373NullExp.prototype.convert = nNop;
7374NullExp.prototype.revert = nNop;
7375NullExp.prototype.mulTo = nMulTo;
7376NullExp.prototype.sqrTo = nSqrTo;
7377
7378// (public) this^e
7379function bnPow(e) { return this.exp(e,new NullExp()); }
7380
7381// (protected) r = lower n words of "this * a", a.t <= n
7382// "this" should be the larger one if appropriate.
7383function bnpMultiplyLowerTo(a,n,r) {
7384 var i = Math.min(this.t+a.t,n);
7385 r.s = 0; // assumes a,this >= 0
7386 r.t = i;
7387 while(i > 0) r[--i] = 0;
7388 var j;
7389 for(j = r.t-this.t; i < j; ++i) r[i+this.t] = this.am(0,a[i],r,i,0,this.t);
7390 for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a[i],r,i,0,n-i);
7391 r.clamp();
7392}
7393
7394// (protected) r = "this * a" without lower n words, n > 0
7395// "this" should be the larger one if appropriate.
7396function bnpMultiplyUpperTo(a,n,r) {
7397 --n;
7398 var i = r.t = this.t+a.t-n;
7399 r.s = 0; // assumes a,this >= 0
7400 while(--i >= 0) r[i] = 0;
7401 for(i = Math.max(n-this.t,0); i < a.t; ++i)
7402 r[this.t+i-n] = this.am(n-i,a[i],r,0,0,this.t+i-n);
7403 r.clamp();
7404 r.drShiftTo(1,r);
7405}
7406
7407// Barrett modular reduction
7408function Barrett(m) {
7409 // setup Barrett
7410 this.r2 = nbi();
7411 this.q3 = nbi();
7412 BigInteger.ONE.dlShiftTo(2*m.t,this.r2);
7413 this.mu = this.r2.divide(m);
7414 this.m = m;
7415}
7416
7417function barrettConvert(x) {
7418 if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m);
7419 else if(x.compareTo(this.m) < 0) return x;
7420 else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; }
7421}
7422
7423function barrettRevert(x) { return x; }
7424
7425// x = x mod m (HAC 14.42)
7426function barrettReduce(x) {
7427 x.drShiftTo(this.m.t-1,this.r2);
7428 if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); }
7429 this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3);
7430 this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);
7431 while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1);
7432 x.subTo(this.r2,x);
7433 while(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
7434}
7435
7436// r = x^2 mod m; x != r
7437function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
7438
7439// r = x*y mod m; x,y != r
7440function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
7441
7442Barrett.prototype.convert = barrettConvert;
7443Barrett.prototype.revert = barrettRevert;
7444Barrett.prototype.reduce = barrettReduce;
7445Barrett.prototype.mulTo = barrettMulTo;
7446Barrett.prototype.sqrTo = barrettSqrTo;
7447
7448// (public) this^e % m (HAC 14.85)
7449function bnModPow(e,m) {
7450 var i = e.bitLength(), k, r = nbv(1), z;
7451 if(i <= 0) return r;
7452 else if(i < 18) k = 1;
7453 else if(i < 48) k = 3;
7454 else if(i < 144) k = 4;
7455 else if(i < 768) k = 5;
7456 else k = 6;
7457 if(i < 8)
7458 z = new Classic(m);
7459 else if(m.isEven())
7460 z = new Barrett(m);
7461 else
7462 z = new Montgomery(m);
7463
7464 // precomputation
7465 var g = new Array(), n = 3, k1 = k-1, km = (1<<k)-1;
7466 g[1] = z.convert(this);
7467 if(k > 1) {
7468 var g2 = nbi();
7469 z.sqrTo(g[1],g2);
7470 while(n <= km) {
7471 g[n] = nbi();
7472 z.mulTo(g2,g[n-2],g[n]);
7473 n += 2;
7474 }
7475 }
7476
7477 var j = e.t-1, w, is1 = true, r2 = nbi(), t;
7478 i = nbits(e[j])-1;
7479 while(j >= 0) {
7480 if(i >= k1) w = (e[j]>>(i-k1))&km;
7481 else {
7482 w = (e[j]&((1<<(i+1))-1))<<(k1-i);
7483 if(j > 0) w |= e[j-1]>>(this.DB+i-k1);
7484 }
7485
7486 n = k;
7487 while((w&1) == 0) { w >>= 1; --n; }
7488 if((i -= n) < 0) { i += this.DB; --j; }
7489 if(is1) { // ret == 1, don't bother squaring or multiplying it
7490 g[w].copyTo(r);
7491 is1 = false;
7492 }
7493 else {
7494 while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; }
7495 if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; }
7496 z.mulTo(r2,g[w],r);
7497 }
7498
7499 while(j >= 0 && (e[j]&(1<<i)) == 0) {
7500 z.sqrTo(r,r2); t = r; r = r2; r2 = t;
7501 if(--i < 0) { i = this.DB-1; --j; }
7502 }
7503 }
7504 return z.revert(r);
7505}
7506
7507// (public) gcd(this,a) (HAC 14.54)
7508function bnGCD(a) {
7509 var x = (this.s<0)?this.negate():this.clone();
7510 var y = (a.s<0)?a.negate():a.clone();
7511 if(x.compareTo(y) < 0) { var t = x; x = y; y = t; }
7512 var i = x.getLowestSetBit(), g = y.getLowestSetBit();
7513 if(g < 0) return x;
7514 if(i < g) g = i;
7515 if(g > 0) {
7516 x.rShiftTo(g,x);
7517 y.rShiftTo(g,y);
7518 }
7519 while(x.signum() > 0) {
7520 if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x);
7521 if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y);
7522 if(x.compareTo(y) >= 0) {
7523 x.subTo(y,x);
7524 x.rShiftTo(1,x);
7525 }
7526 else {
7527 y.subTo(x,y);
7528 y.rShiftTo(1,y);
7529 }
7530 }
7531 if(g > 0) y.lShiftTo(g,y);
7532 return y;
7533}
7534
7535// (protected) this % n, n < 2^26
7536function bnpModInt(n) {
7537 if(n <= 0) return 0;
7538 var d = this.DV%n, r = (this.s<0)?n-1:0;
7539 if(this.t > 0)
7540 if(d == 0) r = this[0]%n;
7541 else for(var i = this.t-1; i >= 0; --i) r = (d*r+this[i])%n;
7542 return r;
7543}
7544
7545// (public) 1/this % m (HAC 14.61)
7546function bnModInverse(m) {
7547 var ac = m.isEven();
7548 if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
7549 var u = m.clone(), v = this.clone();
7550 var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
7551 while(u.signum() != 0) {
7552 while(u.isEven()) {
7553 u.rShiftTo(1,u);
7554 if(ac) {
7555 if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); }
7556 a.rShiftTo(1,a);
7557 }
7558 else if(!b.isEven()) b.subTo(m,b);
7559 b.rShiftTo(1,b);
7560 }
7561 while(v.isEven()) {
7562 v.rShiftTo(1,v);
7563 if(ac) {
7564 if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); }
7565 c.rShiftTo(1,c);
7566 }
7567 else if(!d.isEven()) d.subTo(m,d);
7568 d.rShiftTo(1,d);
7569 }
7570 if(u.compareTo(v) >= 0) {
7571 u.subTo(v,u);
7572 if(ac) a.subTo(c,a);
7573 b.subTo(d,b);
7574 }
7575 else {
7576 v.subTo(u,v);
7577 if(ac) c.subTo(a,c);
7578 d.subTo(b,d);
7579 }
7580 }
7581 if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
7582 if(d.compareTo(m) >= 0) return d.subtract(m);
7583 if(d.signum() < 0) d.addTo(m,d); else return d;
7584 if(d.signum() < 0) return d.add(m); else return d;
7585}
7586
7587var 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];
7588var lplim = (1<<26)/lowprimes[lowprimes.length-1];
7589
7590// (public) test primality with certainty >= 1-.5^t
7591function bnIsProbablePrime(t) {
7592 var i, x = this.abs();
7593 if(x.t == 1 && x[0] <= lowprimes[lowprimes.length-1]) {
7594 for(i = 0; i < lowprimes.length; ++i)
7595 if(x[0] == lowprimes[i]) return true;
7596 return false;
7597 }
7598 if(x.isEven()) return false;
7599 i = 1;
7600 while(i < lowprimes.length) {
7601 var m = lowprimes[i], j = i+1;
7602 while(j < lowprimes.length && m < lplim) m *= lowprimes[j++];
7603 m = x.modInt(m);
7604 while(i < j) if(m%lowprimes[i++] == 0) return false;
7605 }
7606 return x.millerRabin(t);
7607}
7608
7609// (protected) true if probably prime (HAC 4.24, Miller-Rabin)
7610function bnpMillerRabin(t) {
7611 var n1 = this.subtract(BigInteger.ONE);
7612 var k = n1.getLowestSetBit();
7613 if(k <= 0) return false;
7614 var r = n1.shiftRight(k);
7615 t = (t+1)>>1;
7616 if(t > lowprimes.length) t = lowprimes.length;
7617 var a = nbi();
7618 for(var i = 0; i < t; ++i) {
7619 a.fromInt(lowprimes[i]);
7620 var y = a.modPow(r,this);
7621 if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {
7622 var j = 1;
7623 while(j++ < k && y.compareTo(n1) != 0) {
7624 y = y.modPowInt(2,this);
7625 if(y.compareTo(BigInteger.ONE) == 0) return false;
7626 }
7627 if(y.compareTo(n1) != 0) return false;
7628 }
7629 }
7630 return true;
7631}
7632
7633// protected
7634BigInteger.prototype.chunkSize = bnpChunkSize;
7635BigInteger.prototype.toRadix = bnpToRadix;
7636BigInteger.prototype.fromRadix = bnpFromRadix;
7637BigInteger.prototype.fromNumber = bnpFromNumber;
7638BigInteger.prototype.bitwiseTo = bnpBitwiseTo;
7639BigInteger.prototype.changeBit = bnpChangeBit;
7640BigInteger.prototype.addTo = bnpAddTo;
7641BigInteger.prototype.dMultiply = bnpDMultiply;
7642BigInteger.prototype.dAddOffset = bnpDAddOffset;
7643BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo;
7644BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo;
7645BigInteger.prototype.modInt = bnpModInt;
7646BigInteger.prototype.millerRabin = bnpMillerRabin;
7647
7648// public
7649BigInteger.prototype.clone = bnClone;
7650BigInteger.prototype.intValue = bnIntValue;
7651BigInteger.prototype.byteValue = bnByteValue;
7652BigInteger.prototype.shortValue = bnShortValue;
7653BigInteger.prototype.signum = bnSigNum;
7654BigInteger.prototype.toByteArray = bnToByteArray;
7655BigInteger.prototype.equals = bnEquals;
7656BigInteger.prototype.min = bnMin;
7657BigInteger.prototype.max = bnMax;
7658BigInteger.prototype.and = bnAnd;
7659BigInteger.prototype.or = bnOr;
7660BigInteger.prototype.xor = bnXor;
7661BigInteger.prototype.andNot = bnAndNot;
7662BigInteger.prototype.not = bnNot;
7663BigInteger.prototype.shiftLeft = bnShiftLeft;
7664BigInteger.prototype.shiftRight = bnShiftRight;
7665BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit;
7666BigInteger.prototype.bitCount = bnBitCount;
7667BigInteger.prototype.testBit = bnTestBit;
7668BigInteger.prototype.setBit = bnSetBit;
7669BigInteger.prototype.clearBit = bnClearBit;
7670BigInteger.prototype.flipBit = bnFlipBit;
7671BigInteger.prototype.add = bnAdd;
7672BigInteger.prototype.subtract = bnSubtract;
7673BigInteger.prototype.multiply = bnMultiply;
7674BigInteger.prototype.divide = bnDivide;
7675BigInteger.prototype.remainder = bnRemainder;
7676BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder;
7677BigInteger.prototype.modPow = bnModPow;
7678BigInteger.prototype.modInverse = bnModInverse;
7679BigInteger.prototype.pow = bnPow;
7680BigInteger.prototype.gcd = bnGCD;
7681BigInteger.prototype.isProbablePrime = bnIsProbablePrime;
7682
7683// BigInteger interfaces not implemented in jsbn:
7684
7685// BigInteger(int signum, byte[] magnitude)
7686// double doubleValue()
7687// float floatValue()
7688// int hashCode()
7689// long longValue()
7690// static BigInteger valueOf(long val)