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