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