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