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