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