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