blob: bc92e99906227d3271e145e40ed1dd9ae67fb1f6 [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
Wentao Shange0d7f052013-01-05 16:37:02 -0800349 var interest = new Interest(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 Shangbd63e462012-12-03 16:19:33 -08004491/**
Wentao Shang0e291c82012-12-02 23:36:29 -08004492 * @author: Meki Cheraoui
4493 * See COPYING for copyright and distribution information.
4494 */
4495
4496var KeyManager = function KeyManager(){
4497
4498
4499//Certificate
4500
4501this.certificate = 'MIIBmzCCAQQCCQC32FyQa61S7jANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwd'+
4502
4503'heGVsY2R2MB4XDTEyMDQyODIzNDQzN1oXDTEyMDUyODIzNDQzN1owEjEQMA4GA1'+
4504
4505'UEAxMHYXhlbGNkdjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4X0wp9goq'+
4506
4507'xuECxdULcr2IHr9Ih4Iaypg0Wy39URIup8/CLzQmdsh3RYqd55hqonu5VTTpH3i'+
4508
4509'MLx6xZDVJAZ8OJi7pvXcQ2C4Re2kjL2c8SanI0RfDhlS1zJadfr1VhRPmpivcYa'+
4510
4511'wJ4aFuOLAi+qHFxtN7lhcGCgpW1OV60oXd58CAwEAATANBgkqhkiG9w0BAQUFAA'+
4512
4513'OBgQDLOrA1fXzSrpftUB5Ro6DigX1Bjkf7F5Bkd69hSVp+jYeJFBBlsILQAfSxU'+
4514
4515'ZPQtD+2Yc3iCmSYNyxqu9PcufDRJlnvB7PG29+L3y9lR37tetzUV9eTscJ7rdp8'+
4516
4517'Wt6AzpW32IJ/54yKNfP7S6ZIoIG+LP6EIxq6s8K1MXRt8uBJKw==';
4518
4519
4520//this.publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhfTCn2CirG4QLF1QtyvYgev0iHghrKmDRbLf1REi6nz8IvNCZ2yHdFip3nmGqie7lVNOkfeIwvHrFkNUkBnw4mLum9dxDYLhF7aSMvZzxJqcjRF8OGVLXMlp1+vVWFE+amK9xhrAnhoW44sCL6ocXG03uWFwYKClbU5XrShd3nwIDAQAB';
4521this.publicKey ='30819F300D06092A864886F70D010101050003818D0030818902818100E17D30A7D828AB1B840B17542DCAF6207AFD221E086B2A60D16CB7F54448BA9F3F08BCD099DB21DD162A779E61AA89EEE554D3A47DE230BC7AC590D524067C3898BBA6F5DC4360B845EDA48CBD9CF126A723445F0E1952D7325A75FAF556144F9A98AF7186B0278685B8E2C08BEA87171B4DEE585C1828295B5395EB4A17779F0203010001';
4522//Private Key
4523
4524this.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';
4525
4526
4527/*
4528 this.certificate =
4529 'MIIBvTCCASYCCQD55fNzc0WF7TANBgkqhkiG9w0BAQUFADAjMQswCQYDVQQGEwJK'+
4530 'UDEUMBIGA1UEChMLMDAtVEVTVC1SU0EwHhcNMTAwNTI4MDIwODUxWhcNMjAwNTI1'+
4531 'MDIwODUxWjAjMQswCQYDVQQGEwJKUDEUMBIGA1UEChMLMDAtVEVTVC1SU0EwgZ8w'+
4532 'DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANGEYXtfgDRlWUSDn3haY4NVVQiKI9Cz'+
4533 'Thoua9+DxJuiseyzmBBe7Roh1RPqdvmtOHmEPbJ+kXZYhbozzPRbFGHCJyBfCLzQ'+
4534 'fVos9/qUQ88u83b0SFA2MGmQWQAlRtLy66EkR4rDRwTj2DzR4EEXgEKpIvo8VBs/'+
4535 '3+sHLF3ESgAhAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAEZ6mXFFq3AzfaqWHmCy1'+
4536 'ARjlauYAa8ZmUFnLm0emg9dkVBJ63aEqARhtok6bDQDzSJxiLpCEF6G4b/Nv/M/M'+
4537 'LyhP+OoOTmETMegAVQMq71choVJyOFE5BtQa6M/lCHEOya5QUfoRF2HF9EjRF44K'+
4538 '3OK+u3ivTSj3zwjtpudY5Xo=';
4539
4540 this.privateKey =
4541 'MIICWwIBAAKBgQDRhGF7X4A0ZVlEg594WmODVVUIiiPQs04aLmvfg8SborHss5gQ'+
4542 'Xu0aIdUT6nb5rTh5hD2yfpF2WIW6M8z0WxRhwicgXwi80H1aLPf6lEPPLvN29EhQ'+
4543 'NjBpkFkAJUbS8uuhJEeKw0cE49g80eBBF4BCqSL6PFQbP9/rByxdxEoAIQIDAQAB'+
4544 'AoGAA9/q3Zk6ib2GFRpKDLO/O2KMnAfR+b4XJ6zMGeoZ7Lbpi3MW0Nawk9ckVaX0'+
4545 'ZVGqxbSIX5Cvp/yjHHpww+QbUFrw/gCjLiiYjM9E8C3uAF5AKJ0r4GBPl4u8K4bp'+
4546 'bXeSxSB60/wPQFiQAJVcA5xhZVzqNuF3EjuKdHsw+dk+dPECQQDubX/lVGFgD/xY'+
4547 'uchz56Yc7VHX+58BUkNSewSzwJRbcueqknXRWwj97SXqpnYfKqZq78dnEF10SWsr'+
4548 '/NMKi+7XAkEA4PVqDv/OZAbWr4syXZNv/Mpl4r5suzYMMUD9U8B2JIRnrhmGZPzL'+
4549 'x23N9J4hEJ+Xh8tSKVc80jOkrvGlSv+BxwJAaTOtjA3YTV+gU7Hdza53sCnSw/8F'+
4550 'YLrgc6NOJtYhX9xqdevbyn1lkU0zPr8mPYg/F84m6MXixm2iuSz8HZoyzwJARi2p'+
4551 'aYZ5/5B2lwroqnKdZBJMGKFpUDn7Mb5hiSgocxnvMkv6NjT66Xsi3iYakJII9q8C'+
4552 'Ma1qZvT/cigmdbAh7wJAQNXyoizuGEltiSaBXx4H29EdXNYWDJ9SS5f070BRbAIl'+
4553 'dqRh3rcNvpY6BKJqFapda1DjdcncZECMizT/GMrc1w==';
4554
4555 */
4556};
4557
4558
4559KeyManager.prototype.verify = function verify(message,signature){
4560
4561 var input = message;
4562
4563 var _PEM_X509CERT_STRING_ = this.certificate;
4564
4565 var x509 = new X509();
4566
4567 x509.readCertPEM(_PEM_X509CERT_STRING_);
4568
4569 var result = x509.subjectPublicKeyRSA.verifyString(input, signature);
4570
4571 return result;
4572};
4573
4574KeyManager.prototype.sign= function sign(message){
4575
4576 var input = message;
4577
4578 var _PEM_PRIVATE_KEY_STRING_ = this.privateKey;
4579
4580 var rsa = new RSAKey();
4581
4582 rsa.readPrivateKeyFromPEMString(_PEM_PRIVATE_KEY_STRING_);
4583
4584 var hSig = rsa.signString(input, "sha256");
4585
4586 return hSig;
4587
4588};
4589
4590
4591
4592var globalKeyManager = new KeyManager();
4593//var KeyPair = { "public" : "PUBLIC KEY" , "private" : "PRIVATE KEY" };
4594
4595
Wentao Shang882e34e2013-01-05 02:49:51 -08004596/**
4597 * @author: Wentao Shang
4598 * See COPYING for copyright and distribution information.
4599 */
4600
4601var MerklePath = function MerkelPath() {
4602 this.index = null; // int
4603 this.digestList = []; // array of hex string
4604};
4605
4606var Witness = function Witness() {
4607 this.oid = null; // string
4608 this.path = new MerklePath(); // MerklePath
4609};
4610
Wentao Shange0d7f052013-01-05 16:37:02 -08004611function parseOID(bytes, start, end) {
4612 var s, n = 0, bits = 0;
4613 for (var i = start; i < end; ++i) {
4614 var v = bytes[i];
4615 n = (n << 7) | (v & 0x7F);
4616 bits += 7;
4617 if (!(v & 0x80)) { // finished
4618 if (s == undefined)
4619 s = parseInt(n / 40) + "." + (n % 40);
4620 else
4621 s += "." + ((bits >= 31) ? "bigint" : n);
4622 n = bits = 0;
4623 }
4624 s += String.fromCharCode();
4625 }
4626 return s;
4627}
4628
4629function parseInteger(bytes, start, end) {
4630 var n = 0;
4631 for (var i = start; i < end; ++i)
4632 n = (n << 8) | bytes[i];
4633 return n;
4634}
4635
Wentao Shang882e34e2013-01-05 02:49:51 -08004636Witness.prototype.decode = function(/* Uint8Array */ witness) {
Wentao Shange0d7f052013-01-05 16:37:02 -08004637 /* The asn1.js decoder has some bug and
4638 * cannot decode certain kind of witness.
4639 * So we use an alternative (and dirty) hack
4640 * to read witness from byte streams
4641 * ------Wentao
4642 */
4643 /*
Wentao Shang882e34e2013-01-05 02:49:51 -08004644 var wit = DataUtils.toHex(witness).toLowerCase();
Wentao Shange0d7f052013-01-05 16:37:02 -08004645 try {
4646 var der = Hex.decode(wit);
4647 var asn1 = ASN1.decode(der);
4648 }
4649 catch (e) {
4650 console.log(e);
4651 console.log(wit);
4652 }
Wentao Shang882e34e2013-01-05 02:49:51 -08004653 //console.log(asn1.toPrettyString());
4654
4655 this.oid = asn1.sub[0].sub[0].content(); // OID
Wentao Shange0d7f052013-01-05 16:37:02 -08004656 //console.log(this.oid);
Wentao Shang882e34e2013-01-05 02:49:51 -08004657 this.path.index = asn1.sub[1].sub[0].sub[0].content(); // index
Wentao Shange0d7f052013-01-05 16:37:02 -08004658 //console.log(this.path.index);
Wentao Shang882e34e2013-01-05 02:49:51 -08004659 for (i = 0; i < asn1.sub[1].sub[0].sub[1].sub.length; i++) {
4660 pos = asn1.sub[1].sub[0].sub[1].sub[i].stream.pos;
4661 str = wit.substring(2 * pos + 4, 2 * pos + 68);
4662 this.path.digestList.push(str); // digest hex string
Wentao Shange0d7f052013-01-05 16:37:02 -08004663 //console.log(str);
4664 }
4665 */
4666
4667 // FIXME: Need to be fixed to support arbitrary ASN1 encoding,
4668 // But do we really nned that???? -------Wentao
4669
4670 // The structure of Witness is fixed as follows:
4671 // SEQUENCE (2 elem)
4672 // SEQUENCE (1 elem)
4673 // OBJECT IDENTIFIER 1.2.840.113550.11.1.2.2
4674 // OCTET STRING (1 elem)
4675 // SEQUENCE (2 elem)
4676 // INTEGER index
4677 // SEQUENCE (n elem)
4678 // OCTET STRING(32 byte) 345FB4B5E9A1D2FF450ECA87EB87601683027A1A...
4679 // OCTET STRING(32 byte) DBCEE5B7A6C2B851B029324197DDBD9A655723DC...
4680 // OCTET STRING(32 byte) 4C79B2D256E4CD657A27F01DCB51AC3C56A24E71...
4681 // OCTET STRING(32 byte) 7F7FB169604A87EAC94378F0BDB4FC5D5899AB88...
4682 // ......
4683 // Hence we can follow this structure to extract witness fields at fixed level
4684 // Tag numbers for ASN1:
4685 // SEQUENCE 0x10
4686 // OCT STRING 0x04
4687 // INTEGER 0x02
4688 // OBJECT IDENTIFIER 0x06
4689 var i = 0;
4690 var step = 0; // count of sequence tag
4691 while (i < witness.length) {
4692 var len = 0;
4693
4694 if (witness[i] == 0x30) {
4695 // Sequence (constructed)
4696 // There is no primitive sequence in Witness
4697 if ((witness[i + 1] & 0x80) != 0) {
4698 len = witness[i+1] & 0x7F;
4699 }
4700 step++;
4701 } else if (witness[i] == 0x06) {
4702 // Decode OID
4703 len = witness[i+1]; // XXX: OID will not be longer than 127 bytes
4704 this.oid = parseOID(witness, i + 2, i + 2 + len);
4705 //console.log(this.oid);
4706 } else if (witness[i] == 0x02) {
4707 // Decode node index
4708 len = witness[i+1]; // XXX: index will not be longer than 127 bytes
4709 this.path.index = parseInteger(witness, i + 2, i + 2 + len);
4710 //console.log(this.path.index);
4711 } else if (witness[i] == 0x04) {
4712 if ((witness[i + 1] & 0x80) != 0) {
4713 len = witness[i+1] & 0x7F;
4714 } else {
4715 len = witness[i+1];
4716 }
4717 if (step == 4) {
4718 // Start to decode digest hex string
4719 str = DataUtils.toHex(witness.subarray(i + 2, i + 2 + len));
4720 this.path.digestList.push(str); // digest hex string
4721 //console.log(str);
4722 }
4723 }
4724 i = i + 2 + len;
Wentao Shang882e34e2013-01-05 02:49:51 -08004725 }
4726};
Wentao Shang0e291c82012-12-02 23:36:29 -08004727/*
4728 * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined
4729 * in FIPS 180-2
4730 * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
4731 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
4732 * Distributed under the BSD License
4733 * See http://pajhome.org.uk/crypt/md5 for details.
4734 * Also http://anmar.eu.org/projects/jssha2/
4735 */
4736
4737/*
4738 * Configurable variables. You may need to tweak these to be compatible with
4739 * the server-side, but the defaults work in most cases.
4740 */
4741var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
4742var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
4743
4744/*
4745 * These are the functions you'll usually want to call
4746 * They take string arguments and return either hex or base-64 encoded strings
4747 */
4748
4749//@author axelcdv
4750/**
4751 * Computes the Sha-256 hash of the given byte array
4752 * @param {byte[]}
4753 * @return the hex string corresponding to the Sha-256 hash of the byte array
4754 */
4755function hex_sha256_from_bytes(byteArray){
4756 return rstr2hex(binb2rstr(binb_sha256( byteArray2binb(byteArray), byteArray.length * 8)));
4757}
4758
4759function hex_sha256(s) { return rstr2hex(rstr_sha256(str2rstr_utf8(s))); }
4760function b64_sha256(s) { return rstr2b64(rstr_sha256(str2rstr_utf8(s))); }
4761function any_sha256(s, e) { return rstr2any(rstr_sha256(str2rstr_utf8(s)), e); }
4762function hex_hmac_sha256(k, d)
4763 { return rstr2hex(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d))); }
4764function b64_hmac_sha256(k, d)
4765 { return rstr2b64(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d))); }
4766function any_hmac_sha256(k, d, e)
4767 { return rstr2any(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
4768
4769
4770/*
4771 function hex_sha256(s) { return rstr2hex(rstr_sha256(s)); }
4772function b64_sha256(s) { return rstr2b64(rstr_sha256(s)); }
4773function any_sha256(s, e) { return rstr2any(rstr_sha256(s), e); }
4774function hex_hmac_sha256(k, d)
4775 { return rstr2hex(rstr_hmac_sha256(str2rstr_utf8(k), d)); }
4776function b64_hmac_sha256(k, d)
4777 { return rstr2b64(rstr_hmac_sha256(str2rstr_utf8(k), d)); }
4778function any_hmac_sha256(k, d, e)
4779 { return rstr2any(rstr_hmac_sha256(str2rstr_utf8(k), d), e); }
4780*/
4781
4782/*
4783 * Perform a simple self-test to see if the VM is working
4784 */
4785function sha256_vm_test()
4786{
4787 return hex_sha256("abc").toLowerCase() ==
4788 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad";
4789}
4790
4791/**
4792 * Calculate the sha256 of a raw string
4793 * @param s: the raw string
4794 */
4795function rstr_sha256(s)
4796{
4797 return binb2rstr(binb_sha256(rstr2binb(s), s.length * 8));
4798}
4799
4800/**
4801 * Calculate the HMAC-sha256 of a key and some data (raw strings)
4802 */
4803function rstr_hmac_sha256(key, data)
4804{
4805 var bkey = rstr2binb(key);
4806 if(bkey.length > 16) bkey = binb_sha256(bkey, key.length * 8);
4807
4808 var ipad = Array(16), opad = Array(16);
4809 for(var i = 0; i < 16; i++)
4810 {
4811 ipad[i] = bkey[i] ^ 0x36363636;
4812 opad[i] = bkey[i] ^ 0x5C5C5C5C;
4813 }
4814
4815 var hash = binb_sha256(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
4816 return binb2rstr(binb_sha256(opad.concat(hash), 512 + 256));
4817}
4818
4819/**
4820 * Convert a raw string to a hex string
4821 */
4822function rstr2hex(input)
4823{
4824 try { hexcase } catch(e) { hexcase=0; }
4825 var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
4826 var output = "";
4827 var x;
4828 for(var i = 0; i < input.length; i++)
4829 {
4830 x = input.charCodeAt(i);
4831 output += hex_tab.charAt((x >>> 4) & 0x0F)
4832 + hex_tab.charAt( x & 0x0F);
4833 }
4834 return output;
4835}
4836
4837/*
4838 * Convert a raw string to a base-64 string
4839 */
4840function rstr2b64(input)
4841{
4842 try { b64pad } catch(e) { b64pad=''; }
4843 var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4844 var output = "";
4845 var len = input.length;
4846 for(var i = 0; i < len; i += 3)
4847 {
4848 var triplet = (input.charCodeAt(i) << 16)
4849 | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
4850 | (i + 2 < len ? input.charCodeAt(i+2) : 0);
4851 for(var j = 0; j < 4; j++)
4852 {
4853 if(i * 8 + j * 6 > input.length * 8) output += b64pad;
4854 else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
4855 }
4856 }
4857 return output;
4858}
4859
4860/*
4861 * Convert a raw string to an arbitrary string encoding
4862 */
4863function rstr2any(input, encoding)
4864{
4865 var divisor = encoding.length;
4866 var remainders = Array();
4867 var i, q, x, quotient;
4868
4869 /* Convert to an array of 16-bit big-endian values, forming the dividend */
4870 var dividend = Array(Math.ceil(input.length / 2));
4871 for(i = 0; i < dividend.length; i++)
4872 {
4873 dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
4874 }
4875
4876 /*
4877 * Repeatedly perform a long division. The binary array forms the dividend,
4878 * the length of the encoding is the divisor. Once computed, the quotient
4879 * forms the dividend for the next step. We stop when the dividend is zero.
4880 * All remainders are stored for later use.
4881 */
4882 while(dividend.length > 0)
4883 {
4884 quotient = Array();
4885 x = 0;
4886 for(i = 0; i < dividend.length; i++)
4887 {
4888 x = (x << 16) + dividend[i];
4889 q = Math.floor(x / divisor);
4890 x -= q * divisor;
4891 if(quotient.length > 0 || q > 0)
4892 quotient[quotient.length] = q;
4893 }
4894 remainders[remainders.length] = x;
4895 dividend = quotient;
4896 }
4897
4898 /* Convert the remainders to the output string */
4899 var output = "";
4900 for(i = remainders.length - 1; i >= 0; i--)
4901 output += encoding.charAt(remainders[i]);
4902
4903 /* Append leading zero equivalents */
4904 var full_length = Math.ceil(input.length * 8 /
4905 (Math.log(encoding.length) / Math.log(2)))
4906 for(i = output.length; i < full_length; i++)
4907 output = encoding[0] + output;
4908
4909 return output;
4910}
4911
4912/*
4913 * Encode a string as utf-8.
4914 * For efficiency, this assumes the input is valid utf-16.
4915 */
4916function str2rstr_utf8(input)
4917{
4918 var output = "";
4919 var i = -1;
4920 var x, y;
4921
4922 while(++i < input.length)
4923 {
4924 /* Decode utf-16 surrogate pairs */
4925 x = input.charCodeAt(i);
4926 y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
4927 if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
4928 {
4929 x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
4930 i++;
4931 }
4932
4933 /* Encode output as utf-8 */
4934 if(x <= 0x7F)
4935 output += String.fromCharCode(x);
4936 else if(x <= 0x7FF)
4937 output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
4938 0x80 | ( x & 0x3F));
4939 else if(x <= 0xFFFF)
4940 output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
4941 0x80 | ((x >>> 6 ) & 0x3F),
4942 0x80 | ( x & 0x3F));
4943 else if(x <= 0x1FFFFF)
4944 output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
4945 0x80 | ((x >>> 12) & 0x3F),
4946 0x80 | ((x >>> 6 ) & 0x3F),
4947 0x80 | ( x & 0x3F));
4948 }
4949 return output;
4950}
4951
4952/*
4953 * Encode a string as utf-16
4954 */
4955function str2rstr_utf16le(input)
4956{
4957 var output = "";
4958 for(var i = 0; i < input.length; i++)
4959 output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
4960 (input.charCodeAt(i) >>> 8) & 0xFF);
4961 return output;
4962}
4963
4964function str2rstr_utf16be(input)
4965{
4966 var output = "";
4967 for(var i = 0; i < input.length; i++)
4968 output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
4969 input.charCodeAt(i) & 0xFF);
4970 return output;
4971}
4972
4973/**
4974 * Convert a raw string to an array of big-endian words
4975 * Characters >255 have their high-byte silently ignored.
4976 */
4977function rstr2binb(input)
4978{
4979 //console.log('Raw string comming is '+input);
4980 var output = Array(input.length >> 2);
Wentao Shangc0311e52012-12-03 10:38:23 -08004981 /* JavaScript automatically zeroizes a new array.
Wentao Shang0e291c82012-12-02 23:36:29 -08004982 for(var i = 0; i < output.length; i++)
4983 output[i] = 0;
Wentao Shangc0311e52012-12-03 10:38:23 -08004984 */
Wentao Shang0e291c82012-12-02 23:36:29 -08004985 for(var i = 0; i < input.length * 8; i += 8)
4986 output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
4987 return output;
4988}
4989
4990/**
4991 * @author axelcdv
4992 * Convert a byte array to an array of big-endian words
4993 * @param {byte[]} input
4994 * @return the array of big-endian words
4995 */
4996function byteArray2binb(input){
4997 //console.log("Byte array coming is " + input);
4998 var output = Array(input.length >> 2);
Wentao Shangc0311e52012-12-03 10:38:23 -08004999 /* JavaScript automatically zeroizes a new array.
Wentao Shang0e291c82012-12-02 23:36:29 -08005000 for(var i = 0; i < output.length; i++)
5001 output[i] = 0;
Wentao Shangc0311e52012-12-03 10:38:23 -08005002 */
Wentao Shang0e291c82012-12-02 23:36:29 -08005003 for(var i = 0; i < input.length * 8; i += 8)
5004 output[i>>5] |= (input[i / 8] & 0xFF) << (24 - i % 32);
5005 return output;
5006}
5007
5008/*
5009 * Convert an array of big-endian words to a string
5010 */
5011function binb2rstr(input)
5012{
5013 var output = "";
5014 for(var i = 0; i < input.length * 32; i += 8)
5015 output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
5016 return output;
5017}
5018
5019/*
5020 * Main sha256 function, with its support functions
5021 */
5022function sha256_S (X, n) {return ( X >>> n ) | (X << (32 - n));}
5023function sha256_R (X, n) {return ( X >>> n );}
5024function sha256_Ch(x, y, z) {return ((x & y) ^ ((~x) & z));}
5025function sha256_Maj(x, y, z) {return ((x & y) ^ (x & z) ^ (y & z));}
5026function sha256_Sigma0256(x) {return (sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22));}
5027function sha256_Sigma1256(x) {return (sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25));}
5028function sha256_Gamma0256(x) {return (sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3));}
5029function sha256_Gamma1256(x) {return (sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10));}
5030function sha256_Sigma0512(x) {return (sha256_S(x, 28) ^ sha256_S(x, 34) ^ sha256_S(x, 39));}
5031function sha256_Sigma1512(x) {return (sha256_S(x, 14) ^ sha256_S(x, 18) ^ sha256_S(x, 41));}
5032function sha256_Gamma0512(x) {return (sha256_S(x, 1) ^ sha256_S(x, 8) ^ sha256_R(x, 7));}
5033function sha256_Gamma1512(x) {return (sha256_S(x, 19) ^ sha256_S(x, 61) ^ sha256_R(x, 6));}
5034
5035var sha256_K = new Array
5036(
5037 1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993,
5038 -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987,
5039 1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522,
5040 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986,
5041 -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585,
5042 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291,
5043 1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885,
5044 -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344,
5045 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218,
5046 1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872,
5047 -1866530822, -1538233109, -1090935817, -965641998
5048);
5049
5050function binb_sha256(m, l)
5051{
5052 var HASH = new Array(1779033703, -1150833019, 1013904242, -1521486534,
5053 1359893119, -1694144372, 528734635, 1541459225);
5054 var W = new Array(64);
Wentao Shang0e291c82012-12-02 23:36:29 -08005055
5056 /* append padding */
5057 m[l >> 5] |= 0x80 << (24 - l % 32);
5058 m[((l + 64 >> 9) << 4) + 15] = l;
Wentao Shangc0311e52012-12-03 10:38:23 -08005059
5060 for(var offset = 0; offset < m.length; offset += 16)
5061 processBlock_sha256(m, offset, HASH, W);
Wentao Shang0e291c82012-12-02 23:36:29 -08005062
Wentao Shangc0311e52012-12-03 10:38:23 -08005063 return HASH;
5064}
5065
5066/*
5067 * Process a block of 16 4-byte words in m starting at offset and update HASH.
5068 * offset must be a multiple of 16 and less than m.length. W is a scratchpad Array(64).
5069 */
5070function processBlock_sha256(m, offset, HASH, W) {
5071 var a, b, c, d, e, f, g, h;
5072 var j, T1, T2;
5073
Wentao Shang0e291c82012-12-02 23:36:29 -08005074 a = HASH[0];
5075 b = HASH[1];
5076 c = HASH[2];
5077 d = HASH[3];
5078 e = HASH[4];
5079 f = HASH[5];
5080 g = HASH[6];
5081 h = HASH[7];
5082
5083 for(j = 0; j < 64; j++)
5084 {
Wentao Shangc0311e52012-12-03 10:38:23 -08005085 if (j < 16) W[j] = m[j + offset];
Wentao Shang0e291c82012-12-02 23:36:29 -08005086 else W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]),
5087 sha256_Gamma0256(W[j - 15])), W[j - 16]);
5088
5089 T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)),
5090 sha256_K[j]), W[j]);
5091 T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
5092 h = g;
5093 g = f;
5094 f = e;
5095 e = safe_add(d, T1);
5096 d = c;
5097 c = b;
5098 b = a;
5099 a = safe_add(T1, T2);
5100 }
5101
5102 HASH[0] = safe_add(a, HASH[0]);
5103 HASH[1] = safe_add(b, HASH[1]);
5104 HASH[2] = safe_add(c, HASH[2]);
5105 HASH[3] = safe_add(d, HASH[3]);
5106 HASH[4] = safe_add(e, HASH[4]);
5107 HASH[5] = safe_add(f, HASH[5]);
5108 HASH[6] = safe_add(g, HASH[6]);
5109 HASH[7] = safe_add(h, HASH[7]);
Wentao Shang0e291c82012-12-02 23:36:29 -08005110}
5111
5112function safe_add (x, y)
5113{
5114 var lsw = (x & 0xFFFF) + (y & 0xFFFF);
5115 var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
5116 return (msw << 16) | (lsw & 0xFFFF);
5117}
Wentao Shangc0311e52012-12-03 10:38:23 -08005118
5119/*
5120 * Create a Sha256, call update(data) multiple times, then call finalize().
5121 */
5122var Sha256 = function Sha256() {
5123 this.W = new Array(64);
5124 this.hash = new Array(1779033703, -1150833019, 1013904242, -1521486534,
5125 1359893119, -1694144372, 528734635, 1541459225);
5126 this.nTotalBytes = 0;
5127 this.buffer = new Uint8Array(16 * 4);
5128 this.nBufferBytes = 0;
5129}
5130
5131/*
5132 * Update the hash with data, which is Uint8Array.
5133 */
5134Sha256.prototype.update = function(data) {
5135 this.nTotalBytes += data.length;
5136
5137 if (this.nBufferBytes > 0) {
5138 // Fill up the buffer and process it first.
5139 var bytesNeeded = this.buffer.length - this.nBufferBytes;
5140 if (data.length < bytesNeeded) {
5141 this.buffer.set(data, this.nBufferBytes);
5142 this.nBufferBytes += data.length;
5143 return;
5144 }
5145 else {
5146 this.buffer.set(data.subarray(0, bytesNeeded), this.nBufferBytes);
5147 processBlock_sha256(byteArray2binb(this.buffer), 0, this.hash, this.W);
5148 this.nBufferBytes = 0;
5149 // Consume the bytes from data.
5150 data = data.subarray(bytesNeeded, data.length);
5151 if (data.length == 0)
5152 return;
5153 }
5154 }
5155
5156 // 2^6 is 16 * 4.
5157 var nBlocks = data.length >> 6;
5158 if (nBlocks > 0) {
5159 var nBytes = nBlocks * 16 * 4;
5160 var m = byteArray2binb(data.subarray(0, nBytes));
5161 for(var offset = 0; offset < m.length; offset += 16)
5162 processBlock_sha256(m, offset, this.hash, this.W);
5163
5164 data = data.subarray(nBytes, data.length);
5165 }
5166
5167 if (data.length > 0) {
5168 // Save the remainder in the buffer.
5169 this.buffer.set(data);
5170 this.nBufferBytes = data.length;
5171 }
5172}
5173
5174/*
5175 * Finalize the hash and return the result as Uint8Array.
5176 * Only call this once. Return values on subsequent calls are undefined.
5177 */
5178Sha256.prototype.finalize = function() {
5179 var m = byteArray2binb(this.buffer.subarray(0, this.nBufferBytes));
5180 /* append padding */
5181 var l = this.nBufferBytes * 8;
5182 m[l >> 5] |= 0x80 << (24 - l % 32);
5183 m[((l + 64 >> 9) << 4) + 15] = this.nTotalBytes * 8;
5184
5185 for(var offset = 0; offset < m.length; offset += 16)
5186 processBlock_sha256(m, offset, this.hash, this.W);
5187
5188 return Sha256.binb2Uint8Array(this.hash);
5189}
5190
5191/*
5192 * Convert an array of big-endian words to Uint8Array.
5193 */
5194Sha256.binb2Uint8Array = function(input)
5195{
5196 var output = new Uint8Array(input.length * 4);
5197 var iOutput = 0;
5198 for (var i = 0; i < input.length * 32; i += 8)
5199 output[iOutput++] = (input[i>>5] >>> (24 - i % 32)) & 0xFF;
5200 return output;
5201}
Wentao Shang0e291c82012-12-02 23:36:29 -08005202var b64map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
5203var b64pad="=";
5204
5205function hex2b64(h) {
5206 var i;
5207 var c;
5208 var ret = "";
5209 for(i = 0; i+3 <= h.length; i+=3) {
5210 c = parseInt(h.substring(i,i+3),16);
5211 ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63);
5212 }
5213 if(i+1 == h.length) {
5214 c = parseInt(h.substring(i,i+1),16);
5215 ret += b64map.charAt(c << 2);
5216 }
5217 else if(i+2 == h.length) {
5218 c = parseInt(h.substring(i,i+2),16);
5219 ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4);
5220 }
5221 while((ret.length & 3) > 0) ret += b64pad;
5222 return ret;
5223}
5224
5225// convert a base64 string to hex
5226function b64tohex(s) {
5227 var ret = ""
5228 var i;
5229 var k = 0; // b64 state, 0-3
5230 var slop;
5231 for(i = 0; i < s.length; ++i) {
5232 if(s.charAt(i) == b64pad) break;
5233 v = b64map.indexOf(s.charAt(i));
5234 if(v < 0) continue;
5235 if(k == 0) {
5236 ret += int2char(v >> 2);
5237 slop = v & 3;
5238 k = 1;
5239 }
5240 else if(k == 1) {
5241 ret += int2char((slop << 2) | (v >> 4));
5242 slop = v & 0xf;
5243 k = 2;
5244 }
5245 else if(k == 2) {
5246 ret += int2char(slop);
5247 ret += int2char(v >> 2);
5248 slop = v & 3;
5249 k = 3;
5250 }
5251 else {
5252 ret += int2char((slop << 2) | (v >> 4));
5253 ret += int2char(v & 0xf);
5254 k = 0;
5255 }
5256 }
5257 if(k == 1)
5258 ret += int2char(slop << 2);
5259 return ret;
5260}
5261
5262// convert a base64 string to a byte/number array
5263function b64toBA(s) {
5264 //piggyback on b64tohex for now, optimize later
5265 var h = b64tohex(s);
5266 var i;
5267 var a = new Array();
5268 for(i = 0; 2*i < h.length; ++i) {
5269 a[i] = parseInt(h.substring(2*i,2*i+2),16);
5270 }
5271 return a;
5272}
5273// Depends on jsbn.js and rng.js
5274
5275// Version 1.1: support utf-8 encoding in pkcs1pad2
5276
5277// convert a (hex) string to a bignum object
5278function parseBigInt(str,r) {
5279 return new BigInteger(str,r);
5280}
5281
5282function linebrk(s,n) {
5283 var ret = "";
5284 var i = 0;
5285 while(i + n < s.length) {
5286 ret += s.substring(i,i+n) + "\n";
5287 i += n;
5288 }
5289 return ret + s.substring(i,s.length);
5290}
5291
5292function byte2Hex(b) {
5293 if(b < 0x10)
5294 return "0" + b.toString(16);
5295 else
5296 return b.toString(16);
5297}
5298
5299/**
5300 * PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint
5301 * @param s: the string to encode
5302 * @param n: the size in byte
5303 */
5304function pkcs1pad2(s,n) {
5305 if(n < s.length + 11) { // TODO: fix for utf-8
5306 alert("Message too long for RSA");
5307 return null;
5308 }
5309 var ba = new Array();
5310 var i = s.length - 1;
5311 while(i >= 0 && n > 0) {
5312 var c = s.charCodeAt(i--);
5313 if(c < 128) { // encode using utf-8
5314 ba[--n] = c;
5315 }
5316 else if((c > 127) && (c < 2048)) {
5317 ba[--n] = (c & 63) | 128;
5318 ba[--n] = (c >> 6) | 192;
5319 }
5320 else {
5321 ba[--n] = (c & 63) | 128;
5322 ba[--n] = ((c >> 6) & 63) | 128;
5323 ba[--n] = (c >> 12) | 224;
5324 }
5325 }
5326 ba[--n] = 0;
5327 var rng = new SecureRandom();
5328 var x = new Array();
5329 while(n > 2) { // random non-zero pad
5330 x[0] = 0;
5331 while(x[0] == 0) rng.nextBytes(x);
5332 ba[--n] = x[0];
5333 }
5334 ba[--n] = 2;
5335 ba[--n] = 0;
5336 return new BigInteger(ba);
5337}
5338
5339/**
5340 * "empty" RSA key constructor
5341 * @returns {RSAKey}
5342 */
5343function RSAKey() {
5344 this.n = null;
5345 this.e = 0;
5346 this.d = null;
5347 this.p = null;
5348 this.q = null;
5349 this.dmp1 = null;
5350 this.dmq1 = null;
5351 this.coeff = null;
5352}
5353
5354/**
5355 * Set the public key fields N and e from hex strings
5356 * @param N
5357 * @param E
5358 * @returns {RSASetPublic}
5359 */
5360function RSASetPublic(N,E) {
5361 if(N != null && E != null && N.length > 0 && E.length > 0) {
5362 this.n = parseBigInt(N,16);
5363 this.e = parseInt(E,16);
5364 }
5365 else
5366 alert("Invalid RSA public key");
5367}
5368
5369/**
5370 * Perform raw public operation on "x": return x^e (mod n)
5371 * @param x
5372 * @returns x^e (mod n)
5373 */
5374function RSADoPublic(x) {
5375 return x.modPowInt(this.e, this.n);
5376}
5377
5378/**
5379 * Return the PKCS#1 RSA encryption of "text" as an even-length hex string
5380 */
5381function RSAEncrypt(text) {
5382 var m = pkcs1pad2(text,(this.n.bitLength()+7)>>3);
5383 if(m == null) return null;
5384 var c = this.doPublic(m);
5385 if(c == null) return null;
5386 var h = c.toString(16);
5387 if((h.length & 1) == 0) return h; else return "0" + h;
5388}
5389
5390// Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string
5391//function RSAEncryptB64(text) {
5392// var h = this.encrypt(text);
5393// if(h) return hex2b64(h); else return null;
5394//}
5395
5396// protected
5397RSAKey.prototype.doPublic = RSADoPublic;
5398
5399// public
5400RSAKey.prototype.setPublic = RSASetPublic;
5401RSAKey.prototype.encrypt = RSAEncrypt;
5402//RSAKey.prototype.encrypt_b64 = RSAEncryptB64;
5403// Depends on rsa.js and jsbn2.js
5404
5405// Version 1.1: support utf-8 decoding in pkcs1unpad2
5406
5407// Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext
5408function pkcs1unpad2(d,n) {
5409 var b = d.toByteArray();
5410 var i = 0;
5411 while(i < b.length && b[i] == 0) ++i;
5412 if(b.length-i != n-1 || b[i] != 2)
5413 return null;
5414 ++i;
5415 while(b[i] != 0)
5416 if(++i >= b.length) return null;
5417 var ret = "";
5418 while(++i < b.length) {
5419 var c = b[i] & 255;
5420 if(c < 128) { // utf-8 decode
5421 ret += String.fromCharCode(c);
5422 }
5423 else if((c > 191) && (c < 224)) {
5424 ret += String.fromCharCode(((c & 31) << 6) | (b[i+1] & 63));
5425 ++i;
5426 }
5427 else {
5428 ret += String.fromCharCode(((c & 15) << 12) | ((b[i+1] & 63) << 6) | (b[i+2] & 63));
5429 i += 2;
5430 }
5431 }
5432 return ret;
5433}
5434
5435// Set the private key fields N, e, and d from hex strings
5436function RSASetPrivate(N,E,D) {
5437 if(N != null && E != null && N.length > 0 && E.length > 0) {
5438 this.n = parseBigInt(N,16);
5439 this.e = parseInt(E,16);
5440 this.d = parseBigInt(D,16);
5441 }
5442 else
5443 alert("Invalid RSA private key");
5444}
5445
5446// Set the private key fields N, e, d and CRT params from hex strings
5447function RSASetPrivateEx(N,E,D,P,Q,DP,DQ,C) {
5448 if(N != null && E != null && N.length > 0 && E.length > 0) {
5449 this.n = parseBigInt(N,16);
5450 this.e = parseInt(E,16);
5451 this.d = parseBigInt(D,16);
5452 this.p = parseBigInt(P,16);
5453 this.q = parseBigInt(Q,16);
5454 this.dmp1 = parseBigInt(DP,16);
5455 this.dmq1 = parseBigInt(DQ,16);
5456 this.coeff = parseBigInt(C,16);
5457 }
5458 else
5459 alert("Invalid RSA private key");
5460}
5461
5462/**
5463 * Generate a new random private key B bits long, using public expt E
5464 */
5465function RSAGenerate(B,E) {
5466 var rng = new SecureRandom();
5467 var qs = B>>1;
5468 this.e = parseInt(E,16);
5469 var ee = new BigInteger(E,16);
5470 for(;;) {
5471 for(;;) {
5472 this.p = new BigInteger(B-qs,1,rng);
5473 if(this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.p.isProbablePrime(10)) break;
5474 }
5475 for(;;) {
5476 this.q = new BigInteger(qs,1,rng);
5477 if(this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.q.isProbablePrime(10)) break;
5478 }
5479 if(this.p.compareTo(this.q) <= 0) {
5480 var t = this.p;
5481 this.p = this.q;
5482 this.q = t;
5483 }
5484 var p1 = this.p.subtract(BigInteger.ONE); // p1 = p - 1
5485 var q1 = this.q.subtract(BigInteger.ONE); // q1 = q - 1
5486 var phi = p1.multiply(q1);
5487 if(phi.gcd(ee).compareTo(BigInteger.ONE) == 0) {
5488 this.n = this.p.multiply(this.q); // this.n = p * q
5489 this.d = ee.modInverse(phi); // this.d =
5490 this.dmp1 = this.d.mod(p1); // this.dmp1 = d mod (p - 1)
5491 this.dmq1 = this.d.mod(q1); // this.dmq1 = d mod (q - 1)
5492 this.coeff = this.q.modInverse(this.p); // this.coeff = (q ^ -1) mod p
5493 break;
5494 }
5495 }
5496}
5497
5498/**
5499 * Perform raw private operation on "x": return x^d (mod n)
5500 * @return x^d (mod n)
5501 */
5502function RSADoPrivate(x) {
5503 if(this.p == null || this.q == null)
5504 return x.modPow(this.d, this.n);
5505
5506 // TODO: re-calculate any missing CRT params
5507 var xp = x.mod(this.p).modPow(this.dmp1, this.p); // xp=cp?
5508 var xq = x.mod(this.q).modPow(this.dmq1, this.q); // xq=cq?
5509
5510 while(xp.compareTo(xq) < 0)
5511 xp = xp.add(this.p);
5512 // NOTE:
5513 // xp.subtract(xq) => cp -cq
5514 // xp.subtract(xq).multiply(this.coeff).mod(this.p) => (cp - cq) * u mod p = h
5515 // xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq) => cq + (h * q) = M
5516 return xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq);
5517}
5518
5519// Return the PKCS#1 RSA decryption of "ctext".
5520// "ctext" is an even-length hex string and the output is a plain string.
5521function RSADecrypt(ctext) {
5522 var c = parseBigInt(ctext, 16);
5523 var m = this.doPrivate(c);
5524 if(m == null) return null;
5525 return pkcs1unpad2(m, (this.n.bitLength()+7)>>3);
5526}
5527
5528// Return the PKCS#1 RSA decryption of "ctext".
5529// "ctext" is a Base64-encoded string and the output is a plain string.
5530//function RSAB64Decrypt(ctext) {
5531// var h = b64tohex(ctext);
5532// if(h) return this.decrypt(h); else return null;
5533//}
5534
5535// protected
5536RSAKey.prototype.doPrivate = RSADoPrivate;
5537
5538// public
5539RSAKey.prototype.setPrivate = RSASetPrivate;
5540RSAKey.prototype.setPrivateEx = RSASetPrivateEx;
5541RSAKey.prototype.generate = RSAGenerate;
5542RSAKey.prototype.decrypt = RSADecrypt;
5543//RSAKey.prototype.b64_decrypt = RSAB64Decrypt;
5544/*! rsapem-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
5545 */
5546//
5547// rsa-pem.js - adding function for reading/writing PKCS#1 PEM private key
5548// to RSAKey class.
5549//
5550// version: 1.1 (2012-May-10)
5551//
5552// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
5553//
5554// This software is licensed under the terms of the MIT License.
5555// http://kjur.github.com/jsrsasign/license/
5556//
5557// The above copyright and license notice shall be
5558// included in all copies or substantial portions of the Software.
5559//
5560//
5561// Depends on:
5562//
5563//
5564//
5565// _RSApem_pemToBase64(sPEM)
5566//
5567// removing PEM header, PEM footer and space characters including
5568// new lines from PEM formatted RSA private key string.
5569//
5570
5571function _rsapem_pemToBase64(sPEMPrivateKey) {
5572 var s = sPEMPrivateKey;
5573 s = s.replace("-----BEGIN RSA PRIVATE KEY-----", "");
5574 s = s.replace("-----END RSA PRIVATE KEY-----", "");
5575 s = s.replace(/[ \n]+/g, "");
5576 return s;
5577}
5578
5579function _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey) {
5580 var a = new Array();
5581 var v1 = ASN1HEX.getStartPosOfV_AtObj(hPrivateKey, 0);
5582 var n1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, v1);
5583 var e1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, n1);
5584 var d1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, e1);
5585 var p1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, d1);
5586 var q1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, p1);
5587 var dp1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, q1);
5588 var dq1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dp1);
5589 var co1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dq1);
5590 a.push(v1, n1, e1, d1, p1, q1, dp1, dq1, co1);
5591 return a;
5592}
5593
5594function _rsapem_getHexValueArrayOfChildrenFromHex(hPrivateKey) {
5595 var posArray = _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey);
5596 var v = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[0]);
5597 var n = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[1]);
5598 var e = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[2]);
5599 var d = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[3]);
5600 var p = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[4]);
5601 var q = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[5]);
5602 var dp = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[6]);
5603 var dq = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[7]);
5604 var co = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[8]);
5605 var a = new Array();
5606 a.push(v, n, e, d, p, q, dp, dq, co);
5607 return a;
5608}
5609
5610/**
5611 * read PKCS#1 private key from a string
5612 * @name readPrivateKeyFromPEMString
5613 * @memberOf RSAKey#
5614 * @function
5615 * @param {String} keyPEM string of PKCS#1 private key.
5616 */
5617function _rsapem_readPrivateKeyFromPEMString(keyPEM) {
5618 var keyB64 = _rsapem_pemToBase64(keyPEM);
5619 var keyHex = b64tohex(keyB64) // depends base64.js
5620 var a = _rsapem_getHexValueArrayOfChildrenFromHex(keyHex);
5621 this.setPrivateEx(a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]);
5622}
5623
5624RSAKey.prototype.readPrivateKeyFromPEMString = _rsapem_readPrivateKeyFromPEMString;
5625/*! rsasign-1.2.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
5626 */
5627//
5628// rsa-sign.js - adding signing functions to RSAKey class.
5629//
5630//
5631// version: 1.2.1 (08 May 2012)
5632//
5633// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
5634//
5635// This software is licensed under the terms of the MIT License.
5636// http://kjur.github.com/jsrsasign/license/
5637//
5638// The above copyright and license notice shall be
5639// included in all copies or substantial portions of the Software.
5640
5641//
5642// Depends on:
5643// function sha1.hex(s) of sha1.js
5644// jsbn.js
5645// jsbn2.js
5646// rsa.js
5647// rsa2.js
5648//
5649
5650// keysize / pmstrlen
5651// 512 / 128
5652// 1024 / 256
5653// 2048 / 512
5654// 4096 / 1024
5655
5656/**
5657 * @property {Dictionary} _RSASIGN_DIHEAD
5658 * @description Array of head part of hexadecimal DigestInfo value for hash algorithms.
5659 * You can add any DigestInfo hash algorith for signing.
5660 * See PKCS#1 v2.1 spec (p38).
5661 */
5662var _RSASIGN_DIHEAD = [];
5663_RSASIGN_DIHEAD['sha1'] = "3021300906052b0e03021a05000414";
5664_RSASIGN_DIHEAD['sha256'] = "3031300d060960864801650304020105000420";
5665_RSASIGN_DIHEAD['sha384'] = "3041300d060960864801650304020205000430";
5666_RSASIGN_DIHEAD['sha512'] = "3051300d060960864801650304020305000440";
5667_RSASIGN_DIHEAD['md2'] = "3020300c06082a864886f70d020205000410";
5668_RSASIGN_DIHEAD['md5'] = "3020300c06082a864886f70d020505000410";
5669_RSASIGN_DIHEAD['ripemd160'] = "3021300906052b2403020105000414";
5670
5671/**
5672 * @property {Dictionary} _RSASIGN_HASHHEXFUNC
5673 * @description Array of functions which calculate hash and returns it as hexadecimal.
5674 * You can add any hash algorithm implementations.
5675 */
5676var _RSASIGN_HASHHEXFUNC = [];
5677_RSASIGN_HASHHEXFUNC['sha1'] = function(s){return hex_sha1(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
5678_RSASIGN_HASHHEXFUNC['sha256'] = function(s){return hex_sha256(s);} // http://pajhome.org.uk/crypt/md5/md5.html
5679_RSASIGN_HASHHEXFUNC['sha512'] = function(s){return hex_sha512(s);} // http://pajhome.org.uk/crypt/md5/md5.html
5680_RSASIGN_HASHHEXFUNC['md5'] = function(s){return hex_md5(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
5681_RSASIGN_HASHHEXFUNC['ripemd160'] = function(s){return hex_rmd160(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
5682
5683//@author axelcdv
5684var _RSASIGN_HASHBYTEFUNC = [];
5685_RSASIGN_HASHBYTEFUNC['sha256'] = function(byteArray){return hex_sha256_from_bytes(byteArray);};
5686
5687//_RSASIGN_HASHHEXFUNC['sha1'] = function(s){return sha1.hex(s);} // http://user1.matsumoto.ne.jp/~goma/js/hash.html
5688//_RSASIGN_HASHHEXFUNC['sha256'] = function(s){return sha256.hex;} // http://user1.matsumoto.ne.jp/~goma/js/hash.html
5689
5690var _RE_HEXDECONLY = new RegExp("");
5691_RE_HEXDECONLY.compile("[^0-9a-f]", "gi");
5692
5693// ========================================================================
5694// Signature Generation
5695// ========================================================================
5696
5697function _rsasign_getHexPaddedDigestInfoForString(s, keySize, hashAlg) {
5698 var pmStrLen = keySize / 4;
5699 var hashFunc = _RSASIGN_HASHHEXFUNC[hashAlg];
5700 var sHashHex = hashFunc(s);
5701
5702 var sHead = "0001";
5703 var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex;
5704 var sMid = "";
5705 var fLen = pmStrLen - sHead.length - sTail.length;
5706 for (var i = 0; i < fLen; i += 2) {
5707 sMid += "ff";
5708 }
5709 sPaddedMessageHex = sHead + sMid + sTail;
5710 return sPaddedMessageHex;
5711}
5712
5713
5714//@author: Meki Cheraoui
5715function _rsasign_getHexPaddedDigestInfoForStringHEX(s, keySize, hashAlg) {
5716 var pmStrLen = keySize / 4;
5717 var hashFunc = _RSASIGN_HASHHEXFUNC[hashAlg];
5718 var sHashHex = hashFunc(s);
5719
5720 var sHead = "0001";
5721 var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex;
5722 var sMid = "";
5723 var fLen = pmStrLen - sHead.length - sTail.length;
5724 for (var i = 0; i < fLen; i += 2) {
5725 sMid += "ff";
5726 }
5727 sPaddedMessageHex = sHead + sMid + sTail;
5728 return sPaddedMessageHex;
5729}
5730
5731/**
5732 * Apply padding, then computes the hash of the given byte array, according to the key size and with the hash algorithm
5733 * @param byteArray (byte[])
5734 * @param keySize (int)
5735 * @param hashAlg the hash algorithm to apply (string)
5736 * @return the hash of byteArray
5737 */
5738function _rsasign_getHexPaddedDigestInfoForByteArray(byteArray, keySize, hashAlg){
5739 var pmStrLen = keySize / 4;
5740 var hashFunc = _RSASIGN_HASHBYTEFUNC[hashAlg];
5741 var sHashHex = hashFunc(byteArray); //returns hex hash
5742
5743 var sHead = "0001";
5744 var sTail = "00" + _RSASIGN_DIHEAD[hashAlg] + sHashHex;
5745 var sMid = "";
5746 var fLen = pmStrLen - sHead.length - sTail.length;
5747 for (var i = 0; i < fLen; i += 2) {
5748 sMid += "ff";
5749 }
5750 sPaddedMessageHex = sHead + sMid + sTail;
5751 return sPaddedMessageHex;
5752}
5753
5754function _zeroPaddingOfSignature(hex, bitLength) {
5755 var s = "";
5756 var nZero = bitLength / 4 - hex.length;
5757 for (var i = 0; i < nZero; i++) {
5758 s = s + "0";
5759 }
5760 return s + hex;
5761}
5762
5763/**
5764 * sign for a message string with RSA private key.<br/>
5765 * @name signString
5766 * @memberOf RSAKey#
5767 * @function
5768 * @param {String} s message string to be signed.
5769 * @param {String} hashAlg hash algorithm name for signing.<br/>
5770 * @return returns hexadecimal string of signature value.
5771 */
5772function _rsasign_signString(s, hashAlg) {
5773 //alert("this.n.bitLength() = " + this.n.bitLength());
5774 var hPM = _rsasign_getHexPaddedDigestInfoForString(s, this.n.bitLength(), hashAlg);
5775 var biPaddedMessage = parseBigInt(hPM, 16);
5776 var biSign = this.doPrivate(biPaddedMessage);
5777 var hexSign = biSign.toString(16);
5778 return _zeroPaddingOfSignature(hexSign, this.n.bitLength());
5779}
5780
5781//@author: ucla-cs
5782function _rsasign_signStringHEX(s, hashAlg) {
5783 //alert("this.n.bitLength() = " + this.n.bitLength());
5784 var hPM = _rsasign_getHexPaddedDigestInfoForString(s, this.n.bitLength(), hashAlg);
5785 var biPaddedMessage = parseBigInt(hPM, 16);
5786 var biSign = this.doPrivate(biPaddedMessage);
5787 var hexSign = biSign.toString(16);
5788 return _zeroPaddingOfSignature(hexSign, this.n.bitLength());
5789}
5790
5791
5792/**
5793 * Sign a message byteArray with an RSA private key
5794 * @name signByteArray
5795 * @memberOf RSAKey#
5796 * @function
5797 * @param {byte[]} byteArray
5798 * @param {Sring} hashAlg the hash algorithm to apply
5799 * @param {RSAKey} rsa key to sign with: hack because the context is lost here
5800 * @return hexadecimal string of signature value
5801 */
5802function _rsasign_signByteArray(byteArray, hashAlg, rsaKey) {
5803 var hPM = _rsasign_getHexPaddedDigestInfoForByteArray(byteArray, rsaKey.n.bitLength(), hashAlg); ///hack because the context is lost here
5804 var biPaddedMessage = parseBigInt(hPM, 16);
5805 var biSign = rsaKey.doPrivate(biPaddedMessage); //hack because the context is lost here
5806 var hexSign = biSign.toString(16);
5807 return _zeroPaddingOfSignature(hexSign, rsaKey.n.bitLength()); //hack because the context is lost here
5808}
5809
5810/**
5811 * Sign a byte array with the Sha-256 algorithm
5812 * @param {byte[]} byteArray
5813 * @return hexadecimal string of signature value
5814 */
5815function _rsasign_signByteArrayWithSHA256(byteArray){
5816 return _rsasign_signByteArray(byteArray, 'sha256', this); //Hack because the context is lost in the next function
5817}
5818
5819
5820function _rsasign_signStringWithSHA1(s) {
5821 return _rsasign_signString(s, 'sha1');
5822}
5823
5824function _rsasign_signStringWithSHA256(s) {
5825 return _rsasign_signString(s, 'sha256');
5826}
5827
5828// ========================================================================
5829// Signature Verification
5830// ========================================================================
5831
5832function _rsasign_getDecryptSignatureBI(biSig, hN, hE) {
5833 var rsa = new RSAKey();
5834 rsa.setPublic(hN, hE);
5835 var biDecryptedSig = rsa.doPublic(biSig);
5836 return biDecryptedSig;
5837}
5838
5839function _rsasign_getHexDigestInfoFromSig(biSig, hN, hE) {
5840 var biDecryptedSig = _rsasign_getDecryptSignatureBI(biSig, hN, hE);
5841 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
5842 return hDigestInfo;
5843}
5844
5845function _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo) {
5846 for (var algName in _RSASIGN_DIHEAD) {
5847 var head = _RSASIGN_DIHEAD[algName];
5848 var len = head.length;
5849 if (hDigestInfo.substring(0, len) == head) {
5850 var a = [algName, hDigestInfo.substring(len)];
5851 return a;
5852 }
5853 }
5854 return [];
5855}
5856
5857function _rsasign_verifySignatureWithArgs(sMsg, biSig, hN, hE) {
5858 var hDigestInfo = _rsasign_getHexDigestInfoFromSig(biSig, hN, hE);
5859 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
5860 if (digestInfoAry.length == 0) return false;
5861 var algName = digestInfoAry[0];
5862 var diHashValue = digestInfoAry[1];
5863 var ff = _RSASIGN_HASHHEXFUNC[algName];
5864 var msgHashValue = ff(sMsg);
5865 return (diHashValue == msgHashValue);
5866}
5867
5868function _rsasign_verifyHexSignatureForMessage(hSig, sMsg) {
5869 var biSig = parseBigInt(hSig, 16);
5870 var result = _rsasign_verifySignatureWithArgs(sMsg, biSig,
5871 this.n.toString(16),
5872 this.e.toString(16));
5873 return result;
5874}
5875
5876/**
5877 * verifies a sigature for a message string with RSA public key.<br/>
5878 * @name verifyString
5879 * @memberOf RSAKey#
5880 * @function
5881 * @param {String} sMsg message string to be verified.
5882 * @param {String} hSig hexadecimal string of siganture.<br/>
5883 * non-hexadecimal charactors including new lines will be ignored.
5884 * @return returns 1 if valid, otherwise 0
5885 */
5886function _rsasign_verifyString(sMsg, hSig) {
5887 hSig = hSig.replace(_RE_HEXDECONLY, '');
5888
5889 if(LOG>3)console.log('n is '+this.n);
5890 if(LOG>3)console.log('e is '+this.e);
5891
5892 if (hSig.length != this.n.bitLength() / 4) return 0;
5893 hSig = hSig.replace(/[ \n]+/g, "");
5894 var biSig = parseBigInt(hSig, 16);
5895 var biDecryptedSig = this.doPublic(biSig);
5896 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
5897 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
5898
5899 if (digestInfoAry.length == 0) return false;
5900 var algName = digestInfoAry[0];
5901 var diHashValue = digestInfoAry[1];
5902 var ff = _RSASIGN_HASHHEXFUNC[algName];
5903 var msgHashValue = ff(sMsg);
5904 return (diHashValue == msgHashValue);
5905}
5906
5907/**
5908 * verifies a sigature for a message byte array with RSA public key.<br/>
5909 * @name verifyByteArray
5910 * @memberOf RSAKey#
5911 * @function
5912 * @param {byte[]} byteArray message byte array to be verified.
5913 * @param {String} hSig hexadecimal string of signature.<br/>
5914 * non-hexadecimal charactors including new lines will be ignored.
5915 * @return returns 1 if valid, otherwise 0
5916 */
Wentao Shang882e34e2013-01-05 02:49:51 -08005917function _rsasign_verifyByteArray(byteArray, witness, hSig) {
Wentao Shang0e291c82012-12-02 23:36:29 -08005918 hSig = hSig.replace(_RE_HEXDECONLY, '');
5919
5920 if(LOG>3)console.log('n is '+this.n);
5921 if(LOG>3)console.log('e is '+this.e);
5922
5923 if (hSig.length != this.n.bitLength() / 4) return 0;
5924 hSig = hSig.replace(/[ \n]+/g, "");
5925 var biSig = parseBigInt(hSig, 16);
5926 var biDecryptedSig = this.doPublic(biSig);
5927 var hDigestInfo = biDecryptedSig.toString(16).replace(/^1f+00/, '');
5928 var digestInfoAry = _rsasign_getAlgNameAndHashFromHexDisgestInfo(hDigestInfo);
5929
5930 if (digestInfoAry.length == 0) return false;
5931 var algName = digestInfoAry[0];
5932 var diHashValue = digestInfoAry[1];
Wentao Shang882e34e2013-01-05 02:49:51 -08005933 var msgHashValue = null;
5934
5935 if (witness == null) {
5936 var ff = _RSASIGN_HASHBYTEFUNC[algName];
5937 msgHashValue = ff(byteArray);
5938 } else {
5939 // Compute merkle hash
5940 h = hex_sha256_from_bytes(byteArray);
5941 index = witness.path.index;
5942 for (i = witness.path.digestList.length - 1; i >= 0; i--) {
5943 var str = "";
5944 if (index % 2 == 0) {
5945 str = h + witness.path.digestList[i];
5946 } else {
5947 str = witness.path.digestList[i] + h;
5948 }
5949 h = hex_sha256_from_bytes(DataUtils.toNumbers(str));
5950 index = Math.floor(index / 2);
5951 }
5952 msgHashValue = hex_sha256_from_bytes(DataUtils.toNumbers(h));
5953 }
5954 //console.log(diHashValue);
5955 //console.log(msgHashValue);
Wentao Shang0e291c82012-12-02 23:36:29 -08005956 return (diHashValue == msgHashValue);
5957}
5958
Wentao Shang882e34e2013-01-05 02:49:51 -08005959
Wentao Shang0e291c82012-12-02 23:36:29 -08005960RSAKey.prototype.signString = _rsasign_signString;
5961
5962RSAKey.prototype.signByteArray = _rsasign_signByteArray; //@author axelcdv
5963RSAKey.prototype.signByteArrayWithSHA256 = _rsasign_signByteArrayWithSHA256; //@author axelcdv
5964
5965RSAKey.prototype.signStringWithSHA1 = _rsasign_signStringWithSHA1;
5966RSAKey.prototype.signStringWithSHA256 = _rsasign_signStringWithSHA256;
5967RSAKey.prototype.sign = _rsasign_signString;
5968RSAKey.prototype.signWithSHA1 = _rsasign_signStringWithSHA1;
5969RSAKey.prototype.signWithSHA256 = _rsasign_signStringWithSHA256;
5970
5971
5972/*RSAKey.prototype.signStringHEX = _rsasign_signStringHEX;
5973RSAKey.prototype.signStringWithSHA1HEX = _rsasign_signStringWithSHA1HEX;
5974RSAKey.prototype.signStringWithSHA256HEX = _rsasign_signStringWithSHA256HEX;
5975RSAKey.prototype.signHEX = _rsasign_signStringHEX;
5976RSAKey.prototype.signWithSHA1HEX = _rsasign_signStringWithSHA1HEX;
5977RSAKey.prototype.signWithSHA256HEX = _rsasign_signStringWithSHA256HEX;
5978*/
5979
5980RSAKey.prototype.verifyByteArray = _rsasign_verifyByteArray;
5981RSAKey.prototype.verifyString = _rsasign_verifyString;
5982RSAKey.prototype.verifyHexSignatureForMessage = _rsasign_verifyHexSignatureForMessage;
5983RSAKey.prototype.verify = _rsasign_verifyString;
5984RSAKey.prototype.verifyHexSignatureForByteArrayMessage = _rsasign_verifyHexSignatureForMessage;
5985
5986/*
5987RSAKey.prototype.verifyStringHEX = _rsasign_verifyStringHEX;
5988RSAKey.prototype.verifyHexSignatureForMessageHEX = _rsasign_verifyHexSignatureForMessageHEX;
5989RSAKey.prototype.verifyHEX = _rsasign_verifyStringHEX;
5990RSAKey.prototype.verifyHexSignatureForByteArrayMessageHEX = _rsasign_verifyHexSignatureForMessageHEX;
5991*/
5992
5993
5994/**
5995 * @name RSAKey
5996 * @class
5997 * @description Tom Wu's RSA Key class and extension
5998 */
5999/*! asn1hex-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
6000 */
6001//
6002// asn1hex.js - Hexadecimal represented ASN.1 string library
6003//
6004// version: 1.1 (09-May-2012)
6005//
6006// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
6007//
6008// This software is licensed under the terms of the MIT License.
6009// http://kjur.github.com/jsrsasign/license/
6010//
6011// The above copyright and license notice shall be
6012// included in all copies or substantial portions of the Software.
6013//
6014// Depends on:
6015//
6016
6017// MEMO:
6018// f('3082025b02...', 2) ... 82025b ... 3bytes
6019// f('020100', 2) ... 01 ... 1byte
6020// f('0203001...', 2) ... 03 ... 1byte
6021// f('02818003...', 2) ... 8180 ... 2bytes
6022// f('3080....0000', 2) ... 80 ... -1
6023//
6024// Requirements:
6025// - ASN.1 type octet length MUST be 1.
6026// (i.e. ASN.1 primitives like SET, SEQUENCE, INTEGER, OCTETSTRING ...)
6027// -
6028/**
6029 * get byte length for ASN.1 L(length) bytes
6030 * @name getByteLengthOfL_AtObj
6031 * @memberOf ASN1HEX
6032 * @function
6033 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6034 * @param {Number} pos string index
6035 * @return byte length for ASN.1 L(length) bytes
6036 */
6037function _asnhex_getByteLengthOfL_AtObj(s, pos) {
6038 if (s.substring(pos + 2, pos + 3) != '8') return 1;
6039 var i = parseInt(s.substring(pos + 3, pos + 4));
6040 if (i == 0) return -1; // length octet '80' indefinite length
6041 if (0 < i && i < 10) return i + 1; // including '8?' octet;
6042 return -2; // malformed format
6043}
6044
6045
6046/**
6047 * get hexadecimal string for ASN.1 L(length) bytes
6048 * @name getHexOfL_AtObj
6049 * @memberOf ASN1HEX
6050 * @function
6051 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6052 * @param {Number} pos string index
6053 * @return {String} hexadecimal string for ASN.1 L(length) bytes
6054 */
6055function _asnhex_getHexOfL_AtObj(s, pos) {
6056 var len = _asnhex_getByteLengthOfL_AtObj(s, pos);
6057 if (len < 1) return '';
6058 return s.substring(pos + 2, pos + 2 + len * 2);
6059}
6060
6061//
6062// getting ASN.1 length value at the position 'idx' of
6063// hexa decimal string 's'.
6064//
6065// f('3082025b02...', 0) ... 82025b ... ???
6066// f('020100', 0) ... 01 ... 1
6067// f('0203001...', 0) ... 03 ... 3
6068// f('02818003...', 0) ... 8180 ... 128
6069/**
6070 * get integer value of ASN.1 length for ASN.1 data
6071 * @name getIntOfL_AtObj
6072 * @memberOf ASN1HEX
6073 * @function
6074 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6075 * @param {Number} pos string index
6076 * @return ASN.1 L(length) integer value
6077 */
6078function _asnhex_getIntOfL_AtObj(s, pos) {
6079 var hLength = _asnhex_getHexOfL_AtObj(s, pos);
6080 if (hLength == '') return -1;
6081 var bi;
6082 if (parseInt(hLength.substring(0, 1)) < 8) {
6083 bi = parseBigInt(hLength, 16);
6084 } else {
6085 bi = parseBigInt(hLength.substring(2), 16);
6086 }
6087 return bi.intValue();
6088}
6089
6090/**
6091 * get ASN.1 value starting string position for ASN.1 object refered by index 'idx'.
6092 * @name getStartPosOfV_AtObj
6093 * @memberOf ASN1HEX
6094 * @function
6095 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6096 * @param {Number} pos string index
6097 */
6098function _asnhex_getStartPosOfV_AtObj(s, pos) {
6099 var l_len = _asnhex_getByteLengthOfL_AtObj(s, pos);
6100 if (l_len < 0) return l_len;
6101 return pos + (l_len + 1) * 2;
6102}
6103
6104/**
6105 * get hexadecimal string of ASN.1 V(value)
6106 * @name getHexOfV_AtObj
6107 * @memberOf ASN1HEX
6108 * @function
6109 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6110 * @param {Number} pos string index
6111 * @return {String} hexadecimal string of ASN.1 value.
6112 */
6113function _asnhex_getHexOfV_AtObj(s, pos) {
6114 var pos1 = _asnhex_getStartPosOfV_AtObj(s, pos);
6115 var len = _asnhex_getIntOfL_AtObj(s, pos);
6116 return s.substring(pos1, pos1 + len * 2);
6117}
6118
6119/**
6120 * get hexadecimal string of ASN.1 TLV at
6121 * @name getHexOfTLV_AtObj
6122 * @memberOf ASN1HEX
6123 * @function
6124 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6125 * @param {Number} pos string index
6126 * @return {String} hexadecimal string of ASN.1 TLV.
6127 * @since 1.1
6128 */
6129function _asnhex_getHexOfTLV_AtObj(s, pos) {
6130 var hT = s.substr(pos, 2);
6131 var hL = _asnhex_getHexOfL_AtObj(s, pos);
6132 var hV = _asnhex_getHexOfV_AtObj(s, pos);
6133 return hT + hL + hV;
6134}
6135
6136/**
6137 * get next sibling starting index for ASN.1 object string
6138 * @name getPosOfNextSibling_AtObj
6139 * @memberOf ASN1HEX
6140 * @function
6141 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6142 * @param {Number} pos string index
6143 * @return next sibling starting index for ASN.1 object string
6144 */
6145function _asnhex_getPosOfNextSibling_AtObj(s, pos) {
6146 var pos1 = _asnhex_getStartPosOfV_AtObj(s, pos);
6147 var len = _asnhex_getIntOfL_AtObj(s, pos);
6148 return pos1 + len * 2;
6149}
6150
6151/**
6152 * get array of indexes of child ASN.1 objects
6153 * @name getPosArrayOfChildren_AtObj
6154 * @memberOf ASN1HEX
6155 * @function
6156 * @param {String} s hexadecimal string of ASN.1 DER encoded data
6157 * @param {Number} start string index of ASN.1 object
6158 * @return {Array of Number} array of indexes for childen of ASN.1 objects
6159 */
6160function _asnhex_getPosArrayOfChildren_AtObj(h, pos) {
6161 var a = new Array();
6162 var p0 = _asnhex_getStartPosOfV_AtObj(h, pos);
6163 a.push(p0);
6164
6165 var len = _asnhex_getIntOfL_AtObj(h, pos);
6166 var p = p0;
6167 var k = 0;
6168 while (1) {
6169 var pNext = _asnhex_getPosOfNextSibling_AtObj(h, p);
6170 if (pNext == null || (pNext - p0 >= (len * 2))) break;
6171 if (k >= 200) break;
6172
6173 a.push(pNext);
6174 p = pNext;
6175
6176 k++;
6177 }
6178
6179 return a;
6180}
6181
6182/**
6183 * get string index of nth child object of ASN.1 object refered by h, idx
6184 * @name getNthChildIndex_AtObj
6185 * @memberOf ASN1HEX
6186 * @function
6187 * @param {String} h hexadecimal string of ASN.1 DER encoded data
6188 * @param {Number} idx start string index of ASN.1 object
6189 * @param {Number} nth for child
6190 * @return {Number} string index of nth child.
6191 * @since 1.1
6192 */
6193function _asnhex_getNthChildIndex_AtObj(h, idx, nth) {
6194 var a = _asnhex_getPosArrayOfChildren_AtObj(h, idx);
6195 return a[nth];
6196}
6197
6198// ========== decendant methods ==============================
6199
6200/**
6201 * get string index of nth child object of ASN.1 object refered by h, idx
6202 * @name getDecendantIndexByNthList
6203 * @memberOf ASN1HEX
6204 * @function
6205 * @param {String} h hexadecimal string of ASN.1 DER encoded data
6206 * @param {Number} currentIndex start string index of ASN.1 object
6207 * @param {Array of Number} nthList array list of nth
6208 * @return {Number} string index refered by nthList
6209 * @since 1.1
6210 */
6211function _asnhex_getDecendantIndexByNthList(h, currentIndex, nthList) {
6212 if (nthList.length == 0) {
6213 return currentIndex;
6214 }
6215 var firstNth = nthList.shift();
6216 var a = _asnhex_getPosArrayOfChildren_AtObj(h, currentIndex);
6217 return _asnhex_getDecendantIndexByNthList(h, a[firstNth], nthList);
6218}
6219
6220/**
6221 * get hexadecimal string of ASN.1 TLV refered by current index and nth index list.
6222 * @name getDecendantHexTLVByNthList
6223 * @memberOf ASN1HEX
6224 * @function
6225 * @param {String} h hexadecimal string of ASN.1 DER encoded data
6226 * @param {Number} currentIndex start string index of ASN.1 object
6227 * @param {Array of Number} nthList array list of nth
6228 * @return {Number} hexadecimal string of ASN.1 TLV refered by nthList
6229 * @since 1.1
6230 */
6231function _asnhex_getDecendantHexTLVByNthList(h, currentIndex, nthList) {
6232 var idx = _asnhex_getDecendantIndexByNthList(h, currentIndex, nthList);
6233 return _asnhex_getHexOfTLV_AtObj(h, idx);
6234}
6235
6236/**
6237 * get hexadecimal string of ASN.1 V refered by current index and nth index list.
6238 * @name getDecendantHexVByNthList
6239 * @memberOf ASN1HEX
6240 * @function
6241 * @param {String} h hexadecimal string of ASN.1 DER encoded data
6242 * @param {Number} currentIndex start string index of ASN.1 object
6243 * @param {Array of Number} nthList array list of nth
6244 * @return {Number} hexadecimal string of ASN.1 V refered by nthList
6245 * @since 1.1
6246 */
6247function _asnhex_getDecendantHexVByNthList(h, currentIndex, nthList) {
6248 var idx = _asnhex_getDecendantIndexByNthList(h, currentIndex, nthList);
6249 return _asnhex_getHexOfV_AtObj(h, idx);
6250}
6251
6252// ========== class definition ==============================
6253
6254/**
6255 * ASN.1 DER encoded hexadecimal string utility class
6256 * @class ASN.1 DER encoded hexadecimal string utility class
6257 * @author Kenji Urushima
6258 * @version 1.1 (09 May 2012)
6259 * @see <a href="http://kjur.github.com/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a>
6260 * @since 1.1
6261 */
6262function ASN1HEX() {
6263 return ASN1HEX;
6264}
6265
6266ASN1HEX.getByteLengthOfL_AtObj = _asnhex_getByteLengthOfL_AtObj;
6267ASN1HEX.getHexOfL_AtObj = _asnhex_getHexOfL_AtObj;
6268ASN1HEX.getIntOfL_AtObj = _asnhex_getIntOfL_AtObj;
6269ASN1HEX.getStartPosOfV_AtObj = _asnhex_getStartPosOfV_AtObj;
6270ASN1HEX.getHexOfV_AtObj = _asnhex_getHexOfV_AtObj;
6271ASN1HEX.getHexOfTLV_AtObj = _asnhex_getHexOfTLV_AtObj;
6272ASN1HEX.getPosOfNextSibling_AtObj = _asnhex_getPosOfNextSibling_AtObj;
6273ASN1HEX.getPosArrayOfChildren_AtObj = _asnhex_getPosArrayOfChildren_AtObj;
6274ASN1HEX.getNthChildIndex_AtObj = _asnhex_getNthChildIndex_AtObj;
6275ASN1HEX.getDecendantIndexByNthList = _asnhex_getDecendantIndexByNthList;
6276ASN1HEX.getDecendantHexVByNthList = _asnhex_getDecendantHexVByNthList;
6277ASN1HEX.getDecendantHexTLVByNthList = _asnhex_getDecendantHexTLVByNthList;
Jeff Thompson1a338f82012-12-29 17:07:04 -08006278/*! x509-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license
6279 */
6280//
6281// x509.js - X509 class to read subject public key from certificate.
6282//
6283// version: 1.1 (10-May-2012)
6284//
6285// Copyright (c) 2010-2012 Kenji Urushima (kenji.urushima@gmail.com)
6286//
6287// This software is licensed under the terms of the MIT License.
6288// http://kjur.github.com/jsrsasign/license
6289//
6290// The above copyright and license notice shall be
6291// included in all copies or substantial portions of the Software.
6292//
6293
6294// Depends:
6295// base64.js
6296// rsa.js
6297// asn1hex.js
6298
6299function _x509_pemToBase64(sCertPEM) {
6300 var s = sCertPEM;
6301 s = s.replace("-----BEGIN CERTIFICATE-----", "");
6302 s = s.replace("-----END CERTIFICATE-----", "");
6303 s = s.replace(/[ \n]+/g, "");
6304 return s;
6305}
6306
6307function _x509_pemToHex(sCertPEM) {
6308 var b64Cert = _x509_pemToBase64(sCertPEM);
6309 var hCert = b64tohex(b64Cert);
6310 return hCert;
6311}
6312
6313function _x509_getHexTbsCertificateFromCert(hCert) {
6314 var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0);
6315 return pTbsCert;
6316}
6317
6318// NOTE: privateKeyUsagePeriod field of X509v2 not supported.
6319// NOTE: v1 and v3 supported
6320function _x509_getSubjectPublicKeyInfoPosFromCertHex(hCert) {
6321 var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0);
6322 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pTbsCert);
6323 if (a.length < 1) return -1;
6324 if (hCert.substring(a[0], a[0] + 10) == "a003020102") { // v3
6325 if (a.length < 6) return -1;
6326 return a[6];
6327 } else {
6328 if (a.length < 5) return -1;
6329 return a[5];
6330 }
6331}
6332
6333// NOTE: Without BITSTRING encapsulation.
6334// If pInfo is supplied, it is the position in hCert of the SubjectPublicKeyInfo.
6335function _x509_getSubjectPublicKeyPosFromCertHex(hCert, pInfo) {
6336 if (pInfo == null)
6337 pInfo = _x509_getSubjectPublicKeyInfoPosFromCertHex(hCert);
6338 if (pInfo == -1) return -1;
6339 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pInfo);
6340
6341 if (a.length != 2) return -1;
6342 var pBitString = a[1];
6343 if (hCert.substring(pBitString, pBitString + 2) != '03') return -1;
6344 var pBitStringV = ASN1HEX.getStartPosOfV_AtObj(hCert, pBitString);
6345
6346 if (hCert.substring(pBitStringV, pBitStringV + 2) != '00') return -1;
6347 return pBitStringV + 2;
6348}
6349
6350// If p is supplied, it is the public key position in hCert.
6351function _x509_getPublicKeyHexArrayFromCertHex(hCert, p) {
6352 if (p == null)
6353 p = _x509_getSubjectPublicKeyPosFromCertHex(hCert);
6354 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, p);
6355 //var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a[3]);
6356 if(LOG>4){
6357 console.log('a is now');
6358 console.log(a);
6359 }
6360
6361 //if (a.length != 2) return [];
6362 if (a.length < 2) return [];
6363
6364 var hN = ASN1HEX.getHexOfV_AtObj(hCert, a[0]);
6365 var hE = ASN1HEX.getHexOfV_AtObj(hCert, a[1]);
6366 if (hN != null && hE != null) {
6367 return [hN, hE];
6368 } else {
6369 return [];
6370 }
6371}
6372
6373function _x509_getPublicKeyHexArrayFromCertPEM(sCertPEM) {
6374 var hCert = _x509_pemToHex(sCertPEM);
6375 var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
6376 return a;
6377}
6378
6379// ===== get basic fields from hex =====================================
6380/**
6381 * get hexadecimal string of serialNumber field of certificate.<br/>
6382 * @name getSerialNumberHex
6383 * @memberOf X509#
6384 * @function
6385 */
6386function _x509_getSerialNumberHex() {
6387 return ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 1]);
6388}
6389
6390/**
6391 * get hexadecimal string of issuer field of certificate.<br/>
6392 * @name getIssuerHex
6393 * @memberOf X509#
6394 * @function
6395 */
6396function _x509_getIssuerHex() {
6397 return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]);
6398}
6399
6400/**
6401 * get string of issuer field of certificate.<br/>
6402 * @name getIssuerString
6403 * @memberOf X509#
6404 * @function
6405 */
6406function _x509_getIssuerString() {
6407 return _x509_hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]));
6408}
6409
6410/**
6411 * get hexadecimal string of subject field of certificate.<br/>
6412 * @name getSubjectHex
6413 * @memberOf X509#
6414 * @function
6415 */
6416function _x509_getSubjectHex() {
6417 return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]);
6418}
6419
6420/**
6421 * get string of subject field of certificate.<br/>
6422 * @name getSubjectString
6423 * @memberOf X509#
6424 * @function
6425 */
6426function _x509_getSubjectString() {
6427 return _x509_hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]));
6428}
6429
6430/**
6431 * get notBefore field string of certificate.<br/>
6432 * @name getNotBefore
6433 * @memberOf X509#
6434 * @function
6435 */
6436function _x509_getNotBefore() {
6437 var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 0]);
6438 s = s.replace(/(..)/g, "%$1");
6439 s = decodeURIComponent(s);
6440 return s;
6441}
6442
6443/**
6444 * get notAfter field string of certificate.<br/>
6445 * @name getNotAfter
6446 * @memberOf X509#
6447 * @function
6448 */
6449function _x509_getNotAfter() {
6450 var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 1]);
6451 s = s.replace(/(..)/g, "%$1");
6452 s = decodeURIComponent(s);
6453 return s;
6454}
6455
6456// ===== read certificate =====================================
6457
6458_x509_DN_ATTRHEX = {
6459 "0603550406": "C",
6460 "060355040a": "O",
6461 "060355040b": "OU",
6462 "0603550403": "CN",
6463 "0603550405": "SN",
6464 "0603550408": "ST",
6465 "0603550407": "L" };
6466
6467function _x509_hex2dn(hDN) {
6468 var s = "";
6469 var a = ASN1HEX.getPosArrayOfChildren_AtObj(hDN, 0);
6470 for (var i = 0; i < a.length; i++) {
6471 var hRDN = ASN1HEX.getHexOfTLV_AtObj(hDN, a[i]);
6472 s = s + "/" + _x509_hex2rdn(hRDN);
6473 }
6474 return s;
6475}
6476
6477function _x509_hex2rdn(hRDN) {
6478 var hType = ASN1HEX.getDecendantHexTLVByNthList(hRDN, 0, [0, 0]);
6479 var hValue = ASN1HEX.getDecendantHexVByNthList(hRDN, 0, [0, 1]);
6480 var type = "";
6481 try { type = _x509_DN_ATTRHEX[hType]; } catch (ex) { type = hType; }
6482 hValue = hValue.replace(/(..)/g, "%$1");
6483 var value = decodeURIComponent(hValue);
6484 return type + "=" + value;
6485}
6486
6487// ===== read certificate =====================================
6488
6489
6490/**
6491 * read PEM formatted X.509 certificate from string.<br/>
6492 * @name readCertPEM
6493 * @memberOf X509#
6494 * @function
6495 * @param {String} sCertPEM string for PEM formatted X.509 certificate
6496 */
6497function _x509_readCertPEM(sCertPEM) {
6498 var hCert = _x509_pemToHex(sCertPEM);
6499 var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
6500 if(LOG>4){
6501 console.log('HEX VALUE IS ' + hCert);
6502 console.log('type of a' + typeof a);
6503 console.log('a VALUE IS ');
6504 console.log(a);
6505 console.log('a[0] VALUE IS ' + a[0]);
6506 console.log('a[1] VALUE IS ' + a[1]);
6507 }
6508 var rsa = new RSAKey();
6509 rsa.setPublic(a[0], a[1]);
6510 this.subjectPublicKeyRSA = rsa;
6511 this.subjectPublicKeyRSA_hN = a[0];
6512 this.subjectPublicKeyRSA_hE = a[1];
6513 this.hex = hCert;
6514}
6515
6516/**
6517 * read hex formatted X.509 certificate from string.
6518 * @name readCertHex
6519 * @memberOf X509#
6520 * @function
6521 * @param {String} hCert string for hex formatted X.509 certificate
6522 */
6523function _x509_readCertHex(hCert) {
6524 hCert = hCert.toLowerCase();
6525 var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
6526 var rsa = new RSAKey();
6527 rsa.setPublic(a[0], a[1]);
6528 this.subjectPublicKeyRSA = rsa;
6529 this.subjectPublicKeyRSA_hN = a[0];
6530 this.subjectPublicKeyRSA_hE = a[1];
6531 this.hex = hCert;
6532}
6533
6534function _x509_readCertPEMWithoutRSAInit(sCertPEM) {
6535 var hCert = _x509_pemToHex(sCertPEM);
6536 var a = _x509_getPublicKeyHexArrayFromCertHex(hCert);
6537 this.subjectPublicKeyRSA.setPublic(a[0], a[1]);
6538 this.subjectPublicKeyRSA_hN = a[0];
6539 this.subjectPublicKeyRSA_hE = a[1];
6540 this.hex = hCert;
6541}
6542
6543/**
6544 * X.509 certificate class.<br/>
6545 * @class X.509 certificate class
6546 * @property {RSAKey} subjectPublicKeyRSA Tom Wu's RSAKey object
6547 * @property {String} subjectPublicKeyRSA_hN hexadecimal string for modulus of RSA public key
6548 * @property {String} subjectPublicKeyRSA_hE hexadecimal string for public exponent of RSA public key
6549 * @property {String} hex hexacedimal string for X.509 certificate.
6550 * @author Kenji Urushima
6551 * @version 1.0.1 (08 May 2012)
6552 * @see <a href="http://kjur.github.com/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a>
6553 */
6554function X509() {
6555 this.subjectPublicKeyRSA = null;
6556 this.subjectPublicKeyRSA_hN = null;
6557 this.subjectPublicKeyRSA_hE = null;
6558 this.hex = null;
6559}
6560
6561X509.prototype.readCertPEM = _x509_readCertPEM;
6562X509.prototype.readCertHex = _x509_readCertHex;
6563X509.prototype.readCertPEMWithoutRSAInit = _x509_readCertPEMWithoutRSAInit;
6564X509.prototype.getSerialNumberHex = _x509_getSerialNumberHex;
6565X509.prototype.getIssuerHex = _x509_getIssuerHex;
6566X509.prototype.getSubjectHex = _x509_getSubjectHex;
6567X509.prototype.getIssuerString = _x509_getIssuerString;
6568X509.prototype.getSubjectString = _x509_getSubjectString;
6569X509.prototype.getNotBefore = _x509_getNotBefore;
6570X509.prototype.getNotAfter = _x509_getNotAfter;
6571
Wentao Shang0e291c82012-12-02 23:36:29 -08006572// Copyright (c) 2005 Tom Wu
6573// All Rights Reserved.
6574// See "LICENSE" for details.
6575
6576// Basic JavaScript BN library - subset useful for RSA encryption.
6577
6578// Bits per digit
6579var dbits;
6580
6581// JavaScript engine analysis
6582var canary = 0xdeadbeefcafe;
6583var j_lm = ((canary&0xffffff)==0xefcafe);
6584
6585// (public) Constructor
6586function BigInteger(a,b,c) {
6587 if(a != null)
6588 if("number" == typeof a) this.fromNumber(a,b,c);
6589 else if(b == null && "string" != typeof a) this.fromString(a,256);
6590 else this.fromString(a,b);
6591}
6592
6593// return new, unset BigInteger
6594function nbi() { return new BigInteger(null); }
6595
6596// am: Compute w_j += (x*this_i), propagate carries,
6597// c is initial carry, returns final carry.
6598// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
6599// We need to select the fastest one that works in this environment.
6600
6601// am1: use a single mult and divide to get the high bits,
6602// max digit bits should be 26 because
6603// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
6604function am1(i,x,w,j,c,n) {
6605 while(--n >= 0) {
6606 var v = x*this[i++]+w[j]+c;
6607 c = Math.floor(v/0x4000000);
6608 w[j++] = v&0x3ffffff;
6609 }
6610 return c;
6611}
6612// am2 avoids a big mult-and-extract completely.
6613// Max digit bits should be <= 30 because we do bitwise ops
6614// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
6615function am2(i,x,w,j,c,n) {
6616 var xl = x&0x7fff, xh = x>>15;
6617 while(--n >= 0) {
6618 var l = this[i]&0x7fff;
6619 var h = this[i++]>>15;
6620 var m = xh*l+h*xl;
6621 l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff);
6622 c = (l>>>30)+(m>>>15)+xh*h+(c>>>30);
6623 w[j++] = l&0x3fffffff;
6624 }
6625 return c;
6626}
6627// Alternately, set max digit bits to 28 since some
6628// browsers slow down when dealing with 32-bit numbers.
6629function am3(i,x,w,j,c,n) {
6630 var xl = x&0x3fff, xh = x>>14;
6631 while(--n >= 0) {
6632 var l = this[i]&0x3fff;
6633 var h = this[i++]>>14;
6634 var m = xh*l+h*xl;
6635 l = xl*l+((m&0x3fff)<<14)+w[j]+c;
6636 c = (l>>28)+(m>>14)+xh*h;
6637 w[j++] = l&0xfffffff;
6638 }
6639 return c;
6640}
6641if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
6642 BigInteger.prototype.am = am2;
6643 dbits = 30;
6644}
6645else if(j_lm && (navigator.appName != "Netscape")) {
6646 BigInteger.prototype.am = am1;
6647 dbits = 26;
6648}
6649else { // Mozilla/Netscape seems to prefer am3
6650 BigInteger.prototype.am = am3;
6651 dbits = 28;
6652}
6653
6654BigInteger.prototype.DB = dbits;
6655BigInteger.prototype.DM = ((1<<dbits)-1);
6656BigInteger.prototype.DV = (1<<dbits);
6657
6658var BI_FP = 52;
6659BigInteger.prototype.FV = Math.pow(2,BI_FP);
6660BigInteger.prototype.F1 = BI_FP-dbits;
6661BigInteger.prototype.F2 = 2*dbits-BI_FP;
6662
6663// Digit conversions
6664var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
6665var BI_RC = new Array();
6666var rr,vv;
6667rr = "0".charCodeAt(0);
6668for(vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
6669rr = "a".charCodeAt(0);
6670for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
6671rr = "A".charCodeAt(0);
6672for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
6673
6674function int2char(n) { return BI_RM.charAt(n); }
6675function intAt(s,i) {
6676 var c = BI_RC[s.charCodeAt(i)];
6677 return (c==null)?-1:c;
6678}
6679
6680// (protected) copy this to r
6681function bnpCopyTo(r) {
6682 for(var i = this.t-1; i >= 0; --i) r[i] = this[i];
6683 r.t = this.t;
6684 r.s = this.s;
6685}
6686
6687// (protected) set from integer value x, -DV <= x < DV
6688function bnpFromInt(x) {
6689 this.t = 1;
6690 this.s = (x<0)?-1:0;
6691 if(x > 0) this[0] = x;
6692 else if(x < -1) this[0] = x+DV;
6693 else this.t = 0;
6694}
6695
6696// return bigint initialized to value
6697function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
6698
6699// (protected) set from string and radix
6700function bnpFromString(s,b) {
6701 var k;
6702 if(b == 16) k = 4;
6703 else if(b == 8) k = 3;
6704 else if(b == 256) k = 8; // byte array
6705 else if(b == 2) k = 1;
6706 else if(b == 32) k = 5;
6707 else if(b == 4) k = 2;
6708 else { this.fromRadix(s,b); return; }
6709 this.t = 0;
6710 this.s = 0;
6711 var i = s.length, mi = false, sh = 0;
6712 while(--i >= 0) {
6713 var x = (k==8)?s[i]&0xff:intAt(s,i);
6714 if(x < 0) {
6715 if(s.charAt(i) == "-") mi = true;
6716 continue;
6717 }
6718 mi = false;
6719 if(sh == 0)
6720 this[this.t++] = x;
6721 else if(sh+k > this.DB) {
6722 this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<<sh;
6723 this[this.t++] = (x>>(this.DB-sh));
6724 }
6725 else
6726 this[this.t-1] |= x<<sh;
6727 sh += k;
6728 if(sh >= this.DB) sh -= this.DB;
6729 }
6730 if(k == 8 && (s[0]&0x80) != 0) {
6731 this.s = -1;
6732 if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh;
6733 }
6734 this.clamp();
6735 if(mi) BigInteger.ZERO.subTo(this,this);
6736}
6737
6738// (protected) clamp off excess high words
6739function bnpClamp() {
6740 var c = this.s&this.DM;
6741 while(this.t > 0 && this[this.t-1] == c) --this.t;
6742}
6743
6744// (public) return string representation in given radix
6745function bnToString(b) {
6746 if(this.s < 0) return "-"+this.negate().toString(b);
6747 var k;
6748 if(b == 16) k = 4;
6749 else if(b == 8) k = 3;
6750 else if(b == 2) k = 1;
6751 else if(b == 32) k = 5;
6752 else if(b == 4) k = 2;
6753 else return this.toRadix(b);
6754 var km = (1<<k)-1, d, m = false, r = "", i = this.t;
6755 var p = this.DB-(i*this.DB)%k;
6756 if(i-- > 0) {
6757 if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); }
6758 while(i >= 0) {
6759 if(p < k) {
6760 d = (this[i]&((1<<p)-1))<<(k-p);
6761 d |= this[--i]>>(p+=this.DB-k);
6762 }
6763 else {
6764 d = (this[i]>>(p-=k))&km;
6765 if(p <= 0) { p += this.DB; --i; }
6766 }
6767 if(d > 0) m = true;
6768 if(m) r += int2char(d);
6769 }
6770 }
6771 return m?r:"0";
6772}
6773
6774// (public) -this
6775function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }
6776
6777// (public) |this|
6778function bnAbs() { return (this.s<0)?this.negate():this; }
6779
6780// (public) return + if this > a, - if this < a, 0 if equal
6781function bnCompareTo(a) {
6782 var r = this.s-a.s;
6783 if(r != 0) return r;
6784 var i = this.t;
6785 r = i-a.t;
6786 if(r != 0) return r;
6787 while(--i >= 0) if((r=this[i]-a[i]) != 0) return r;
6788 return 0;
6789}
6790
6791// returns bit length of the integer x
6792function nbits(x) {
6793 var r = 1, t;
6794 if((t=x>>>16) != 0) { x = t; r += 16; }
6795 if((t=x>>8) != 0) { x = t; r += 8; }
6796 if((t=x>>4) != 0) { x = t; r += 4; }
6797 if((t=x>>2) != 0) { x = t; r += 2; }
6798 if((t=x>>1) != 0) { x = t; r += 1; }
6799 return r;
6800}
6801
6802// (public) return the number of bits in "this"
6803function bnBitLength() {
6804 if(this.t <= 0) return 0;
6805 return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM));
6806}
6807
6808// (protected) r = this << n*DB
6809function bnpDLShiftTo(n,r) {
6810 var i;
6811 for(i = this.t-1; i >= 0; --i) r[i+n] = this[i];
6812 for(i = n-1; i >= 0; --i) r[i] = 0;
6813 r.t = this.t+n;
6814 r.s = this.s;
6815}
6816
6817// (protected) r = this >> n*DB
6818function bnpDRShiftTo(n,r) {
6819 for(var i = n; i < this.t; ++i) r[i-n] = this[i];
6820 r.t = Math.max(this.t-n,0);
6821 r.s = this.s;
6822}
6823
6824// (protected) r = this << n
6825function bnpLShiftTo(n,r) {
6826 var bs = n%this.DB;
6827 var cbs = this.DB-bs;
6828 var bm = (1<<cbs)-1;
6829 var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i;
6830 for(i = this.t-1; i >= 0; --i) {
6831 r[i+ds+1] = (this[i]>>cbs)|c;
6832 c = (this[i]&bm)<<bs;
6833 }
6834 for(i = ds-1; i >= 0; --i) r[i] = 0;
6835 r[ds] = c;
6836 r.t = this.t+ds+1;
6837 r.s = this.s;
6838 r.clamp();
6839}
6840
6841// (protected) r = this >> n
6842function bnpRShiftTo(n,r) {
6843 r.s = this.s;
6844 var ds = Math.floor(n/this.DB);
6845 if(ds >= this.t) { r.t = 0; return; }
6846 var bs = n%this.DB;
6847 var cbs = this.DB-bs;
6848 var bm = (1<<bs)-1;
6849 r[0] = this[ds]>>bs;
6850 for(var i = ds+1; i < this.t; ++i) {
6851 r[i-ds-1] |= (this[i]&bm)<<cbs;
6852 r[i-ds] = this[i]>>bs;
6853 }
6854 if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs;
6855 r.t = this.t-ds;
6856 r.clamp();
6857}
6858
6859// (protected) r = this - a
6860function bnpSubTo(a,r) {
6861 var i = 0, c = 0, m = Math.min(a.t,this.t);
6862 while(i < m) {
6863 c += this[i]-a[i];
6864 r[i++] = c&this.DM;
6865 c >>= this.DB;
6866 }
6867 if(a.t < this.t) {
6868 c -= a.s;
6869 while(i < this.t) {
6870 c += this[i];
6871 r[i++] = c&this.DM;
6872 c >>= this.DB;
6873 }
6874 c += this.s;
6875 }
6876 else {
6877 c += this.s;
6878 while(i < a.t) {
6879 c -= a[i];
6880 r[i++] = c&this.DM;
6881 c >>= this.DB;
6882 }
6883 c -= a.s;
6884 }
6885 r.s = (c<0)?-1:0;
6886 if(c < -1) r[i++] = this.DV+c;
6887 else if(c > 0) r[i++] = c;
6888 r.t = i;
6889 r.clamp();
6890}
6891
6892// (protected) r = this * a, r != this,a (HAC 14.12)
6893// "this" should be the larger one if appropriate.
6894function bnpMultiplyTo(a,r) {
6895 var x = this.abs(), y = a.abs();
6896 var i = x.t;
6897 r.t = i+y.t;
6898 while(--i >= 0) r[i] = 0;
6899 for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t);
6900 r.s = 0;
6901 r.clamp();
6902 if(this.s != a.s) BigInteger.ZERO.subTo(r,r);
6903}
6904
6905// (protected) r = this^2, r != this (HAC 14.16)
6906function bnpSquareTo(r) {
6907 var x = this.abs();
6908 var i = r.t = 2*x.t;
6909 while(--i >= 0) r[i] = 0;
6910 for(i = 0; i < x.t-1; ++i) {
6911 var c = x.am(i,x[i],r,2*i,0,1);
6912 if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) {
6913 r[i+x.t] -= x.DV;
6914 r[i+x.t+1] = 1;
6915 }
6916 }
6917 if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1);
6918 r.s = 0;
6919 r.clamp();
6920}
6921
6922// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
6923// r != q, this != m. q or r may be null.
6924function bnpDivRemTo(m,q,r) {
6925 var pm = m.abs();
6926 if(pm.t <= 0) return;
6927 var pt = this.abs();
6928 if(pt.t < pm.t) {
6929 if(q != null) q.fromInt(0);
6930 if(r != null) this.copyTo(r);
6931 return;
6932 }
6933 if(r == null) r = nbi();
6934 var y = nbi(), ts = this.s, ms = m.s;
6935 var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus
6936 if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); }
6937 else { pm.copyTo(y); pt.copyTo(r); }
6938 var ys = y.t;
6939 var y0 = y[ys-1];
6940 if(y0 == 0) return;
6941 var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0);
6942 var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
6943 var i = r.t, j = i-ys, t = (q==null)?nbi():q;
6944 y.dlShiftTo(j,t);
6945 if(r.compareTo(t) >= 0) {
6946 r[r.t++] = 1;
6947 r.subTo(t,r);
6948 }
6949 BigInteger.ONE.dlShiftTo(ys,t);
6950 t.subTo(y,y); // "negative" y so we can replace sub with am later
6951 while(y.t < ys) y[y.t++] = 0;
6952 while(--j >= 0) {
6953 // Estimate quotient digit
6954 var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);
6955 if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out
6956 y.dlShiftTo(j,t);
6957 r.subTo(t,r);
6958 while(r[i] < --qd) r.subTo(t,r);
6959 }
6960 }
6961 if(q != null) {
6962 r.drShiftTo(ys,q);
6963 if(ts != ms) BigInteger.ZERO.subTo(q,q);
6964 }
6965 r.t = ys;
6966 r.clamp();
6967 if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder
6968 if(ts < 0) BigInteger.ZERO.subTo(r,r);
6969}
6970
6971// (public) this mod a
6972function bnMod(a) {
6973 var r = nbi();
6974 this.abs().divRemTo(a,null,r);
6975 if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r);
6976 return r;
6977}
6978
6979// Modular reduction using "classic" algorithm
6980function Classic(m) { this.m = m; }
6981function cConvert(x) {
6982 if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
6983 else return x;
6984}
6985function cRevert(x) { return x; }
6986function cReduce(x) { x.divRemTo(this.m,null,x); }
6987function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
6988function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
6989
6990Classic.prototype.convert = cConvert;
6991Classic.prototype.revert = cRevert;
6992Classic.prototype.reduce = cReduce;
6993Classic.prototype.mulTo = cMulTo;
6994Classic.prototype.sqrTo = cSqrTo;
6995
6996// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
6997// justification:
6998// xy == 1 (mod m)
6999// xy = 1+km
7000// xy(2-xy) = (1+km)(1-km)
7001// x[y(2-xy)] = 1-k^2m^2
7002// x[y(2-xy)] == 1 (mod m^2)
7003// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
7004// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
7005// JS multiply "overflows" differently from C/C++, so care is needed here.
7006function bnpInvDigit() {
7007 if(this.t < 1) return 0;
7008 var x = this[0];
7009 if((x&1) == 0) return 0;
7010 var y = x&3; // y == 1/x mod 2^2
7011 y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4
7012 y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8
7013 y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16
7014 // last step - calculate inverse mod DV directly;
7015 // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
7016 y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits
7017 // we really want the negative inverse, and -DV < y < DV
7018 return (y>0)?this.DV-y:-y;
7019}
7020
7021// Montgomery reduction
7022function Montgomery(m) {
7023 this.m = m;
7024 this.mp = m.invDigit();
7025 this.mpl = this.mp&0x7fff;
7026 this.mph = this.mp>>15;
7027 this.um = (1<<(m.DB-15))-1;
7028 this.mt2 = 2*m.t;
7029}
7030
7031// xR mod m
7032function montConvert(x) {
7033 var r = nbi();
7034 x.abs().dlShiftTo(this.m.t,r);
7035 r.divRemTo(this.m,null,r);
7036 if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r);
7037 return r;
7038}
7039
7040// x/R mod m
7041function montRevert(x) {
7042 var r = nbi();
7043 x.copyTo(r);
7044 this.reduce(r);
7045 return r;
7046}
7047
7048// x = x/R mod m (HAC 14.32)
7049function montReduce(x) {
7050 while(x.t <= this.mt2) // pad x so am has enough room later
7051 x[x.t++] = 0;
7052 for(var i = 0; i < this.m.t; ++i) {
7053 // faster way of calculating u0 = x[i]*mp mod DV
7054 var j = x[i]&0x7fff;
7055 var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM;
7056 // use am to combine the multiply-shift-add into one call
7057 j = i+this.m.t;
7058 x[j] += this.m.am(0,u0,x,i,0,this.m.t);
7059 // propagate carry
7060 while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; }
7061 }
7062 x.clamp();
7063 x.drShiftTo(this.m.t,x);
7064 if(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
7065}
7066
7067// r = "x^2/R mod m"; x != r
7068function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
7069
7070// r = "xy/R mod m"; x,y != r
7071function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
7072
7073Montgomery.prototype.convert = montConvert;
7074Montgomery.prototype.revert = montRevert;
7075Montgomery.prototype.reduce = montReduce;
7076Montgomery.prototype.mulTo = montMulTo;
7077Montgomery.prototype.sqrTo = montSqrTo;
7078
7079// (protected) true iff this is even
7080function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; }
7081
7082// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
7083function bnpExp(e,z) {
7084 if(e > 0xffffffff || e < 1) return BigInteger.ONE;
7085 var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1;
7086 g.copyTo(r);
7087 while(--i >= 0) {
7088 z.sqrTo(r,r2);
7089 if((e&(1<<i)) > 0) z.mulTo(r2,g,r);
7090 else { var t = r; r = r2; r2 = t; }
7091 }
7092 return z.revert(r);
7093}
7094
7095// (public) this^e % m, 0 <= e < 2^32
7096function bnModPowInt(e,m) {
7097 var z;
7098 if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
7099 return this.exp(e,z);
7100}
7101
7102// protected
7103BigInteger.prototype.copyTo = bnpCopyTo;
7104BigInteger.prototype.fromInt = bnpFromInt;
7105BigInteger.prototype.fromString = bnpFromString;
7106BigInteger.prototype.clamp = bnpClamp;
7107BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
7108BigInteger.prototype.drShiftTo = bnpDRShiftTo;
7109BigInteger.prototype.lShiftTo = bnpLShiftTo;
7110BigInteger.prototype.rShiftTo = bnpRShiftTo;
7111BigInteger.prototype.subTo = bnpSubTo;
7112BigInteger.prototype.multiplyTo = bnpMultiplyTo;
7113BigInteger.prototype.squareTo = bnpSquareTo;
7114BigInteger.prototype.divRemTo = bnpDivRemTo;
7115BigInteger.prototype.invDigit = bnpInvDigit;
7116BigInteger.prototype.isEven = bnpIsEven;
7117BigInteger.prototype.exp = bnpExp;
7118
7119// public
7120BigInteger.prototype.toString = bnToString;
7121BigInteger.prototype.negate = bnNegate;
7122BigInteger.prototype.abs = bnAbs;
7123BigInteger.prototype.compareTo = bnCompareTo;
7124BigInteger.prototype.bitLength = bnBitLength;
7125BigInteger.prototype.mod = bnMod;
7126BigInteger.prototype.modPowInt = bnModPowInt;
7127
7128// "constants"
7129BigInteger.ZERO = nbv(0);
7130BigInteger.ONE = nbv(1);
7131// Copyright (c) 2005-2009 Tom Wu
7132// All Rights Reserved.
7133// See "LICENSE" for details.
7134
7135// Extended JavaScript BN functions, required for RSA private ops.
7136
7137// Version 1.1: new BigInteger("0", 10) returns "proper" zero
7138
7139// (public)
7140function bnClone() { var r = nbi(); this.copyTo(r); return r; }
7141
7142// (public) return value as integer
7143function bnIntValue() {
7144 if(this.s < 0) {
7145 if(this.t == 1) return this[0]-this.DV;
7146 else if(this.t == 0) return -1;
7147 }
7148 else if(this.t == 1) return this[0];
7149 else if(this.t == 0) return 0;
7150 // assumes 16 < DB < 32
7151 return ((this[1]&((1<<(32-this.DB))-1))<<this.DB)|this[0];
7152}
7153
7154// (public) return value as byte
7155function bnByteValue() { return (this.t==0)?this.s:(this[0]<<24)>>24; }
7156
7157// (public) return value as short (assumes DB>=16)
7158function bnShortValue() { return (this.t==0)?this.s:(this[0]<<16)>>16; }
7159
7160// (protected) return x s.t. r^x < DV
7161function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); }
7162
7163// (public) 0 if this == 0, 1 if this > 0
7164function bnSigNum() {
7165 if(this.s < 0) return -1;
7166 else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
7167 else return 1;
7168}
7169
7170// (protected) convert to radix string
7171function bnpToRadix(b) {
7172 if(b == null) b = 10;
7173 if(this.signum() == 0 || b < 2 || b > 36) return "0";
7174 var cs = this.chunkSize(b);
7175 var a = Math.pow(b,cs);
7176 var d = nbv(a), y = nbi(), z = nbi(), r = "";
7177 this.divRemTo(d,y,z);
7178 while(y.signum() > 0) {
7179 r = (a+z.intValue()).toString(b).substr(1) + r;
7180 y.divRemTo(d,y,z);
7181 }
7182 return z.intValue().toString(b) + r;
7183}
7184
7185// (protected) convert from radix string
7186function bnpFromRadix(s,b) {
7187 this.fromInt(0);
7188 if(b == null) b = 10;
7189 var cs = this.chunkSize(b);
7190 var d = Math.pow(b,cs), mi = false, j = 0, w = 0;
7191 for(var i = 0; i < s.length; ++i) {
7192 var x = intAt(s,i);
7193 if(x < 0) {
7194 if(s.charAt(i) == "-" && this.signum() == 0) mi = true;
7195 continue;
7196 }
7197 w = b*w+x;
7198 if(++j >= cs) {
7199 this.dMultiply(d);
7200 this.dAddOffset(w,0);
7201 j = 0;
7202 w = 0;
7203 }
7204 }
7205 if(j > 0) {
7206 this.dMultiply(Math.pow(b,j));
7207 this.dAddOffset(w,0);
7208 }
7209 if(mi) BigInteger.ZERO.subTo(this,this);
7210}
7211
7212// (protected) alternate constructor
7213function bnpFromNumber(a,b,c) {
7214 if("number" == typeof b) {
7215 // new BigInteger(int,int,RNG)
7216 if(a < 2) this.fromInt(1);
7217 else {
7218 this.fromNumber(a,c);
7219 if(!this.testBit(a-1)) // force MSB set
7220 this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this);
7221 if(this.isEven()) this.dAddOffset(1,0); // force odd
7222 while(!this.isProbablePrime(b)) {
7223 this.dAddOffset(2,0);
7224 if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this);
7225 }
7226 }
7227 }
7228 else {
7229 // new BigInteger(int,RNG)
7230 var x = new Array(), t = a&7;
7231 x.length = (a>>3)+1;
7232 b.nextBytes(x);
7233 if(t > 0) x[0] &= ((1<<t)-1); else x[0] = 0;
7234 this.fromString(x,256);
7235 }
7236}
7237
7238// (public) convert to bigendian byte array
7239function bnToByteArray() {
7240 var i = this.t, r = new Array();
7241 r[0] = this.s;
7242 var p = this.DB-(i*this.DB)%8, d, k = 0;
7243 if(i-- > 0) {
7244 if(p < this.DB && (d = this[i]>>p) != (this.s&this.DM)>>p)
7245 r[k++] = d|(this.s<<(this.DB-p));
7246 while(i >= 0) {
7247 if(p < 8) {
7248 d = (this[i]&((1<<p)-1))<<(8-p);
7249 d |= this[--i]>>(p+=this.DB-8);
7250 }
7251 else {
7252 d = (this[i]>>(p-=8))&0xff;
7253 if(p <= 0) { p += this.DB; --i; }
7254 }
7255 if((d&0x80) != 0) d |= -256;
7256 if(k == 0 && (this.s&0x80) != (d&0x80)) ++k;
7257 if(k > 0 || d != this.s) r[k++] = d;
7258 }
7259 }
7260 return r;
7261}
7262
7263function bnEquals(a) { return(this.compareTo(a)==0); }
7264function bnMin(a) { return(this.compareTo(a)<0)?this:a; }
7265function bnMax(a) { return(this.compareTo(a)>0)?this:a; }
7266
7267// (protected) r = this op a (bitwise)
7268function bnpBitwiseTo(a,op,r) {
7269 var i, f, m = Math.min(a.t,this.t);
7270 for(i = 0; i < m; ++i) r[i] = op(this[i],a[i]);
7271 if(a.t < this.t) {
7272 f = a.s&this.DM;
7273 for(i = m; i < this.t; ++i) r[i] = op(this[i],f);
7274 r.t = this.t;
7275 }
7276 else {
7277 f = this.s&this.DM;
7278 for(i = m; i < a.t; ++i) r[i] = op(f,a[i]);
7279 r.t = a.t;
7280 }
7281 r.s = op(this.s,a.s);
7282 r.clamp();
7283}
7284
7285// (public) this & a
7286function op_and(x,y) { return x&y; }
7287function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; }
7288
7289// (public) this | a
7290function op_or(x,y) { return x|y; }
7291function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; }
7292
7293// (public) this ^ a
7294function op_xor(x,y) { return x^y; }
7295function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; }
7296
7297// (public) this & ~a
7298function op_andnot(x,y) { return x&~y; }
7299function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; }
7300
7301// (public) ~this
7302function bnNot() {
7303 var r = nbi();
7304 for(var i = 0; i < this.t; ++i) r[i] = this.DM&~this[i];
7305 r.t = this.t;
7306 r.s = ~this.s;
7307 return r;
7308}
7309
7310// (public) this << n
7311function bnShiftLeft(n) {
7312 var r = nbi();
7313 if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r);
7314 return r;
7315}
7316
7317// (public) this >> n
7318function bnShiftRight(n) {
7319 var r = nbi();
7320 if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r);
7321 return r;
7322}
7323
7324// return index of lowest 1-bit in x, x < 2^31
7325function lbit(x) {
7326 if(x == 0) return -1;
7327 var r = 0;
7328 if((x&0xffff) == 0) { x >>= 16; r += 16; }
7329 if((x&0xff) == 0) { x >>= 8; r += 8; }
7330 if((x&0xf) == 0) { x >>= 4; r += 4; }
7331 if((x&3) == 0) { x >>= 2; r += 2; }
7332 if((x&1) == 0) ++r;
7333 return r;
7334}
7335
7336// (public) returns index of lowest 1-bit (or -1 if none)
7337function bnGetLowestSetBit() {
7338 for(var i = 0; i < this.t; ++i)
7339 if(this[i] != 0) return i*this.DB+lbit(this[i]);
7340 if(this.s < 0) return this.t*this.DB;
7341 return -1;
7342}
7343
7344// return number of 1 bits in x
7345function cbit(x) {
7346 var r = 0;
7347 while(x != 0) { x &= x-1; ++r; }
7348 return r;
7349}
7350
7351// (public) return number of set bits
7352function bnBitCount() {
7353 var r = 0, x = this.s&this.DM;
7354 for(var i = 0; i < this.t; ++i) r += cbit(this[i]^x);
7355 return r;
7356}
7357
7358// (public) true iff nth bit is set
7359function bnTestBit(n) {
7360 var j = Math.floor(n/this.DB);
7361 if(j >= this.t) return(this.s!=0);
7362 return((this[j]&(1<<(n%this.DB)))!=0);
7363}
7364
7365// (protected) this op (1<<n)
7366function bnpChangeBit(n,op) {
7367 var r = BigInteger.ONE.shiftLeft(n);
7368 this.bitwiseTo(r,op,r);
7369 return r;
7370}
7371
7372// (public) this | (1<<n)
7373function bnSetBit(n) { return this.changeBit(n,op_or); }
7374
7375// (public) this & ~(1<<n)
7376function bnClearBit(n) { return this.changeBit(n,op_andnot); }
7377
7378// (public) this ^ (1<<n)
7379function bnFlipBit(n) { return this.changeBit(n,op_xor); }
7380
7381// (protected) r = this + a
7382function bnpAddTo(a,r) {
7383 var i = 0, c = 0, m = Math.min(a.t,this.t);
7384 while(i < m) {
7385 c += this[i]+a[i];
7386 r[i++] = c&this.DM;
7387 c >>= this.DB;
7388 }
7389 if(a.t < this.t) {
7390 c += a.s;
7391 while(i < this.t) {
7392 c += this[i];
7393 r[i++] = c&this.DM;
7394 c >>= this.DB;
7395 }
7396 c += this.s;
7397 }
7398 else {
7399 c += this.s;
7400 while(i < a.t) {
7401 c += a[i];
7402 r[i++] = c&this.DM;
7403 c >>= this.DB;
7404 }
7405 c += a.s;
7406 }
7407 r.s = (c<0)?-1:0;
7408 if(c > 0) r[i++] = c;
7409 else if(c < -1) r[i++] = this.DV+c;
7410 r.t = i;
7411 r.clamp();
7412}
7413
7414// (public) this + a
7415function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; }
7416
7417// (public) this - a
7418function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; }
7419
7420// (public) this * a
7421function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; }
7422
7423// (public) this / a
7424function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; }
7425
7426// (public) this % a
7427function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; }
7428
7429// (public) [this/a,this%a]
7430function bnDivideAndRemainder(a) {
7431 var q = nbi(), r = nbi();
7432 this.divRemTo(a,q,r);
7433 return new Array(q,r);
7434}
7435
7436// (protected) this *= n, this >= 0, 1 < n < DV
7437function bnpDMultiply(n) {
7438 this[this.t] = this.am(0,n-1,this,0,0,this.t);
7439 ++this.t;
7440 this.clamp();
7441}
7442
7443// (protected) this += n << w words, this >= 0
7444function bnpDAddOffset(n,w) {
7445 if(n == 0) return;
7446 while(this.t <= w) this[this.t++] = 0;
7447 this[w] += n;
7448 while(this[w] >= this.DV) {
7449 this[w] -= this.DV;
7450 if(++w >= this.t) this[this.t++] = 0;
7451 ++this[w];
7452 }
7453}
7454
7455// A "null" reducer
7456function NullExp() {}
7457function nNop(x) { return x; }
7458function nMulTo(x,y,r) { x.multiplyTo(y,r); }
7459function nSqrTo(x,r) { x.squareTo(r); }
7460
7461NullExp.prototype.convert = nNop;
7462NullExp.prototype.revert = nNop;
7463NullExp.prototype.mulTo = nMulTo;
7464NullExp.prototype.sqrTo = nSqrTo;
7465
7466// (public) this^e
7467function bnPow(e) { return this.exp(e,new NullExp()); }
7468
7469// (protected) r = lower n words of "this * a", a.t <= n
7470// "this" should be the larger one if appropriate.
7471function bnpMultiplyLowerTo(a,n,r) {
7472 var i = Math.min(this.t+a.t,n);
7473 r.s = 0; // assumes a,this >= 0
7474 r.t = i;
7475 while(i > 0) r[--i] = 0;
7476 var j;
7477 for(j = r.t-this.t; i < j; ++i) r[i+this.t] = this.am(0,a[i],r,i,0,this.t);
7478 for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a[i],r,i,0,n-i);
7479 r.clamp();
7480}
7481
7482// (protected) r = "this * a" without lower n words, n > 0
7483// "this" should be the larger one if appropriate.
7484function bnpMultiplyUpperTo(a,n,r) {
7485 --n;
7486 var i = r.t = this.t+a.t-n;
7487 r.s = 0; // assumes a,this >= 0
7488 while(--i >= 0) r[i] = 0;
7489 for(i = Math.max(n-this.t,0); i < a.t; ++i)
7490 r[this.t+i-n] = this.am(n-i,a[i],r,0,0,this.t+i-n);
7491 r.clamp();
7492 r.drShiftTo(1,r);
7493}
7494
7495// Barrett modular reduction
7496function Barrett(m) {
7497 // setup Barrett
7498 this.r2 = nbi();
7499 this.q3 = nbi();
7500 BigInteger.ONE.dlShiftTo(2*m.t,this.r2);
7501 this.mu = this.r2.divide(m);
7502 this.m = m;
7503}
7504
7505function barrettConvert(x) {
7506 if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m);
7507 else if(x.compareTo(this.m) < 0) return x;
7508 else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; }
7509}
7510
7511function barrettRevert(x) { return x; }
7512
7513// x = x mod m (HAC 14.42)
7514function barrettReduce(x) {
7515 x.drShiftTo(this.m.t-1,this.r2);
7516 if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); }
7517 this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3);
7518 this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);
7519 while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1);
7520 x.subTo(this.r2,x);
7521 while(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
7522}
7523
7524// r = x^2 mod m; x != r
7525function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
7526
7527// r = x*y mod m; x,y != r
7528function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
7529
7530Barrett.prototype.convert = barrettConvert;
7531Barrett.prototype.revert = barrettRevert;
7532Barrett.prototype.reduce = barrettReduce;
7533Barrett.prototype.mulTo = barrettMulTo;
7534Barrett.prototype.sqrTo = barrettSqrTo;
7535
7536// (public) this^e % m (HAC 14.85)
7537function bnModPow(e,m) {
7538 var i = e.bitLength(), k, r = nbv(1), z;
7539 if(i <= 0) return r;
7540 else if(i < 18) k = 1;
7541 else if(i < 48) k = 3;
7542 else if(i < 144) k = 4;
7543 else if(i < 768) k = 5;
7544 else k = 6;
7545 if(i < 8)
7546 z = new Classic(m);
7547 else if(m.isEven())
7548 z = new Barrett(m);
7549 else
7550 z = new Montgomery(m);
7551
7552 // precomputation
7553 var g = new Array(), n = 3, k1 = k-1, km = (1<<k)-1;
7554 g[1] = z.convert(this);
7555 if(k > 1) {
7556 var g2 = nbi();
7557 z.sqrTo(g[1],g2);
7558 while(n <= km) {
7559 g[n] = nbi();
7560 z.mulTo(g2,g[n-2],g[n]);
7561 n += 2;
7562 }
7563 }
7564
7565 var j = e.t-1, w, is1 = true, r2 = nbi(), t;
7566 i = nbits(e[j])-1;
7567 while(j >= 0) {
7568 if(i >= k1) w = (e[j]>>(i-k1))&km;
7569 else {
7570 w = (e[j]&((1<<(i+1))-1))<<(k1-i);
7571 if(j > 0) w |= e[j-1]>>(this.DB+i-k1);
7572 }
7573
7574 n = k;
7575 while((w&1) == 0) { w >>= 1; --n; }
7576 if((i -= n) < 0) { i += this.DB; --j; }
7577 if(is1) { // ret == 1, don't bother squaring or multiplying it
7578 g[w].copyTo(r);
7579 is1 = false;
7580 }
7581 else {
7582 while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; }
7583 if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; }
7584 z.mulTo(r2,g[w],r);
7585 }
7586
7587 while(j >= 0 && (e[j]&(1<<i)) == 0) {
7588 z.sqrTo(r,r2); t = r; r = r2; r2 = t;
7589 if(--i < 0) { i = this.DB-1; --j; }
7590 }
7591 }
7592 return z.revert(r);
7593}
7594
7595// (public) gcd(this,a) (HAC 14.54)
7596function bnGCD(a) {
7597 var x = (this.s<0)?this.negate():this.clone();
7598 var y = (a.s<0)?a.negate():a.clone();
7599 if(x.compareTo(y) < 0) { var t = x; x = y; y = t; }
7600 var i = x.getLowestSetBit(), g = y.getLowestSetBit();
7601 if(g < 0) return x;
7602 if(i < g) g = i;
7603 if(g > 0) {
7604 x.rShiftTo(g,x);
7605 y.rShiftTo(g,y);
7606 }
7607 while(x.signum() > 0) {
7608 if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x);
7609 if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y);
7610 if(x.compareTo(y) >= 0) {
7611 x.subTo(y,x);
7612 x.rShiftTo(1,x);
7613 }
7614 else {
7615 y.subTo(x,y);
7616 y.rShiftTo(1,y);
7617 }
7618 }
7619 if(g > 0) y.lShiftTo(g,y);
7620 return y;
7621}
7622
7623// (protected) this % n, n < 2^26
7624function bnpModInt(n) {
7625 if(n <= 0) return 0;
7626 var d = this.DV%n, r = (this.s<0)?n-1:0;
7627 if(this.t > 0)
7628 if(d == 0) r = this[0]%n;
7629 else for(var i = this.t-1; i >= 0; --i) r = (d*r+this[i])%n;
7630 return r;
7631}
7632
7633// (public) 1/this % m (HAC 14.61)
7634function bnModInverse(m) {
7635 var ac = m.isEven();
7636 if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
7637 var u = m.clone(), v = this.clone();
7638 var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
7639 while(u.signum() != 0) {
7640 while(u.isEven()) {
7641 u.rShiftTo(1,u);
7642 if(ac) {
7643 if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); }
7644 a.rShiftTo(1,a);
7645 }
7646 else if(!b.isEven()) b.subTo(m,b);
7647 b.rShiftTo(1,b);
7648 }
7649 while(v.isEven()) {
7650 v.rShiftTo(1,v);
7651 if(ac) {
7652 if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); }
7653 c.rShiftTo(1,c);
7654 }
7655 else if(!d.isEven()) d.subTo(m,d);
7656 d.rShiftTo(1,d);
7657 }
7658 if(u.compareTo(v) >= 0) {
7659 u.subTo(v,u);
7660 if(ac) a.subTo(c,a);
7661 b.subTo(d,b);
7662 }
7663 else {
7664 v.subTo(u,v);
7665 if(ac) c.subTo(a,c);
7666 d.subTo(b,d);
7667 }
7668 }
7669 if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
7670 if(d.compareTo(m) >= 0) return d.subtract(m);
7671 if(d.signum() < 0) d.addTo(m,d); else return d;
7672 if(d.signum() < 0) return d.add(m); else return d;
7673}
7674
7675var lowprimes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509];
7676var lplim = (1<<26)/lowprimes[lowprimes.length-1];
7677
7678// (public) test primality with certainty >= 1-.5^t
7679function bnIsProbablePrime(t) {
7680 var i, x = this.abs();
7681 if(x.t == 1 && x[0] <= lowprimes[lowprimes.length-1]) {
7682 for(i = 0; i < lowprimes.length; ++i)
7683 if(x[0] == lowprimes[i]) return true;
7684 return false;
7685 }
7686 if(x.isEven()) return false;
7687 i = 1;
7688 while(i < lowprimes.length) {
7689 var m = lowprimes[i], j = i+1;
7690 while(j < lowprimes.length && m < lplim) m *= lowprimes[j++];
7691 m = x.modInt(m);
7692 while(i < j) if(m%lowprimes[i++] == 0) return false;
7693 }
7694 return x.millerRabin(t);
7695}
7696
7697// (protected) true if probably prime (HAC 4.24, Miller-Rabin)
7698function bnpMillerRabin(t) {
7699 var n1 = this.subtract(BigInteger.ONE);
7700 var k = n1.getLowestSetBit();
7701 if(k <= 0) return false;
7702 var r = n1.shiftRight(k);
7703 t = (t+1)>>1;
7704 if(t > lowprimes.length) t = lowprimes.length;
7705 var a = nbi();
7706 for(var i = 0; i < t; ++i) {
7707 a.fromInt(lowprimes[i]);
7708 var y = a.modPow(r,this);
7709 if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {
7710 var j = 1;
7711 while(j++ < k && y.compareTo(n1) != 0) {
7712 y = y.modPowInt(2,this);
7713 if(y.compareTo(BigInteger.ONE) == 0) return false;
7714 }
7715 if(y.compareTo(n1) != 0) return false;
7716 }
7717 }
7718 return true;
7719}
7720
7721// protected
7722BigInteger.prototype.chunkSize = bnpChunkSize;
7723BigInteger.prototype.toRadix = bnpToRadix;
7724BigInteger.prototype.fromRadix = bnpFromRadix;
7725BigInteger.prototype.fromNumber = bnpFromNumber;
7726BigInteger.prototype.bitwiseTo = bnpBitwiseTo;
7727BigInteger.prototype.changeBit = bnpChangeBit;
7728BigInteger.prototype.addTo = bnpAddTo;
7729BigInteger.prototype.dMultiply = bnpDMultiply;
7730BigInteger.prototype.dAddOffset = bnpDAddOffset;
7731BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo;
7732BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo;
7733BigInteger.prototype.modInt = bnpModInt;
7734BigInteger.prototype.millerRabin = bnpMillerRabin;
7735
7736// public
7737BigInteger.prototype.clone = bnClone;
7738BigInteger.prototype.intValue = bnIntValue;
7739BigInteger.prototype.byteValue = bnByteValue;
7740BigInteger.prototype.shortValue = bnShortValue;
7741BigInteger.prototype.signum = bnSigNum;
7742BigInteger.prototype.toByteArray = bnToByteArray;
7743BigInteger.prototype.equals = bnEquals;
7744BigInteger.prototype.min = bnMin;
7745BigInteger.prototype.max = bnMax;
7746BigInteger.prototype.and = bnAnd;
7747BigInteger.prototype.or = bnOr;
7748BigInteger.prototype.xor = bnXor;
7749BigInteger.prototype.andNot = bnAndNot;
7750BigInteger.prototype.not = bnNot;
7751BigInteger.prototype.shiftLeft = bnShiftLeft;
7752BigInteger.prototype.shiftRight = bnShiftRight;
7753BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit;
7754BigInteger.prototype.bitCount = bnBitCount;
7755BigInteger.prototype.testBit = bnTestBit;
7756BigInteger.prototype.setBit = bnSetBit;
7757BigInteger.prototype.clearBit = bnClearBit;
7758BigInteger.prototype.flipBit = bnFlipBit;
7759BigInteger.prototype.add = bnAdd;
7760BigInteger.prototype.subtract = bnSubtract;
7761BigInteger.prototype.multiply = bnMultiply;
7762BigInteger.prototype.divide = bnDivide;
7763BigInteger.prototype.remainder = bnRemainder;
7764BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder;
7765BigInteger.prototype.modPow = bnModPow;
7766BigInteger.prototype.modInverse = bnModInverse;
7767BigInteger.prototype.pow = bnPow;
7768BigInteger.prototype.gcd = bnGCD;
7769BigInteger.prototype.isProbablePrime = bnIsProbablePrime;
7770
7771// BigInteger interfaces not implemented in jsbn:
7772
7773// BigInteger(int signum, byte[] magnitude)
7774// double doubleValue()
7775// float floatValue()
7776// int hashCode()
7777// long longValue()
7778// static BigInteger valueOf(long val)
Wentao Shangb42483a2013-01-03 15:32:32 -08007779/**
7780 * @author: Meki Cherkaoui, Jeff Thompson, Wentao Shang
7781 * See COPYING for copyright and distribution information.
7782 * This class represents the top-level object for communicating with an NDN host.
7783 */
7784
7785var LOG = 0;
7786
7787/**
7788 * settings is an associative array with the following defaults:
7789 * {
7790 * getTransport: function() { return new WebSocketTransport(); }
7791 * getHostAndPort: transport.defaultGetHostAndPort,
7792 * host: 'localhost', // If null, use getHostAndPort when connecting.
7793 * port: 9696,
7794 * onopen: function() { if (LOG > 3) console.log("NDN connection established."); }
7795 * onclose: function() { if (LOG > 3) console.log("NDN connection closed."); }
7796 * }
7797 *
7798 * getHostAndPort is a function, on each call it returns a new { host: host, port: port } or
7799 * null if there are no more hosts.
7800 */
7801var NDN = function NDN(settings) {
7802 settings = (settings || {});
7803 var getTransport = (settings.getTransport || function() { return new WebSocketTransport(); });
7804 this.transport = getTransport();
7805 this.getHostAndPort = (settings.getHostAndPort || this.transport.defaultGetHostAndPort);
7806 this.host = (settings.host !== undefined ? settings.host : 'localhost');
7807 this.port = (settings.port || 9696);
7808 this.readyStatus = NDN.UNOPEN;
7809 // Event handler
7810 this.onopen = (settings.onopen || function() { if (LOG > 3) console.log("NDN connection established."); });
7811 this.onclose = (settings.onclose || function() { if (LOG > 3) console.log("NDN connection closed."); });
7812};
7813
7814NDN.UNOPEN = 0; // created but not opened yet
7815NDN.OPENED = 1; // connection to ccnd opened
7816NDN.CLOSED = 2; // connection to ccnd closed
7817
7818NDN.ccndIdFetcher = new Name('/%C1.M.S.localhost/%C1.M.SRV/ccnd/KEY');
7819
7820NDN.prototype.createRoute = function(host, port) {
7821 this.host=host;
7822 this.port=port;
7823};
7824
7825
7826NDN.KeyStore = new Array();
7827
7828var KeyStoreEntry = function KeyStoreEntry(name, rsa, time) {
7829 this.keyName = name; // KeyName
7830 this.rsaKey = rsa; // RSA key
7831 this.timeStamp = time; // Time Stamp
7832};
7833
7834NDN.addKeyEntry = function(/* KeyStoreEntry */ keyEntry) {
7835 var result = NDN.getKeyByName(keyEntry.keyName);
7836 if (result == null)
7837 NDN.KeyStore.push(keyEntry);
7838 else
7839 result = keyEntry;
7840};
7841
7842NDN.getKeyByName = function(/* KeyName */ name) {
7843 var result = null;
7844
7845 for (var i = 0; i < NDN.KeyStore.length; i++) {
7846 if (NDN.KeyStore[i].keyName.contentName.match(name.contentName)) {
7847 if (result == null ||
7848 NDN.KeyStore[i].keyName.contentName.components.length > result.keyName.contentName.components.length)
7849 result = NDN.KeyStore[i];
7850 }
7851 }
7852
7853 return result;
7854};
7855
7856// For fetching data
7857NDN.PITTable = new Array();
7858
7859var PITEntry = function PITEntry(interest, closure) {
7860 this.interest = interest; // Interest
7861 this.closure = closure; // Closure
7862};
7863
7864// Return the longest entry from NDN.PITTable that matches name.
7865NDN.getEntryForExpressedInterest = function(/*Name*/ name) {
7866 // TODO: handle multiple matches? Maybe not from registerPrefix because multiple ContentObject
7867 // could be sent for one Interest?
7868 var result = null;
7869
7870 for (var i = 0; i < NDN.PITTable.length; i++) {
7871 if (NDN.PITTable[i].interest.matches_name(name)) {
7872 if (result == null ||
7873 NDN.PITTable[i].interest.name.components.length > result.interest.name.components.length)
7874 result = NDN.PITTable[i];
7875 }
7876 }
7877
7878 return result;
7879};
7880
7881/*
7882 * Return a function that selects a host at random from hostList and returns { host: host, port: port }.
7883 * If no more hosts remain, return null.
7884 */
7885NDN.makeShuffledGetHostAndPort = function(hostList, port) {
7886 // Make a copy.
7887 hostList = hostList.slice(0, hostList.length);
7888 DataUtils.shuffle(hostList);
7889
7890 return function() {
7891 if (hostList.length == 0)
7892 return null;
7893
7894 return { host: hostList.splice(0, 1)[0], port: port };
7895 };
7896};
7897
7898/** Encode name as an Interest. If template is not null, use its attributes.
7899 * Send the interest to host:port, read the entire response and call
7900 * closure.upcall(Closure.UPCALL_CONTENT (or Closure.UPCALL_CONTENT_UNVERIFIED),
7901 * new UpcallInfo(this, interest, 0, contentObject)).
7902 */
7903NDN.prototype.expressInterest = function(
7904 // Name
7905 name,
7906 // Closure
7907 closure,
7908 // Interest
7909 template) {
7910 var interest = new Interest(name);
7911 if (template != null) {
7912 interest.minSuffixComponents = template.minSuffixComponents;
7913 interest.maxSuffixComponents = template.maxSuffixComponents;
7914 interest.publisherPublicKeyDigest = template.publisherPublicKeyDigest;
7915 interest.exclude = template.exclude;
7916 interest.childSelector = template.childSelector;
7917 interest.answerOriginKind = template.answerOriginKind;
7918 interest.scope = template.scope;
7919 interest.interestLifetime = template.interestLifetime;
7920 }
7921 else
7922 interest.interestLifetime = 4000; // default interest timeout value in milliseconds.
7923
7924 if (this.host == null || this.port == null) {
7925 if (this.getHostAndPort == null)
7926 console.log('ERROR: host OR port NOT SET');
7927 else
7928 this.connectAndExpressInterest(interest, closure);
7929 }
7930 else
7931 this.transport.expressInterest(this, interest, closure);
7932};
7933
7934NDN.prototype.registerPrefix = function(name, closure, flag) {
7935 return this.transport.registerPrefix(this, name, closure, flag);
7936};
7937
7938/*
7939 * Assume this.getHostAndPort is not null. This is called when this.host is null or its host
7940 * is not alive. Get a host and port, connect, then express callerInterest with callerClosure.
7941 */
7942NDN.prototype.connectAndExpressInterest = function(callerInterest, callerClosure) {
7943 var hostAndPort = this.getHostAndPort();
7944 if (hostAndPort == null) {
7945 console.log('ERROR: No more hosts from getHostAndPort');
7946 this.host = null;
7947 return;
7948 }
7949
7950 if (hostAndPort.host == this.host && hostAndPort.port == this.port) {
7951 console.log('ERROR: The host returned by getHostAndPort is not alive: ' +
7952 this.host + ":" + this.port);
7953 return;
7954 }
7955
7956 this.host = hostAndPort.host;
7957 this.port = hostAndPort.port;
7958 console.log("Trying host from getHostAndPort: " + this.host);
7959
7960 // Fetch the ccndId.
7961 var interest = new Interest(new Name(NDN.ccndIdFetcher));
7962 interest.interestLifetime = 4000; // milliseconds
7963
7964 var thisNDN = this;
7965 var timerID = setTimeout(function() {
7966 console.log("Timeout waiting for host " + thisNDN.host);
7967 // Try again.
7968 thisNDN.connectAndExpressInterest(callerInterest, callerClosure);
7969 }, 3000);
7970
7971 this.transport.expressInterest
7972 (this, interest, new NDN.ConnectClosure(this, callerInterest, callerClosure, timerID));
7973};
7974
7975NDN.ConnectClosure = function ConnectClosure(ndn, callerInterest, callerClosure, timerID) {
7976 // Inherit from Closure.
7977 Closure.call(this);
7978
7979 this.ndn = ndn;
7980 this.callerInterest = callerInterest;
7981 this.callerClosure = callerClosure;
7982 this.timerID = timerID;
7983};
7984
7985NDN.ConnectClosure.prototype.upcall = function(kind, upcallInfo) {
7986 if (!(kind == Closure.UPCALL_CONTENT ||
7987 kind == Closure.UPCALL_CONTENT_UNVERIFIED ||
7988 kind == Closure.UPCALL_INTEREST))
7989 // The upcall is not for us.
7990 return Closure.RESULT_ERR;
7991
7992 // The host is alive, so cancel the timeout and issue the caller's interest.
7993 clearTimeout(this.timerID);
7994 console.log(this.ndn.host + ": Host is alive. Fetching callerInterest.");
7995 this.ndn.transport.expressInterest(this.ndn, this.callerInterest, this.callerClosure);
7996
7997 return Closure.RESULT_OK;
7998};
7999