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