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