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