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