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