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