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