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