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