diff --git a/src/js/sjcl/Makefile b/src/js/sjcl/Makefile
new file mode 100644
index 00000000..30515b25
--- /dev/null
+++ b/src/js/sjcl/Makefile
@@ -0,0 +1,96 @@
+JSDOCSTYLE= codeview
+JSDOCDIR= jsdoc_toolkit-2.3.3-beta
+JSDOC= $(JSDOCDIR)/jsrun.sh
+JSTEMPLATEDIR= $(JSDOCDIR)/templates/$(JSDOCSTYLE)/
+
+YUICOMPRESSOR= yuicompressor-2.4.2.jar
+
+include config.mk
+
+.PHONY: all test test_yui test_closure test_uncompressed lint compression_stats
+
+all: sjcl.js
+
+sjcl.js: $(COMPRESS)
+ cp $^ $@
+
+core.js: $(SOURCES) config.mk
+ cat $(SOURCES) > $@
+
+# compressed targets
+core_closure.js: core.js compress/compress_with_closure.sh compress/*.pl
+ compress/compress_with_closure.sh $< > $@
+
+core_yui.js: core.js compress/compress_with_yui.sh compress/*.pl
+ compress/compress_with_yui.sh $< > $@
+
+compression_stats: core.js core_closure.js core_yui.js
+ gzip -c core.js > core.js.gz
+ gzip -c core_yui.js > core_yui.js.gz
+ gzip -c core_closure.js > core_closure.js.gz
+
+ @echo
+ @echo
+ @echo Compression stats:
+ @echo
+ @wc -c core.js core_closure.js core_yui.js | head -n -1
+ @echo
+ @wc -c core*.js.gz | head -n -1
+ @echo
+ @echo
+
+ rm -f core*.js.gz
+
+doc: $(SOURCES)
+ rm -fr $@
+ JSDOCDIR=$(JSDOCDIR) $(JSDOC) -t=$(JSTEMPLATEDIR) $(SOURCES) -d=$@
+
+doc_private: $(SOURCES)
+ rm -fr $@
+ JSDOCDIR=$(JSDOCDIR) $(JSDOC) -t=$(JSTEMPLATEDIR) $(SOURCES) --private -d=$@
+
+lint: core.js core/*.js test/*.js browserTest/*.js lint/coding_guidelines.pl
+ rhino lint/jslint_rhino.js core.js
+ lint/coding_guidelines.pl core/*.js test/*.js browserTest/*.js
+
+
+TEST_COMMON= browserTest/rhinoUtil.js test/test.js
+
+TEST_SCRIPTS= $(TEST_COMMON) \
+ test/aes_vectors.js test/aes_test.js \
+ test/ocb2_vectors.js test/ocb2_test.js \
+ test/ccm_vectors.js test/ccm_test.js \
+ test/cbc_vectors.js test/cbc_test.js \
+ test/gcm_vectors.js test/gcm_test.js \
+ test/sha256_vectors.js test/sha256_test.js \
+ test/sha256_test_brute_force.js \
+ test/sha512_vectors.js test/sha512_test.js \
+ test/sha512_test_brute_force.js \
+ test/sha1_vectors.js test/sha1_test.js \
+ test/hmac_vectors.js test/hmac_test.js \
+ test/pbkdf2_test.js \
+ test/bn_vectors.js test/bn_test.js \
+ test/ecdsa_test.js test/ecdsa_vectors.js test/ecdh_test.js
+
+TEST_SCRIPTS_OPT= $(TEST_COMMON) \
+ test/srp_vectors.js test/srp_test.js
+
+# Rhino fails at -O 0. Probably because the big files full of test vectors blow the
+# bytecode limit. So, run most tests with -O -1. But modular exponentiation is
+# currently very slow (on Rhino), so run the SRP test with optimizations on.
+
+test: sjcl.js $(TEST_SCRIPTS) test/run_tests_rhino.js
+ @rhino -O -1 -w test/run_tests_rhino.js $< $(TEST_SCRIPTS)
+ @rhino -O 9 -w test/run_tests_rhino.js $< $(TEST_SCRIPTS_OPT)
+
+tidy:
+ find . -name '*~' -delete
+ rm -f core.js core_*.js
+
+clean: tidy
+ rm -fr sjcl.js doc doc_private
+
+distclean: clean
+ ./configure
+ make sjcl.js tidy
+
diff --git a/src/js/sjcl/README/COPYRIGHT b/src/js/sjcl/README/COPYRIGHT
new file mode 100644
index 00000000..d573a057
--- /dev/null
+++ b/src/js/sjcl/README/COPYRIGHT
@@ -0,0 +1,32 @@
+SJCL used to be in the public domain. Now it's:
+
+Copyright 2009-2010 Emily Stark, Mike Hamburg, Dan Boneh, Stanford University.
+
+This is for liability reasons. (Speaking of which, SJCL comes with NO
+WARRANTY WHATSOEVER, express or implied, to the limit of applicable
+law.)
+
+SJCL is dual-licensed under the GNU GPL version 2.0 or higher, and a
+2-clause BSD license. You may use SJCL under the terms of either of
+these licenses. For your convenience, the GPL versions 2.0 and 3.0
+and the 2-clause BSD license are included here. Additionally, you may
+serve "crunched" copies of sjcl (i.e. those with comments removed,
+and other transformations to reduce code size) without any copyright
+notice.
+
+SJCL includes JsDoc toolkit, YUI compressor, Closure compressor,
+JSLint and the CodeView template in its build system. These programs'
+copyrights are owned by other people. They are distributed here under
+the MPL, MIT, BSD, Apache and JSLint licenses. Codeview is "free for
+download" but has no license attached; it is Copyright 2010 Wouter Bos.
+
+The BSD license is (almost?) strictly more permissive, but the
+additionally licensing under the GPL allows us to use OCB 2.0 code
+royalty-free (at least, if OCB 2.0's creator Phil Rogaway has anything
+to say about it). Note that if you redistribute SJCL under a license
+other than the GPL, you or your users may need to pay patent licensing
+fees for OCB 2.0.
+
+There may be patents which apply to SJCL other than Phil Rogaway's OCB
+patents. We suggest that you consult legal counsel before using SJCL
+in a commercial project.
diff --git a/src/js/sjcl/README/INSTALL b/src/js/sjcl/README/INSTALL
new file mode 100644
index 00000000..a5898c40
--- /dev/null
+++ b/src/js/sjcl/README/INSTALL
@@ -0,0 +1,36 @@
+SJCL comes with a file sjcl.js pre-built. This default build includes
+all the modules except for sjcl.codec.bytes (because the demo site doesn't
+use it). All you need to do to install is copy this file to your web
+server and start using it.
+
+SJCL is divided into modules implementing various cryptographic and
+convenience functions. If you don't need them all for your application,
+you can reconfigure SJCL for a smaller code size. To do this, you can
+run
+
+./configure --without-all --with-aes --with-sha256 ...
+
+Then type
+
+make
+
+to rebuild sjcl.js. This will also create a few intermediate files
+core*.js; you can delete these automatically by typing
+
+make sjcl.js tidy
+
+instead. You will need make, perl, bash and java to rebuild SJCL.
+
+Some of the modules depend on other modules; configure should handle this
+automatically unless you tell it --without-FOO --with-BAR, where BAR
+depends on FOO. If you do this, configure will yell at you.
+
+SJCL is compressed by stripping comments, shortening variable names, etc.
+You can also pass a --compress argument to configure to change the
+compressor. By default SJCL uses some perl/sh scripts and Google's
+Closure compressor.
+
+If you reconfigure SJCL, it is recommended that you run the included test
+suite by typing "make test". If this prints "FAIL" or segfaults, SJCL
+doesn't work; please file a bug.
+
diff --git a/src/js/sjcl/README/bsd.txt b/src/js/sjcl/README/bsd.txt
new file mode 100644
index 00000000..a0559ed0
--- /dev/null
+++ b/src/js/sjcl/README/bsd.txt
@@ -0,0 +1,30 @@
+Copyright 2009-2010 Emily Stark, Mike Hamburg, Dan Boneh.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation
+are those of the authors and should not be interpreted as representing
+official policies, either expressed or implied, of the authors.
diff --git a/src/js/sjcl/README/gpl-2.0.txt b/src/js/sjcl/README/gpl-2.0.txt
new file mode 100644
index 00000000..d159169d
--- /dev/null
+++ b/src/js/sjcl/README/gpl-2.0.txt
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ , 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/src/js/sjcl/README/gpl-3.0.txt b/src/js/sjcl/README/gpl-3.0.txt
new file mode 100644
index 00000000..94a9ed02
--- /dev/null
+++ b/src/js/sjcl/README/gpl-3.0.txt
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/src/js/sjcl/browserTest/browserTest.html b/src/js/sjcl/browserTest/browserTest.html
new file mode 100644
index 00000000..be8d5348
--- /dev/null
+++ b/src/js/sjcl/browserTest/browserTest.html
@@ -0,0 +1,16 @@
+
+
+
+
+ SJCL browser test
+
+
+
+
+
+
SJCL browser test
+
Waiting for tests to begin...
+
+
+
diff --git a/src/js/sjcl/browserTest/browserUtil.js b/src/js/sjcl/browserTest/browserUtil.js
new file mode 100644
index 00000000..9c23d01f
--- /dev/null
+++ b/src/js/sjcl/browserTest/browserUtil.js
@@ -0,0 +1,133 @@
+browserUtil = {};
+
+browserUtil.isRhino = (typeof(window) === 'undefined');
+
+/**
+ * Pause (for the graphics to update and the script timer to clear), then run the
+ * specified action.
+ */
+browserUtil.pauseAndThen = function (cb) {
+ cb && window.setTimeout(cb, 1);
+};
+
+/**
+ * Iterate using continuation-passing style.
+ */
+browserUtil.cpsIterate = function (f, start, end, pause, callback) {
+ var pat = pause ? browserUtil.pauseAndThen : function (cb) { cb && cb(); };
+ function go() {
+ var called = false;
+ if (start >= end) {
+ pat(callback);
+ } else {
+ pat(function () { f(start, function () {
+ if (!called) { called = true; start++; go(); }
+ }); });
+ }
+ }
+ go (start);
+};
+
+/**
+ * Map a function over an array using continuation-passing style.
+ */
+browserUtil.cpsMap = function (map, list, pause, callback) {
+ browserUtil.cpsIterate(function (i, cb) { map(list[i], i, list.length, cb); },
+ 0, list.length, pause, callback);
+}
+
+/** Cache for remotely loaded scripts. */
+browserUtil.scriptCache = {}
+
+/** Load several scripts, then call back */
+browserUtil.loadScripts = function(scriptNames, cbSuccess, cbError) {
+ var head = document.getElementsByTagName('head')[0];
+ browserUtil.cpsMap(function (script, i, n, cb) {
+ var scriptE = document.createElement('script'), xhr, loaded = false;
+
+ browserUtil.status("Loading script " + script);
+
+ if (window.location.protocol === "file:") {
+ /* Can't make an AJAX request for files.
+ * But, we know the load time will be short, so timeout-based error
+ * detection is fine.
+ */
+ scriptE.onload = function () {
+ loaded = true;
+ cb();
+ };
+ scriptE.onerror = function(err) {
+ cbError && cbError(script, err, cb);
+ };
+ script.onreadystatechange = function() {
+ if (this.readyState == 'complete' || this.readyState == 'loaded') {
+ loaded = true;
+ cb();
+ }
+ };
+ scriptE.type = 'text/javascript';
+ scriptE.src = script+"?"+(new Date().valueOf());
+ window.setTimeout(function () {
+ loaded || cbError && cbError(script, "timeout expired", cb);
+ }, 100);
+ head.appendChild(scriptE);
+ } else if (browserUtil.scriptCache[script] !== undefined) {
+ try {
+ scriptE.appendChild(document.createTextNode(browserUtil.scriptCache[script]));
+ } catch (e) {
+ scriptE.text = browserUtil.scriptCache[script];
+ }
+ head.appendChild(scriptE);
+ cb();
+ } else {
+ var xhr;
+ if (window.XMLHttpRequest) {
+ xhr = new XMLHttpRequest;
+ } else if (window.ActiveXObject) {
+ xhr = new ActiveXObject("Microsoft.XMLHTTP");
+ }
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ if (xhr.status == 200) {
+ browserUtil.scriptCache[script] = xhr.responseText;
+ try {
+ scriptE.appendChild(document.createTextNode(xhr.responseText));
+ } catch (e) {
+ scriptE.text = xhr.responseText;
+ }
+ head.appendChild(scriptE);
+ cb();
+ } else {
+ cbError && cbError(script, xhr.status, cb);
+ }
+ }
+ }
+ xhr.open("GET", script+"?"+(new Date().valueOf()), true);
+ xhr.send();
+ }
+ }, scriptNames, false, cbSuccess);
+};
+
+/** Write a message to the console */
+browserUtil.write = function(type, message) {
+ var d1 = document.getElementById("print"), d2 = document.createElement("div"), d3 = document.createElement("div");
+ d3.className = type;
+ d3.appendChild(document.createTextNode(message));
+ d2.appendChild(d3);
+ d1.appendChild(d2);
+ return { update: function (type2, message2) {
+ var d4 = document.createElement("div");
+ d4.className = type2 + " also";
+ d4.appendChild(document.createTextNode(message2));
+ d2.insertBefore(d4, d3);
+ }};
+};
+
+/** Write a newline. Does nothing in the browser. */
+browserUtil.writeNewline = function () { };
+
+/** Write a message to the status line */
+browserUtil.status = function(message) {
+ var d1 = document.getElementById("status");
+ d1.replaceChild(document.createTextNode(message), d1.firstChild);
+};
diff --git a/src/js/sjcl/browserTest/rhinoUtil.js b/src/js/sjcl/browserTest/rhinoUtil.js
new file mode 100644
index 00000000..3107104d
--- /dev/null
+++ b/src/js/sjcl/browserTest/rhinoUtil.js
@@ -0,0 +1,44 @@
+browserUtil = {
+ isRhino: true,
+
+ pauseAndThen: function (cb) { cb(); },
+
+ cpsIterate: function (f, start, end, pause, callback) {
+ function go() {
+ var called = false;
+ if (start >= end) {
+ callback && callback();
+ } else {
+ f(start, function () {
+ if (!called) { called = true; start++; go(); }
+ });
+ }
+ }
+ go (start);
+ },
+
+ cpsMap: function (map, list, pause, callback) {
+ browserUtil.cpsIterate(function (i, cb) { map(list[i], i, list.length, cb); },
+ 0, list.length, pause, callback);
+ },
+
+ loadScripts: function(scriptNames, callback) {
+ for (i=0; i .begin, *+* > .all {
+ margin-top: 1em;
+}
+
+.also {
+ float: right;
+ width: 17em;
+ text-align: right;
+}
+
+h1 {
+ text-align: center;
+ background: #8A0000;
+ padding: 5px;
+ color: white;
+}
+
+#status {
+ padding: 3px 10px 3px 5px;
+ background: #d5c490;
+ color: #444;
+ font-size: 0.8em;
+ margin-bottom: 1em;
+ height: 1.3em;
+ vertical-align: middle;
+}
diff --git a/src/js/sjcl/component.json b/src/js/sjcl/component.json
new file mode 100644
index 00000000..5fde069a
--- /dev/null
+++ b/src/js/sjcl/component.json
@@ -0,0 +1,5 @@
+{
+ "name": "sjcl",
+ "version": "1.0.0",
+ "main": ["./sjcl.js"]
+}
diff --git a/src/js/sjcl/compress/compiler.jar b/src/js/sjcl/compress/compiler.jar
new file mode 100644
index 00000000..e2338676
Binary files /dev/null and b/src/js/sjcl/compress/compiler.jar differ
diff --git a/src/js/sjcl/compress/compress_with_closure.sh b/src/js/sjcl/compress/compress_with_closure.sh
new file mode 100755
index 00000000..07985c87
--- /dev/null
+++ b/src/js/sjcl/compress/compress_with_closure.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+DIR=`dirname $0`
+
+$DIR/remove_constants.pl $1 | $DIR/opacify.pl > ._tmpRC.js
+
+echo -n '"use strict";'
+java -jar $DIR/compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS \
+ --js ._tmpRC.js \
+ | $DIR/digitize.pl \
+ | $DIR/dewindowize.pl
+
+
+rm -f ._tmpRC.js
+
diff --git a/src/js/sjcl/compress/compress_with_yui.sh b/src/js/sjcl/compress/compress_with_yui.sh
new file mode 100755
index 00000000..9dfecdac
--- /dev/null
+++ b/src/js/sjcl/compress/compress_with_yui.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# Compress $1 with YUI Compressor 2.4.2, returning the compressed script on stdout
+
+DIR=`dirname $0`
+
+$DIR/remove_constants.pl $1 > ._tmpRC.js
+
+java -jar $DIR/yuicompressor-2.4.2.jar ._tmpRC.js \
+ | $DIR/digitize.pl
+
+rm -f ._tmpRC.js
+
diff --git a/src/js/sjcl/compress/dewindowize.pl b/src/js/sjcl/compress/dewindowize.pl
new file mode 100755
index 00000000..c8843825
--- /dev/null
+++ b/src/js/sjcl/compress/dewindowize.pl
@@ -0,0 +1,8 @@
+#!/usr/bin/env perl
+
+while (<>) {
+ s/window\.sjcl\s*=/var sjcl=/g;
+ s/window\.sjcl/sjcl/g;
+ print;
+}
+
diff --git a/src/js/sjcl/compress/digitize.pl b/src/js/sjcl/compress/digitize.pl
new file mode 100755
index 00000000..e8a01404
--- /dev/null
+++ b/src/js/sjcl/compress/digitize.pl
@@ -0,0 +1,22 @@
+#!/usr/bin/env perl
+
+# Convert numbers to hex, when doing so is likely to increase compressibility.
+# This actually makes the script slightly longer, but generally makes it compress
+# to something shorter.
+#
+# Here we're targeting constants like 0xFF, 0xFFFF0000, 0x10101, 0x100000000, etc.
+
+sub digitize {
+ my $number = shift;
+ if ($number >= 256) {
+ my $nn = `printf "%x" $number`;
+ if ($nn =~ /^[01f]+$/i) { return "0x$nn"; }
+ }
+ return $number;
+}
+
+while (<>) {
+ s/([^a-zA-Z0-9_])(\d+)/$1 . digitize $2/eg;
+ print;
+}
+
diff --git a/src/js/sjcl/compress/opacify.pl b/src/js/sjcl/compress/opacify.pl
new file mode 100755
index 00000000..4d76a752
--- /dev/null
+++ b/src/js/sjcl/compress/opacify.pl
@@ -0,0 +1,39 @@
+#!/usr/bin/env perl
+
+# This script is a hack.
+#
+# Opacify all non-private names by turning them into strings.
+# That way, the Google compressor won't rename them.
+#
+# The script ignores properties whose names begin with _, because they
+# are believed to be private.
+#
+# XXX TODO FIXME: this messes with strings, so it screws up exceptions.
+
+my $script = join '', <>;
+
+# remove comments
+#$script =~ s=/\*([^\*]|\*+[^\/])*\*/==g;
+#$script =~ s=//.*==g;
+
+# stringify property names
+$script =~ s=\.([a-zA-Z][_a-zA-Z0-9]*)=['$1']=g;
+
+# destringify 'prototype'
+$script =~ s=\['prototype'\]=.prototype=g;
+
+# stringify sjcl
+$script =~ s=(?:var\s+)?sjcl(\.|\s*\=)=window['sjcl']$1=g;
+
+# stringify object notation
+$script =~ s=([\{,]
+ \s*
+ (?:/\*(?:[^\*]|\*+[^\/])*\*/\s* # preserve C-style comments
+ |//[^\n]*\n\s*)*)
+ ([a-zA-Z0-9][_a-zA-Z0-9]*):=$1'$2':=xg;
+
+# Export sjcl. This is a bit of a hack, and might get replaced later.
+print $script;
+
+# not necessary with windowization.
+# print "window\['sjcl'\] = sjcl;\n";
diff --git a/src/js/sjcl/compress/remove_constants.pl b/src/js/sjcl/compress/remove_constants.pl
new file mode 100755
index 00000000..73aee057
--- /dev/null
+++ b/src/js/sjcl/compress/remove_constants.pl
@@ -0,0 +1,69 @@
+#!/usr/bin/env perl
+
+# This script is a hack. It identifies things which it believes to be
+# constant, then replaces them throughout the code.
+#
+# Constants are identified as properties declared in object notation
+# with values consisting only of capital letters and underscores. If
+# the first character is an underscore, the constant is private, and
+# can be removed entirely.
+#
+# The script dies if any two constants have the same property name but
+# different values.
+my $script = join '', <>;
+
+# remove comments
+#$script =~ s=/\*([^\*]|\*+[^\/])*\*/==g;
+#$script =~ s=//.*==g;
+
+sub preserve {
+ my $stuff = shift;
+ $stuff =~ s/,//;
+ return $stuff;
+}
+
+my %constants = ();
+
+sub add_constant {
+ my ($name, $value) = @_;
+ if (defined $constants{$name} && $constants{$name} ne $value) {
+ print STDERR "variant constant $name = $value";
+ die;
+ } else {
+ $constants{$name} = $value;
+ #print STDERR "constant: $name = $value\n";
+ }
+}
+
+# find private constants
+while ($script =~
+ s/([,\{]) \s* # indicator that this is part of an object
+ (_[A-Z0-9_]+) \s* : \s* # all-caps variable name beginning with _
+ (\d+|0x[0-9A-Fa-f]+) \s* # numeric value
+ ([,\}]) # next part of object
+ /preserve "$1$4"/ex) {
+ add_constant $2, $3;
+}
+
+my $script2 = '';
+
+# find public constants
+while ($script =~
+ s/^(.*?) # beginning of script
+ ([,\{]) \s* # indicator that this is part of an object
+ ([A-Z0-9_]+) \s* : \s* # all-caps variable name
+ (\d+|0x[0-9A-Fa-f]+) \s* # numeric value
+ ([,\}]) # next part of object([,\{]) \s*
+ /$5/esx) {
+ $script2 .= "$1$2$3:$4";
+ add_constant $3, $4;
+}
+
+$script = "$script2$script";
+
+foreach (keys %constants) {
+ my $value = $constants{$_};
+ $script =~ s/(?:[a-zA-Z0-9_]+\.)+$_(?=[^a-zA-Z0-9_])/$value/g;
+}
+
+print $script;
diff --git a/src/js/sjcl/compress/yuicompressor-2.4.2.jar b/src/js/sjcl/compress/yuicompressor-2.4.2.jar
new file mode 100644
index 00000000..c29470bd
Binary files /dev/null and b/src/js/sjcl/compress/yuicompressor-2.4.2.jar differ
diff --git a/src/js/sjcl/config.mk b/src/js/sjcl/config.mk
new file mode 100644
index 00000000..ca76e339
--- /dev/null
+++ b/src/js/sjcl/config.mk
@@ -0,0 +1,2 @@
+SOURCES= core/sjcl.js core/aes.js core/bitArray.js core/codecString.js core/codecHex.js core/codecBase64.js core/sha256.js core/ccm.js core/ocb2.js core/gcm.js core/hmac.js core/pbkdf2.js core/random.js core/convenience.js
+COMPRESS= core_closure.js
diff --git a/src/js/sjcl/configure b/src/js/sjcl/configure
new file mode 100755
index 00000000..f5465cdc
--- /dev/null
+++ b/src/js/sjcl/configure
@@ -0,0 +1,143 @@
+#!/usr/bin/env perl
+
+use strict;
+
+my ($arg, $i, $j, $targ);
+
+my @targets = qw/sjcl aes bitArray codecString codecHex codecBase64 codecBytes sha256 sha512 sha1 ccm cbc ocb2 gcm hmac pbkdf2 random convenience bn ecc srp/;
+my %deps = ('aes'=>'sjcl',
+ 'bitArray'=>'sjcl',
+ 'codecString'=>'bitArray',
+ 'codecHex'=>'bitArray',
+ 'codecBase64'=>'bitArray',
+ 'codecBytes'=>'bitArray',
+ 'sha256'=>'codecString',
+ 'sha512'=>'codecString',
+ 'sha1'=>'codecString',
+ 'ccm'=>'bitArray,aes',
+ 'ocb2'=>'bitArray,aes',
+ 'gcm'=>'bitArray,aes',
+ 'hmac'=>'sha256',
+ 'pbkdf2'=>'hmac',
+ 'srp'=>'sha1,bn,bitArray',
+ 'bn'=>'bitArray,random',
+ 'ecc'=>'bn',
+ 'cbc'=>'bitArray,aes',
+ 'random'=>'sha256,aes',
+ 'convenience'=>'ccm,pbkdf2,random,codecBase64');
+
+my $compress = "closure";
+
+my %enabled = ();
+$enabled{$_} = 0 foreach (@targets);
+
+# by default, all but codecBytes, srp, bn
+$enabled{$_} = 1 foreach (qw/aes bitArray codecString codecHex codecBase64 sha256 ccm ocb2 gcm hmac pbkdf2 random convenience/);
+
+# argument parsing
+while ($arg = shift @ARGV) {
+ if ($arg =~ /^--?with-all$/) {
+ foreach (@targets) {
+ if ($enabled{$_} == 0) {
+ $enabled{$_} = 1;
+ }
+ }
+ } elsif ($arg =~ /^--?without-all$/) {
+ foreach (@targets) {
+ if ($enabled{$_} == 1) {
+ $enabled{$_} = 0;
+ }
+ }
+ } elsif ($arg =~ /^--?with-(.*)$/) {
+ $targ = $1;
+ $targ =~ s/-(.)/uc $1/ge;
+ if (!defined $deps{$targ}) {
+ print STDERR "No such target $targ\n";
+ exit 1;
+ }
+ $enabled{$targ} = 2;
+ } elsif ($arg =~ /^--?without-(.*)$/) {
+ $targ = $1;
+ $targ =~ s/-(.)/uc $1/ge;
+ if (!defined $deps{$targ}) {
+ print STDERR "No such target $targ\n";
+ exit 1;
+ }
+ $enabled{$targ} = -1;
+ } elsif ($arg =~ /^--?compress(?:or|ion)?=(none|closure|yui)$/) {
+ $compress = $1;
+ } else {
+ my $targets = join " ", @targets;
+ $targets =~ s/sjcl //;
+ $targets =~ s/(.{50})\s+/$1\n /g;
+ print STDERR < 0) {
+ foreach $j (split /,/, $deps{$i}) {
+ if ($enabled{$j} == -1) {
+ if ($enabled{$i} == 2) {
+ print STDERR "Conflicting options: $i depends on $j\n";
+ exit 1;
+ } else {
+ $enabled{$i} = -1;
+ last;
+ }
+ }
+ }
+ }
+}
+
+# reverse
+foreach $i (reverse @targets) {
+ if ($enabled{$i} > 0) {
+ foreach $j (split /,/, $deps{$i}) {
+ if ($enabled{$j} < $enabled{$i}) {
+ $enabled{$j} = $enabled{$i};
+ }
+ }
+ $config = "$i $config";
+ }
+}
+
+open CONFIG, "> config.mk" or die "$!";
+
+
+($pconfig = $config) =~ s/^sjcl //;
+$pconfig =~ s/ /\n /g;
+print "Enabled components:\n $pconfig\n";
+print "Compression: $compress\n";
+
+$config =~ s=\S+=core/$&.js=g;
+print CONFIG "SOURCES= $config\n";
+
+$compress = "core_$compress.js";
+$compress = 'core.js' if ($compress eq 'core_none.js');
+
+print CONFIG "COMPRESS= $compress\n";
+
diff --git a/src/js/sjcl/core/aes.js b/src/js/sjcl/core/aes.js
new file mode 100644
index 00000000..144cd248
--- /dev/null
+++ b/src/js/sjcl/core/aes.js
@@ -0,0 +1,208 @@
+/** @fileOverview Low-level AES implementation.
+ *
+ * This file contains a low-level implementation of AES, optimized for
+ * size and for efficiency on several browsers. It is based on
+ * OpenSSL's aes_core.c, a public-domain implementation by Vincent
+ * Rijmen, Antoon Bosselaers and Paulo Barreto.
+ *
+ * An older version of this implementation is available in the public
+ * domain, but this one is (c) Emily Stark, Mike Hamburg, Dan Boneh,
+ * Stanford University 2008-2010 and BSD-licensed for liability
+ * reasons.
+ *
+ * @author Emily Stark
+ * @author Mike Hamburg
+ * @author Dan Boneh
+ */
+
+/**
+ * Schedule out an AES key for both encryption and decryption. This
+ * is a low-level class. Use a cipher mode to do bulk encryption.
+ *
+ * @constructor
+ * @param {Array} key The key as an array of 4, 6 or 8 words.
+ *
+ * @class Advanced Encryption Standard (low-level interface)
+ */
+sjcl.cipher.aes = function (key) {
+ if (!this._tables[0][0][0]) {
+ this._precompute();
+ }
+
+ var i, j, tmp,
+ encKey, decKey,
+ sbox = this._tables[0][4], decTable = this._tables[1],
+ keyLen = key.length, rcon = 1;
+
+ if (keyLen !== 4 && keyLen !== 6 && keyLen !== 8) {
+ throw new sjcl.exception.invalid("invalid aes key size");
+ }
+
+ this._key = [encKey = key.slice(0), decKey = []];
+
+ // schedule encryption keys
+ for (i = keyLen; i < 4 * keyLen + 28; i++) {
+ tmp = encKey[i-1];
+
+ // apply sbox
+ if (i%keyLen === 0 || (keyLen === 8 && i%keyLen === 4)) {
+ tmp = sbox[tmp>>>24]<<24 ^ sbox[tmp>>16&255]<<16 ^ sbox[tmp>>8&255]<<8 ^ sbox[tmp&255];
+
+ // shift rows and add rcon
+ if (i%keyLen === 0) {
+ tmp = tmp<<8 ^ tmp>>>24 ^ rcon<<24;
+ rcon = rcon<<1 ^ (rcon>>7)*283;
+ }
+ }
+
+ encKey[i] = encKey[i-keyLen] ^ tmp;
+ }
+
+ // schedule decryption keys
+ for (j = 0; i; j++, i--) {
+ tmp = encKey[j&3 ? i : i - 4];
+ if (i<=4 || j<4) {
+ decKey[j] = tmp;
+ } else {
+ decKey[j] = decTable[0][sbox[tmp>>>24 ]] ^
+ decTable[1][sbox[tmp>>16 & 255]] ^
+ decTable[2][sbox[tmp>>8 & 255]] ^
+ decTable[3][sbox[tmp & 255]];
+ }
+ }
+};
+
+sjcl.cipher.aes.prototype = {
+ // public
+ /* Something like this might appear here eventually
+ name: "AES",
+ blockSize: 4,
+ keySizes: [4,6,8],
+ */
+
+ /**
+ * Encrypt an array of 4 big-endian words.
+ * @param {Array} data The plaintext.
+ * @return {Array} The ciphertext.
+ */
+ encrypt:function (data) { return this._crypt(data,0); },
+
+ /**
+ * Decrypt an array of 4 big-endian words.
+ * @param {Array} data The ciphertext.
+ * @return {Array} The plaintext.
+ */
+ decrypt:function (data) { return this._crypt(data,1); },
+
+ /**
+ * The expanded S-box and inverse S-box tables. These will be computed
+ * on the client so that we don't have to send them down the wire.
+ *
+ * There are two tables, _tables[0] is for encryption and
+ * _tables[1] is for decryption.
+ *
+ * The first 4 sub-tables are the expanded S-box with MixColumns. The
+ * last (_tables[01][4]) is the S-box itself.
+ *
+ * @private
+ */
+ _tables: [[[],[],[],[],[]],[[],[],[],[],[]]],
+
+ /**
+ * Expand the S-box tables.
+ *
+ * @private
+ */
+ _precompute: function () {
+ var encTable = this._tables[0], decTable = this._tables[1],
+ sbox = encTable[4], sboxInv = decTable[4],
+ i, x, xInv, d=[], th=[], x2, x4, x8, s, tEnc, tDec;
+
+ // Compute double and third tables
+ for (i = 0; i < 256; i++) {
+ th[( d[i] = i<<1 ^ (i>>7)*283 )^i]=i;
+ }
+
+ for (x = xInv = 0; !sbox[x]; x ^= x2 || 1, xInv = th[xInv] || 1) {
+ // Compute sbox
+ s = xInv ^ xInv<<1 ^ xInv<<2 ^ xInv<<3 ^ xInv<<4;
+ s = s>>8 ^ s&255 ^ 99;
+ sbox[x] = s;
+ sboxInv[s] = x;
+
+ // Compute MixColumns
+ x8 = d[x4 = d[x2 = d[x]]];
+ tDec = x8*0x1010101 ^ x4*0x10001 ^ x2*0x101 ^ x*0x1010100;
+ tEnc = d[s]*0x101 ^ s*0x1010100;
+
+ for (i = 0; i < 4; i++) {
+ encTable[i][x] = tEnc = tEnc<<24 ^ tEnc>>>8;
+ decTable[i][s] = tDec = tDec<<24 ^ tDec>>>8;
+ }
+ }
+
+ // Compactify. Considerable speedup on Firefox.
+ for (i = 0; i < 5; i++) {
+ encTable[i] = encTable[i].slice(0);
+ decTable[i] = decTable[i].slice(0);
+ }
+ },
+
+ /**
+ * Encryption and decryption core.
+ * @param {Array} input Four words to be encrypted or decrypted.
+ * @param dir The direction, 0 for encrypt and 1 for decrypt.
+ * @return {Array} The four encrypted or decrypted words.
+ * @private
+ */
+ _crypt:function (input, dir) {
+ if (input.length !== 4) {
+ throw new sjcl.exception.invalid("invalid aes block size");
+ }
+
+ var key = this._key[dir],
+ // state variables a,b,c,d are loaded with pre-whitened data
+ a = input[0] ^ key[0],
+ b = input[dir ? 3 : 1] ^ key[1],
+ c = input[2] ^ key[2],
+ d = input[dir ? 1 : 3] ^ key[3],
+ a2, b2, c2,
+
+ nInnerRounds = key.length/4 - 2,
+ i,
+ kIndex = 4,
+ out = [0,0,0,0],
+ table = this._tables[dir],
+
+ // load up the tables
+ t0 = table[0],
+ t1 = table[1],
+ t2 = table[2],
+ t3 = table[3],
+ sbox = table[4];
+
+ // Inner rounds. Cribbed from OpenSSL.
+ for (i = 0; i < nInnerRounds; i++) {
+ a2 = t0[a>>>24] ^ t1[b>>16 & 255] ^ t2[c>>8 & 255] ^ t3[d & 255] ^ key[kIndex];
+ b2 = t0[b>>>24] ^ t1[c>>16 & 255] ^ t2[d>>8 & 255] ^ t3[a & 255] ^ key[kIndex + 1];
+ c2 = t0[c>>>24] ^ t1[d>>16 & 255] ^ t2[a>>8 & 255] ^ t3[b & 255] ^ key[kIndex + 2];
+ d = t0[d>>>24] ^ t1[a>>16 & 255] ^ t2[b>>8 & 255] ^ t3[c & 255] ^ key[kIndex + 3];
+ kIndex += 4;
+ a=a2; b=b2; c=c2;
+ }
+
+ // Last round.
+ for (i = 0; i < 4; i++) {
+ out[dir ? 3&-i : i] =
+ sbox[a>>>24 ]<<24 ^
+ sbox[b>>16 & 255]<<16 ^
+ sbox[c>>8 & 255]<<8 ^
+ sbox[d & 255] ^
+ key[kIndex++];
+ a2=a; a=b; b=c; c=d; d=a2;
+ }
+
+ return out;
+ }
+};
+
diff --git a/src/js/sjcl/core/bitArray.js b/src/js/sjcl/core/bitArray.js
new file mode 100644
index 00000000..a6d06171
--- /dev/null
+++ b/src/js/sjcl/core/bitArray.js
@@ -0,0 +1,187 @@
+/** @fileOverview Arrays of bits, encoded as arrays of Numbers.
+ *
+ * @author Emily Stark
+ * @author Mike Hamburg
+ * @author Dan Boneh
+ */
+
+/** @namespace Arrays of bits, encoded as arrays of Numbers.
+ *
+ * @description
+ *
+ * These objects are the currency accepted by SJCL's crypto functions.
+ *
+ *
+ *
+ * Most of our crypto primitives operate on arrays of 4-byte words internally,
+ * but many of them can take arguments that are not a multiple of 4 bytes.
+ * This library encodes arrays of bits (whose size need not be a multiple of 8
+ * bits) as arrays of 32-bit words. The bits are packed, big-endian, into an
+ * array of words, 32 bits at a time. Since the words are double-precision
+ * floating point numbers, they fit some extra data. We use this (in a private,
+ * possibly-changing manner) to encode the number of bits actually present
+ * in the last word of the array.
+ *
+ *
+ *
+ * Because bitwise ops clear this out-of-band data, these arrays can be passed
+ * to ciphers like AES which want arrays of words.
+ *
+ */
+sjcl.bitArray = {
+ /**
+ * Array slices in units of bits.
+ * @param {bitArray} a The array to slice.
+ * @param {Number} bstart The offset to the start of the slice, in bits.
+ * @param {Number} bend The offset to the end of the slice, in bits. If this is undefined,
+ * slice until the end of the array.
+ * @return {bitArray} The requested slice.
+ */
+ bitSlice: function (a, bstart, bend) {
+ a = sjcl.bitArray._shiftRight(a.slice(bstart/32), 32 - (bstart & 31)).slice(1);
+ return (bend === undefined) ? a : sjcl.bitArray.clamp(a, bend-bstart);
+ },
+
+ /**
+ * Extract a number packed into a bit array.
+ * @param {bitArray} a The array to slice.
+ * @param {Number} bstart The offset to the start of the slice, in bits.
+ * @param {Number} length The length of the number to extract.
+ * @return {Number} The requested slice.
+ */
+ extract: function(a, bstart, blength) {
+ // FIXME: this Math.floor is not necessary at all, but for some reason
+ // seems to suppress a bug in the Chromium JIT.
+ var x, sh = Math.floor((-bstart-blength) & 31);
+ if ((bstart + blength - 1 ^ bstart) & -32) {
+ // it crosses a boundary
+ x = (a[bstart/32|0] << (32 - sh)) ^ (a[bstart/32+1|0] >>> sh);
+ } else {
+ // within a single word
+ x = a[bstart/32|0] >>> sh;
+ }
+ return x & ((1< 0 && len) {
+ a[l-1] = sjcl.bitArray.partial(len, a[l-1] & 0x80000000 >> (len-1), 1);
+ }
+ return a;
+ },
+
+ /**
+ * Make a partial word for a bit array.
+ * @param {Number} len The number of bits in the word.
+ * @param {Number} x The bits.
+ * @param {Number} [0] _end Pass 1 if x has already been shifted to the high side.
+ * @return {Number} The partial word.
+ */
+ partial: function (len, x, _end) {
+ if (len === 32) { return x; }
+ return (_end ? x|0 : x << (32-len)) + len * 0x10000000000;
+ },
+
+ /**
+ * Get the number of bits used by a partial word.
+ * @param {Number} x The partial word.
+ * @return {Number} The number of bits used by the partial word.
+ */
+ getPartial: function (x) {
+ return Math.round(x/0x10000000000) || 32;
+ },
+
+ /**
+ * Compare two arrays for equality in a predictable amount of time.
+ * @param {bitArray} a The first array.
+ * @param {bitArray} b The second array.
+ * @return {boolean} true if a == b; false otherwise.
+ */
+ equal: function (a, b) {
+ if (sjcl.bitArray.bitLength(a) !== sjcl.bitArray.bitLength(b)) {
+ return false;
+ }
+ var x = 0, i;
+ for (i=0; i= 32; shift -= 32) {
+ out.push(carry);
+ carry = 0;
+ }
+ if (shift === 0) {
+ return out.concat(a);
+ }
+
+ for (i=0; i>>shift);
+ carry = a[i] << (32-shift);
+ }
+ last2 = a.length ? a[a.length-1] : 0;
+ shift2 = sjcl.bitArray.getPartial(last2);
+ out.push(sjcl.bitArray.partial(shift+shift2 & 31, (shift + shift2 > 32) ? carry : out.pop(),1));
+ return out;
+ },
+
+ /** xor a block of 4 words together.
+ * @private
+ */
+ _xor4: function(x,y) {
+ return [x[0]^y[0],x[1]^y[1],x[2]^y[2],x[3]^y[3]];
+ }
+};
diff --git a/src/js/sjcl/core/bn.js b/src/js/sjcl/core/bn.js
new file mode 100644
index 00000000..d5a6b63e
--- /dev/null
+++ b/src/js/sjcl/core/bn.js
@@ -0,0 +1,552 @@
+/**
+ * @constructor
+ * Constructs a new bignum from another bignum, a number or a hex string.
+ */
+sjcl.bn = function(it) {
+ this.initWith(it);
+};
+
+sjcl.bn.prototype = {
+ radix: 24,
+ maxMul: 8,
+ _class: sjcl.bn,
+
+ copy: function() {
+ return new this._class(this);
+ },
+
+ /**
+ * Initializes this with it, either as a bn, a number, or a hex string.
+ */
+ initWith: function(it) {
+ var i=0, k, n, l;
+ switch(typeof it) {
+ case "object":
+ this.limbs = it.limbs.slice(0);
+ break;
+
+ case "number":
+ this.limbs = [it];
+ this.normalize();
+ break;
+
+ case "string":
+ it = it.replace(/^0x/, '');
+ this.limbs = [];
+ // hack
+ k = this.radix / 4;
+ for (i=0; i < it.length; i+=k) {
+ this.limbs.push(parseInt(it.substring(Math.max(it.length - i - k, 0), it.length - i),16));
+ }
+ break;
+
+ default:
+ this.limbs = [0];
+ }
+ return this;
+ },
+
+ /**
+ * Returns true if "this" and "that" are equal. Calls fullReduce().
+ * Equality test is in constant time.
+ */
+ equals: function(that) {
+ if (typeof that === "number") { that = new this._class(that); }
+ var difference = 0, i;
+ this.fullReduce();
+ that.fullReduce();
+ for (i = 0; i < this.limbs.length || i < that.limbs.length; i++) {
+ difference |= this.getLimb(i) ^ that.getLimb(i);
+ }
+ return (difference === 0);
+ },
+
+ /**
+ * Get the i'th limb of this, zero if i is too large.
+ */
+ getLimb: function(i) {
+ return (i >= this.limbs.length) ? 0 : this.limbs[i];
+ },
+
+ /**
+ * Constant time comparison function.
+ * Returns 1 if this >= that, or zero otherwise.
+ */
+ greaterEquals: function(that) {
+ if (typeof that === "number") { that = new this._class(that); }
+ var less = 0, greater = 0, i, a, b;
+ i = Math.max(this.limbs.length, that.limbs.length) - 1;
+ for (; i>= 0; i--) {
+ a = this.getLimb(i);
+ b = that.getLimb(i);
+ greater |= (b - a) & ~less;
+ less |= (a - b) & ~greater;
+ }
+ return (greater | ~less) >>> 31;
+ },
+
+ /**
+ * Convert to a hex string.
+ */
+ toString: function() {
+ this.fullReduce();
+ var out="", i, s, l = this.limbs;
+ for (i=0; i < this.limbs.length; i++) {
+ s = l[i].toString(16);
+ while (i < this.limbs.length - 1 && s.length < 6) {
+ s = "0" + s;
+ }
+ out = s + out;
+ }
+ return "0x"+out;
+ },
+
+ /** this += that. Does not normalize. */
+ addM: function(that) {
+ if (typeof(that) !== "object") { that = new this._class(that); }
+ var i, l=this.limbs, ll=that.limbs;
+ for (i=l.length; i> r;
+ }
+ if (carry) {
+ l.push(carry);
+ }
+ return this;
+ },
+
+ /** this /= 2, rounded down. Requires normalized; ends up normalized. */
+ halveM: function() {
+ var i, carry=0, tmp, r=this.radix, l=this.limbs;
+ for (i=l.length-1; i>=0; i--) {
+ tmp = l[i];
+ l[i] = (tmp+carry)>>1;
+ carry = (tmp&1) << r;
+ }
+ if (!l[l.length-1]) {
+ l.pop();
+ }
+ return this;
+ },
+
+ /** this -= that. Does not normalize. */
+ subM: function(that) {
+ if (typeof(that) !== "object") { that = new this._class(that); }
+ var i, l=this.limbs, ll=that.limbs;
+ for (i=l.length; i 0; ci--) {
+ that.halveM();
+ if (out.greaterEquals(that)) {
+ out.subM(that).normalize();
+ }
+ }
+ return out.trim();
+ },
+
+ /** return inverse mod prime p. p must be odd. Binary extended Euclidean algorithm mod p. */
+ inverseMod: function(p) {
+ var a = new sjcl.bn(1), b = new sjcl.bn(0), x = new sjcl.bn(this), y = new sjcl.bn(p), tmp, i, nz=1;
+
+ if (!(p.limbs[0] & 1)) {
+ throw (new sjcl.exception.invalid("inverseMod: p must be odd"));
+ }
+
+ // invariant: y is odd
+ do {
+ if (x.limbs[0] & 1) {
+ if (!x.greaterEquals(y)) {
+ // x < y; swap everything
+ tmp = x; x = y; y = tmp;
+ tmp = a; a = b; b = tmp;
+ }
+ x.subM(y);
+ x.normalize();
+
+ if (!a.greaterEquals(b)) {
+ a.addM(p);
+ }
+ a.subM(b);
+ }
+
+ // cut everything in half
+ x.halveM();
+ if (a.limbs[0] & 1) {
+ a.addM(p);
+ }
+ a.normalize();
+ a.halveM();
+
+ // check for termination: x ?= 0
+ for (i=nz=0; i= 0; i--) {
+ out = w.concat(out, [w.partial(Math.min(this.radix,len), this.getLimb(i))]);
+ len -= this.radix;
+ }
+ return out;
+ },
+
+ /** Return the length in bits, rounded up to the nearest byte. */
+ bitLength: function() {
+ this.fullReduce();
+ var out = this.radix * (this.limbs.length - 1),
+ b = this.limbs[this.limbs.length - 1];
+ for (; b; b >>>= 1) {
+ out ++;
+ }
+ return out+7 & -8;
+ }
+};
+
+/** @this { sjcl.bn } */
+sjcl.bn.fromBits = function(bits) {
+ var Class = this, out = new Class(), words=[], w=sjcl.bitArray, t = this.prototype,
+ l = Math.min(this.bitLength || 0x100000000, w.bitLength(bits)), e = l % t.radix || t.radix;
+
+ words[0] = w.extract(bits, 0, e);
+ for (; e < l; e += t.radix) {
+ words.unshift(w.extract(bits, e, t.radix));
+ }
+
+ out.limbs = words;
+ return out;
+};
+
+
+
+sjcl.bn.prototype.ipv = 1 / (sjcl.bn.prototype.placeVal = Math.pow(2,sjcl.bn.prototype.radix));
+sjcl.bn.prototype.radixMask = (1 << sjcl.bn.prototype.radix) - 1;
+
+/**
+ * Creates a new subclass of bn, based on reduction modulo a pseudo-Mersenne prime,
+ * i.e. a prime of the form 2^e + sum(a * 2^b),where the sum is negative and sparse.
+ */
+sjcl.bn.pseudoMersennePrime = function(exponent, coeff) {
+ /** @constructor */
+ function p(it) {
+ this.initWith(it);
+ /*if (this.limbs[this.modOffset]) {
+ this.reduce();
+ }*/
+ }
+
+ var ppr = p.prototype = new sjcl.bn(), i, tmp, mo;
+ mo = ppr.modOffset = Math.ceil(tmp = exponent / ppr.radix);
+ ppr.exponent = exponent;
+ ppr.offset = [];
+ ppr.factor = [];
+ ppr.minOffset = mo;
+ ppr.fullMask = 0;
+ ppr.fullOffset = [];
+ ppr.fullFactor = [];
+ ppr.modulus = p.modulus = new sjcl.bn(Math.pow(2,exponent));
+
+ ppr.fullMask = 0|-Math.pow(2, exponent % ppr.radix);
+
+ for (i=0; i mo) {
+ l = limbs.pop();
+ ll = limbs.length;
+ for (k=0; k> 3) & 15)) * 0x1010101;
+
+ /* Pad and encrypt. */
+ iv = prp.encrypt(xor(iv,w.concat(plaintext,[bl,bl,bl,bl]).slice(i,i+4)));
+ output.splice(i,0,iv[0],iv[1],iv[2],iv[3]);
+ return output;
+ },
+
+ /** Decrypt in CBC mode.
+ * @param {Object} prp The block cipher. It must have a block size of 16 bytes.
+ * @param {bitArray} ciphertext The ciphertext data.
+ * @param {bitArray} iv The initialization value.
+ * @param {bitArray} [adata=[]] The authenticated data. It must be empty.
+ * @return The decrypted data, an array of bytes.
+ * @throws {sjcl.exception.invalid} if the IV isn't exactly 128 bits, or if any adata is specified.
+ * @throws {sjcl.exception.corrupt} if if the message is corrupt.
+ */
+ decrypt: function(prp, ciphertext, iv, adata) {
+ if (adata && adata.length) {
+ throw new sjcl.exception.invalid("cbc can't authenticate data");
+ }
+ if (sjcl.bitArray.bitLength(iv) !== 128) {
+ throw new sjcl.exception.invalid("cbc iv must be 128 bits");
+ }
+ if ((sjcl.bitArray.bitLength(ciphertext) & 127) || !ciphertext.length) {
+ throw new sjcl.exception.corrupt("cbc ciphertext must be a positive multiple of the block size");
+ }
+ var i,
+ w = sjcl.bitArray,
+ xor = w._xor4,
+ bi, bo,
+ output = [];
+
+ adata = adata || [];
+
+ for (i=0; i 16) {
+ throw new sjcl.exception.corrupt("pkcs#5 padding corrupt");
+ }
+ bo = bi * 0x1010101;
+ if (!w.equal(w.bitSlice([bo,bo,bo,bo], 0, bi*8),
+ w.bitSlice(output, output.length*32 - bi*8, output.length*32))) {
+ throw new sjcl.exception.corrupt("pkcs#5 padding corrupt");
+ }
+
+ return w.bitSlice(output, 0, output.length*32 - bi*8);
+ }
+ };
+};
diff --git a/src/js/sjcl/core/ccm.js b/src/js/sjcl/core/ccm.js
new file mode 100644
index 00000000..8a32c5ae
--- /dev/null
+++ b/src/js/sjcl/core/ccm.js
@@ -0,0 +1,185 @@
+/** @fileOverview CCM mode implementation.
+ *
+ * Special thanks to Roy Nicholson for pointing out a bug in our
+ * implementation.
+ *
+ * @author Emily Stark
+ * @author Mike Hamburg
+ * @author Dan Boneh
+ */
+
+/** @namespace CTR mode with CBC MAC. */
+sjcl.mode.ccm = {
+ /** The name of the mode.
+ * @constant
+ */
+ name: "ccm",
+
+ /** Encrypt in CCM mode.
+ * @static
+ * @param {Object} prf The pseudorandom function. It must have a block size of 16 bytes.
+ * @param {bitArray} plaintext The plaintext data.
+ * @param {bitArray} iv The initialization value.
+ * @param {bitArray} [adata=[]] The authenticated data.
+ * @param {Number} [tlen=64] the desired tag length, in bits.
+ * @return {bitArray} The encrypted data, an array of bytes.
+ */
+ encrypt: function(prf, plaintext, iv, adata, tlen) {
+ var L, i, out = plaintext.slice(0), tag, w=sjcl.bitArray, ivl = w.bitLength(iv) / 8, ol = w.bitLength(out) / 8;
+ tlen = tlen || 64;
+ adata = adata || [];
+
+ if (ivl < 7) {
+ throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");
+ }
+
+ // compute the length of the length
+ for (L=2; L<4 && ol >>> 8*L; L++) {}
+ if (L < 15 - ivl) { L = 15-ivl; }
+ iv = w.clamp(iv,8*(15-L));
+
+ // compute the tag
+ tag = sjcl.mode.ccm._computeTag(prf, plaintext, iv, adata, tlen, L);
+
+ // encrypt
+ out = sjcl.mode.ccm._ctrMode(prf, out, iv, tag, tlen, L);
+
+ return w.concat(out.data, out.tag);
+ },
+
+ /** Decrypt in CCM mode.
+ * @static
+ * @param {Object} prf The pseudorandom function. It must have a block size of 16 bytes.
+ * @param {bitArray} ciphertext The ciphertext data.
+ * @param {bitArray} iv The initialization value.
+ * @param {bitArray} [[]] adata The authenticated data.
+ * @param {Number} [64] tlen the desired tag length, in bits.
+ * @return {bitArray} The decrypted data.
+ */
+ decrypt: function(prf, ciphertext, iv, adata, tlen) {
+ tlen = tlen || 64;
+ adata = adata || [];
+ var L, i,
+ w=sjcl.bitArray,
+ ivl = w.bitLength(iv) / 8,
+ ol = w.bitLength(ciphertext),
+ out = w.clamp(ciphertext, ol - tlen),
+ tag = w.bitSlice(ciphertext, ol - tlen), tag2;
+
+
+ ol = (ol - tlen) / 8;
+
+ if (ivl < 7) {
+ throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");
+ }
+
+ // compute the length of the length
+ for (L=2; L<4 && ol >>> 8*L; L++) {}
+ if (L < 15 - ivl) { L = 15-ivl; }
+ iv = w.clamp(iv,8*(15-L));
+
+ // decrypt
+ out = sjcl.mode.ccm._ctrMode(prf, out, iv, tag, tlen, L);
+
+ // check the tag
+ tag2 = sjcl.mode.ccm._computeTag(prf, out.data, iv, adata, tlen, L);
+ if (!w.equal(out.tag, tag2)) {
+ throw new sjcl.exception.corrupt("ccm: tag doesn't match");
+ }
+
+ return out.data;
+ },
+
+ /* Compute the (unencrypted) authentication tag, according to the CCM specification
+ * @param {Object} prf The pseudorandom function.
+ * @param {bitArray} plaintext The plaintext data.
+ * @param {bitArray} iv The initialization value.
+ * @param {bitArray} adata The authenticated data.
+ * @param {Number} tlen the desired tag length, in bits.
+ * @return {bitArray} The tag, but not yet encrypted.
+ * @private
+ */
+ _computeTag: function(prf, plaintext, iv, adata, tlen, L) {
+ // compute B[0]
+ var q, mac, field = 0, offset = 24, tmp, i, macData = [], w=sjcl.bitArray, xor = w._xor4;
+
+ tlen /= 8;
+
+ // check tag length and message length
+ if (tlen % 2 || tlen < 4 || tlen > 16) {
+ throw new sjcl.exception.invalid("ccm: invalid tag length");
+ }
+
+ if (adata.length > 0xFFFFFFFF || plaintext.length > 0xFFFFFFFF) {
+ // I don't want to deal with extracting high words from doubles.
+ throw new sjcl.exception.bug("ccm: can't deal with 4GiB or more data");
+ }
+
+ // mac the flags
+ mac = [w.partial(8, (adata.length ? 1<<6 : 0) | (tlen-2) << 2 | L-1)];
+
+ // mac the iv and length
+ mac = w.concat(mac, iv);
+ mac[3] |= w.bitLength(plaintext)/8;
+ mac = prf.encrypt(mac);
+
+
+ if (adata.length) {
+ // mac the associated data. start with its length...
+ tmp = w.bitLength(adata)/8;
+ if (tmp <= 0xFEFF) {
+ macData = [w.partial(16, tmp)];
+ } else if (tmp <= 0xFFFFFFFF) {
+ macData = w.concat([w.partial(16,0xFFFE)], [tmp]);
+ } // else ...
+
+ // mac the data itself
+ macData = w.concat(macData, adata);
+ for (i=0; i>>bits) >>> 26);
+ if (bits < 6) {
+ ta = arr[i] << (6-bits);
+ bits += 26;
+ i++;
+ } else {
+ ta <<= 6;
+ bits -= 6;
+ }
+ }
+ while ((out.length & 3) && !_noEquals) { out += "="; }
+ return out;
+ },
+
+ /** Convert from a base64 string to a bitArray */
+ toBits: function(str, _url) {
+ str = str.replace(/\s|=/g,'');
+ var out = [], i, bits=0, c = sjcl.codec.base64._chars, ta=0, x;
+ if (_url) c = c.substr(0,62) + '-_';
+ for (i=0; i 26) {
+ bits -= 26;
+ out.push(ta ^ x>>>bits);
+ ta = x << (32-bits);
+ } else {
+ bits += 6;
+ ta ^= x << (32-bits);
+ }
+ }
+ if (bits&56) {
+ out.push(sjcl.bitArray.partial(bits&56, ta, 1));
+ }
+ return out;
+ }
+};
+
+sjcl.codec.base64url = {
+ fromBits: function (arr) { return sjcl.codec.base64.fromBits(arr,1,1); },
+ toBits: function (str) { return sjcl.codec.base64.toBits(str,1); }
+};
diff --git a/src/js/sjcl/core/codecBytes.js b/src/js/sjcl/core/codecBytes.js
new file mode 100644
index 00000000..cde2af3a
--- /dev/null
+++ b/src/js/sjcl/core/codecBytes.js
@@ -0,0 +1,37 @@
+/** @fileOverview Bit array codec implementations.
+ *
+ * @author Emily Stark
+ * @author Mike Hamburg
+ * @author Dan Boneh
+ */
+
+/** @namespace Arrays of bytes */
+sjcl.codec.bytes = {
+ /** Convert from a bitArray to an array of bytes. */
+ fromBits: function (arr) {
+ var out = [], bl = sjcl.bitArray.bitLength(arr), i, tmp;
+ for (i=0; i>> 24);
+ tmp <<= 8;
+ }
+ return out;
+ },
+ /** Convert from an array of bytes to a bitArray. */
+ toBits: function (bytes) {
+ var out = [], i, tmp=0;
+ for (i=0; i>> 24);
+ tmp <<= 8;
+ }
+ return decodeURIComponent(escape(out));
+ },
+
+ /** Convert from a UTF-8 string to a bitArray. */
+ toBits: function (str) {
+ str = unescape(encodeURIComponent(str));
+ var out = [], i, tmp=0;
+ for (i=0; i 4)) {
+ throw new sjcl.exception.invalid("json encrypt: invalid parameters");
+ }
+
+ if (typeof password === "string") {
+ tmp = sjcl.misc.cachedPbkdf2(password, p);
+ password = tmp.key.slice(0,p.ks/32);
+ p.salt = tmp.salt;
+ } else if (sjcl.ecc && password instanceof sjcl.ecc.elGamal.publicKey) {
+ tmp = password.kem();
+ p.kemtag = tmp.tag;
+ password = tmp.key.slice(0,p.ks/32);
+ }
+ if (typeof plaintext === "string") {
+ plaintext = sjcl.codec.utf8String.toBits(plaintext);
+ }
+ if (typeof adata === "string") {
+ adata = sjcl.codec.utf8String.toBits(adata);
+ }
+ prp = new sjcl.cipher[p.cipher](password);
+
+ /* return the json data */
+ j._add(rp, p);
+ rp.key = password;
+
+ /* do the encryption */
+ p.ct = sjcl.mode[p.mode].encrypt(prp, plaintext, p.iv, adata, p.ts);
+
+ //return j.encode(j._subtract(p, j.defaults));
+ return j.encode(p);
+ },
+
+ /** Simple decryption function.
+ * @param {String|bitArray} password The password or key.
+ * @param {String} ciphertext The ciphertext to decrypt.
+ * @param {Object} [params] Additional non-default parameters.
+ * @param {Object} [rp] A returned object with filled parameters.
+ * @return {String} The plaintext.
+ * @throws {sjcl.exception.invalid} if a parameter is invalid.
+ * @throws {sjcl.exception.corrupt} if the ciphertext is corrupt.
+ */
+ decrypt: function (password, ciphertext, params, rp) {
+ params = params || {};
+ rp = rp || {};
+
+ var j = sjcl.json, p = j._add(j._add(j._add({},j.defaults),j.decode(ciphertext)), params, true), ct, tmp, prp, adata=p.adata;
+ if (typeof p.salt === "string") {
+ p.salt = sjcl.codec.base64.toBits(p.salt);
+ }
+ if (typeof p.iv === "string") {
+ p.iv = sjcl.codec.base64.toBits(p.iv);
+ }
+
+ if (!sjcl.mode[p.mode] ||
+ !sjcl.cipher[p.cipher] ||
+ (typeof password === "string" && p.iter <= 100) ||
+ (p.ts !== 64 && p.ts !== 96 && p.ts !== 128) ||
+ (p.ks !== 128 && p.ks !== 192 && p.ks !== 256) ||
+ (!p.iv) ||
+ (p.iv.length < 2 || p.iv.length > 4)) {
+ throw new sjcl.exception.invalid("json decrypt: invalid parameters");
+ }
+
+ if (typeof password === "string") {
+ tmp = sjcl.misc.cachedPbkdf2(password, p);
+ password = tmp.key.slice(0,p.ks/32);
+ p.salt = tmp.salt;
+ } else if (sjcl.ecc && password instanceof sjcl.ecc.elGamal.secretKey) {
+ password = password.unkem(sjcl.codec.base64.toBits(p.kemtag)).slice(0,p.ks/32);
+ }
+ if (typeof adata === "string") {
+ adata = sjcl.codec.utf8String.toBits(adata);
+ }
+ prp = new sjcl.cipher[p.cipher](password);
+
+ /* do the decryption */
+ ct = sjcl.mode[p.mode].decrypt(prp, p.ct, p.iv, adata, p.ts);
+
+ /* return the json data */
+ j._add(rp, p);
+ rp.key = password;
+
+ return sjcl.codec.utf8String.fromBits(ct);
+ },
+
+ /** Encode a flat structure into a JSON string.
+ * @param {Object} obj The structure to encode.
+ * @return {String} A JSON string.
+ * @throws {sjcl.exception.invalid} if obj has a non-alphanumeric property.
+ * @throws {sjcl.exception.bug} if a parameter has an unsupported type.
+ */
+ encode: function (obj) {
+ var i, out='{', comma='';
+ for (i in obj) {
+ if (obj.hasOwnProperty(i)) {
+ if (!i.match(/^[a-z0-9]+$/i)) {
+ throw new sjcl.exception.invalid("json encode: invalid property name");
+ }
+ out += comma + '"' + i + '":';
+ comma = ',';
+
+ switch (typeof obj[i]) {
+ case 'number':
+ case 'boolean':
+ out += obj[i];
+ break;
+
+ case 'string':
+ out += '"' + escape(obj[i]) + '"';
+ break;
+
+ case 'object':
+ out += '"' + sjcl.codec.base64.fromBits(obj[i],0) + '"';
+ break;
+
+ default:
+ throw new sjcl.exception.bug("json encode: unsupported type");
+ }
+ }
+ }
+ return out+'}';
+ },
+
+ /** Decode a simple (flat) JSON string into a structure. The ciphertext,
+ * adata, salt and iv will be base64-decoded.
+ * @param {String} str The string.
+ * @return {Object} The decoded structure.
+ * @throws {sjcl.exception.invalid} if str isn't (simple) JSON.
+ */
+ decode: function (str) {
+ str = str.replace(/\s/g,'');
+ if (!str.match(/^\{.*\}$/)) {
+ throw new sjcl.exception.invalid("json decode: this isn't json!");
+ }
+ var a = str.replace(/^\{|\}$/g, '').split(/,/), out={}, i, m;
+ for (i=0; i=0; i--) {
+ for (j=sjcl.bn.prototype.radix-4; j>=0; j-=4) {
+ out = out.doubl().doubl().doubl().doubl().add(multiples[k[i]>>j & 0xF]);
+ }
+ }
+
+ return out;
+ },
+
+ /**
+ * Multiply this point by k, added to affine2*k2, and return the answer in Jacobian coordinates.
+ * @param {bigInt} k The coefficient to multiply this by.
+ * @param {sjcl.ecc.point} affine This point in affine coordinates.
+ * @param {bigInt} k2 The coefficient to multiply affine2 this by.
+ * @param {sjcl.ecc.point} affine The other point in affine coordinates.
+ * @return {sjcl.ecc.pointJac} The result of the multiplication and addition, in Jacobian coordinates.
+ */
+ mult2: function(k1, affine, k2, affine2) {
+ if (typeof(k1) === "number") {
+ k1 = [k1];
+ } else if (k1.limbs !== undefined) {
+ k1 = k1.normalize().limbs;
+ }
+
+ if (typeof(k2) === "number") {
+ k2 = [k2];
+ } else if (k2.limbs !== undefined) {
+ k2 = k2.normalize().limbs;
+ }
+
+ var i, j, out = new sjcl.ecc.point(this.curve).toJac(), m1 = affine.multiples(),
+ m2 = affine2.multiples(), l1, l2;
+
+ for (i=Math.max(k1.length,k2.length)-1; i>=0; i--) {
+ l1 = k1[i] | 0;
+ l2 = k2[i] | 0;
+ for (j=sjcl.bn.prototype.radix-4; j>=0; j-=4) {
+ out = out.doubl().doubl().doubl().doubl().add(m1[l1>>j & 0xF]).add(m2[l2>>j & 0xF]);
+ }
+ }
+
+ return out;
+ },
+
+ isValid: function() {
+ var z2 = this.z.square(), z4 = z2.square(), z6 = z4.mul(z2);
+ return this.y.square().equals(
+ this.curve.b.mul(z6).add(this.x.mul(
+ this.curve.a.mul(z4).add(this.x.square()))));
+ }
+};
+
+/**
+ * Construct an elliptic curve. Most users will not use this and instead start with one of the NIST curves defined below.
+ *
+ * @constructor
+ * @param {bigInt} p The prime modulus.
+ * @param {bigInt} r The prime order of the curve.
+ * @param {bigInt} a The constant a in the equation of the curve y^2 = x^3 + ax + b (for NIST curves, a is always -3).
+ * @param {bigInt} x The x coordinate of a base point of the curve.
+ * @param {bigInt} y The y coordinate of a base point of the curve.
+ */
+sjcl.ecc.curve = function(Field, r, a, b, x, y) {
+ this.field = Field;
+ this.r = Field.prototype.modulus.sub(r);
+ this.a = new Field(a);
+ this.b = new Field(b);
+ this.G = new sjcl.ecc.point(this, new Field(x), new Field(y));
+};
+
+sjcl.ecc.curve.prototype.fromBits = function (bits) {
+ var w = sjcl.bitArray, l = this.field.prototype.exponent + 7 & -8,
+ p = new sjcl.ecc.point(this, this.field.fromBits(w.bitSlice(bits, 0, l)),
+ this.field.fromBits(w.bitSlice(bits, l, 2*l)));
+ if (!p.isValid()) {
+ throw new sjcl.exception.corrupt("not on the curve!");
+ }
+ return p;
+};
+
+sjcl.ecc.curves = {
+ c192: new sjcl.ecc.curve(
+ sjcl.bn.prime.p192,
+ "0x662107c8eb94364e4b2dd7ce",
+ -3,
+ "0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1",
+ "0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012",
+ "0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811"),
+
+ c224: new sjcl.ecc.curve(
+ sjcl.bn.prime.p224,
+ "0xe95c1f470fc1ec22d6baa3a3d5c4",
+ -3,
+ "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4",
+ "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
+ "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"),
+
+ c256: new sjcl.ecc.curve(
+ sjcl.bn.prime.p256,
+ "0x4319055358e8617b0c46353d039cdaae",
+ -3,
+ "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
+ "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
+ "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"),
+
+ c384: new sjcl.ecc.curve(
+ sjcl.bn.prime.p384,
+ "0x389cb27e0bc8d21fa7e5f24cb74f58851313e696333ad68c",
+ -3,
+ "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef",
+ "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7",
+ "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f")
+};
+
+
+/* Diffie-Hellman-like public-key system */
+sjcl.ecc._dh = function(cn) {
+ sjcl.ecc[cn] = {
+ /** @constructor */
+ publicKey: function(curve, point) {
+ this._curve = curve;
+ this._curveBitLength = curve.r.bitLength();
+ if (point instanceof Array) {
+ this._point = curve.fromBits(point);
+ } else {
+ this._point = point;
+ }
+
+ this.get = function() {
+ var pointbits = this._point.toBits();
+ var len = sjcl.bitArray.bitLength(pointbits);
+ var x = sjcl.bitArray.bitSlice(pointbits, 0, len/2);
+ var y = sjcl.bitArray.bitSlice(pointbits, len/2);
+ return { x: x, y: y };
+ }
+ },
+
+ /** @constructor */
+ secretKey: function(curve, exponent) {
+ this._curve = curve;
+ this._curveBitLength = curve.r.bitLength();
+ this._exponent = exponent;
+
+ this.get = function() {
+ return this._exponent.toBits();
+ }
+ },
+
+ /** @constructor */
+ generateKeys: function(curve, paranoia, sec) {
+ if (curve === undefined) {
+ curve = 256;
+ }
+ if (typeof curve === "number") {
+ curve = sjcl.ecc.curves['c'+curve];
+ if (curve === undefined) {
+ throw new sjcl.exception.invalid("no such curve");
+ }
+ }
+ if (sec === undefined) {
+ var sec = sjcl.bn.random(curve.r, paranoia);
+ }
+ var pub = curve.G.mult(sec);
+ return { pub: new sjcl.ecc[cn].publicKey(curve, pub),
+ sec: new sjcl.ecc[cn].secretKey(curve, sec) };
+ }
+ };
+};
+
+sjcl.ecc._dh("elGamal");
+
+sjcl.ecc.elGamal.publicKey.prototype = {
+ kem: function(paranoia) {
+ var sec = sjcl.bn.random(this._curve.r, paranoia),
+ tag = this._curve.G.mult(sec).toBits(),
+ key = sjcl.hash.sha256.hash(this._point.mult(sec).toBits());
+ return { key: key, tag: tag };
+ }
+};
+
+sjcl.ecc.elGamal.secretKey.prototype = {
+ unkem: function(tag) {
+ return sjcl.hash.sha256.hash(this._curve.fromBits(tag).mult(this._exponent).toBits());
+ },
+
+ dh: function(pk) {
+ return sjcl.hash.sha256.hash(pk._point.mult(this._exponent).toBits());
+ }
+};
+
+sjcl.ecc._dh("ecdsa");
+
+sjcl.ecc.ecdsa.secretKey.prototype = {
+ sign: function(hash, paranoia, fakeLegacyVersion, fixedKForTesting) {
+ if (sjcl.bitArray.bitLength(hash) > this._curveBitLength) {
+ hash = sjcl.bitArray.clamp(hash, this._curveBitLength);
+ }
+ var R = this._curve.r,
+ l = R.bitLength(),
+ k = fixedKForTesting || sjcl.bn.random(R.sub(1), paranoia).add(1),
+ r = this._curve.G.mult(k).x.mod(R),
+ ss = sjcl.bn.fromBits(hash).add(r.mul(this._exponent)),
+ s = fakeLegacyVersion ? ss.inverseMod(R).mul(k).mod(R)
+ : ss.mul(k.inverseMod(R)).mod(R);
+ return sjcl.bitArray.concat(r.toBits(l), s.toBits(l));
+ }
+};
+
+sjcl.ecc.ecdsa.publicKey.prototype = {
+ verify: function(hash, rs, fakeLegacyVersion) {
+ if (sjcl.bitArray.bitLength(hash) > this._curveBitLength) {
+ hash = sjcl.bitArray.clamp(hash, this._curveBitLength);
+ }
+ var w = sjcl.bitArray,
+ R = this._curve.r,
+ l = this._curveBitLength,
+ r = sjcl.bn.fromBits(w.bitSlice(rs,0,l)),
+ ss = sjcl.bn.fromBits(w.bitSlice(rs,l,2*l)),
+ s = fakeLegacyVersion ? ss : ss.inverseMod(R),
+ hG = sjcl.bn.fromBits(hash).mul(s).mod(R),
+ hA = r.mul(s).mod(R),
+ r2 = this._curve.G.mult2(hG, hA, this._point).x;
+ if (r.equals(0) || ss.equals(0) || r.greaterEquals(R) || ss.greaterEquals(R) || !r2.equals(r)) {
+ if (fakeLegacyVersion === undefined) {
+ return this.verify(hash, rs, true);
+ } else {
+ throw (new sjcl.exception.corrupt("signature didn't check out"));
+ }
+ }
+ return true;
+ }
+};
diff --git a/src/js/sjcl/core/gcm.js b/src/js/sjcl/core/gcm.js
new file mode 100644
index 00000000..b39cb6a6
--- /dev/null
+++ b/src/js/sjcl/core/gcm.js
@@ -0,0 +1,183 @@
+/** @fileOverview GCM mode implementation.
+ *
+ * @author Juho Vähä-Herttua
+ */
+
+/** @namespace Galois/Counter mode. */
+sjcl.mode.gcm = {
+ /** The name of the mode.
+ * @constant
+ */
+ name: "gcm",
+
+ /** Encrypt in GCM mode.
+ * @static
+ * @param {Object} prf The pseudorandom function. It must have a block size of 16 bytes.
+ * @param {bitArray} plaintext The plaintext data.
+ * @param {bitArray} iv The initialization value.
+ * @param {bitArray} [adata=[]] The authenticated data.
+ * @param {Number} [tlen=128] The desired tag length, in bits.
+ * @return {bitArray} The encrypted data, an array of bytes.
+ */
+ encrypt: function (prf, plaintext, iv, adata, tlen) {
+ var out, data = plaintext.slice(0), w=sjcl.bitArray;
+ tlen = tlen || 128;
+ adata = adata || [];
+
+ // encrypt and tag
+ out = sjcl.mode.gcm._ctrMode(true, prf, data, adata, iv, tlen);
+
+ return w.concat(out.data, out.tag);
+ },
+
+ /** Decrypt in GCM mode.
+ * @static
+ * @param {Object} prf The pseudorandom function. It must have a block size of 16 bytes.
+ * @param {bitArray} ciphertext The ciphertext data.
+ * @param {bitArray} iv The initialization value.
+ * @param {bitArray} [adata=[]] The authenticated data.
+ * @param {Number} [tlen=128] The desired tag length, in bits.
+ * @return {bitArray} The decrypted data.
+ */
+ decrypt: function (prf, ciphertext, iv, adata, tlen) {
+ var out, data = ciphertext.slice(0), tag, w=sjcl.bitArray, l=w.bitLength(data);
+ tlen = tlen || 128;
+ adata = adata || [];
+
+ // Slice tag out of data
+ if (tlen <= l) {
+ tag = w.bitSlice(data, l-tlen);
+ data = w.bitSlice(data, 0, l-tlen);
+ } else {
+ tag = data;
+ data = [];
+ }
+
+ // decrypt and tag
+ out = sjcl.mode.gcm._ctrMode(false, prf, data, adata, iv, tlen);
+
+ if (!w.equal(out.tag, tag)) {
+ throw new sjcl.exception.corrupt("gcm: tag doesn't match");
+ }
+ return out.data;
+ },
+
+ /* Compute the galois multiplication of X and Y
+ * @private
+ */
+ _galoisMultiply: function (x, y) {
+ var i, j, xi, Zi, Vi, lsb_Vi, w=sjcl.bitArray, xor=w._xor4;
+
+ Zi = [0,0,0,0];
+ Vi = y.slice(0);
+
+ // Block size is 128 bits, run 128 times to get Z_128
+ for (i=0; i<128; i++) {
+ xi = (x[Math.floor(i/32)] & (1 << (31-i%32))) !== 0;
+ if (xi) {
+ // Z_i+1 = Z_i ^ V_i
+ Zi = xor(Zi, Vi);
+ }
+
+ // Store the value of LSB(V_i)
+ lsb_Vi = (Vi[3] & 1) !== 0;
+
+ // V_i+1 = V_i >> 1
+ for (j=3; j>0; j--) {
+ Vi[j] = (Vi[j] >>> 1) | ((Vi[j-1]&1) << 31);
+ }
+ Vi[0] = Vi[0] >>> 1;
+
+ // If LSB(V_i) is 1, V_i+1 = (V_i >> 1) ^ R
+ if (lsb_Vi) {
+ Vi[0] = Vi[0] ^ (0xe1 << 24);
+ }
+ }
+ return Zi;
+ },
+
+ _ghash: function(H, Y0, data) {
+ var Yi, i, l = data.length;
+
+ Yi = Y0.slice(0);
+ for (i=0; i bs) {
+ key = Hash.hash(key);
+ }
+
+ for (i=0; i>>31,
+ x[1]<<1 ^ x[2]>>>31,
+ x[2]<<1 ^ x[3]>>>31,
+ x[3]<<1 ^ (x[0]>>>31)*0x87];
+ }
+};
diff --git a/src/js/sjcl/core/pbkdf2.js b/src/js/sjcl/core/pbkdf2.js
new file mode 100644
index 00000000..869e4dfa
--- /dev/null
+++ b/src/js/sjcl/core/pbkdf2.js
@@ -0,0 +1,54 @@
+/** @fileOverview Password-based key-derivation function, version 2.0.
+ *
+ * @author Emily Stark
+ * @author Mike Hamburg
+ * @author Dan Boneh
+ */
+
+/** Password-Based Key-Derivation Function, version 2.0.
+ *
+ * Generate keys from passwords using PBKDF2-HMAC-SHA256.
+ *
+ * This is the method specified by RSA's PKCS #5 standard.
+ *
+ * @param {bitArray|String} password The password.
+ * @param {bitArray} salt The salt. Should have lots of entropy.
+ * @param {Number} [count=1000] The number of iterations. Higher numbers make the function slower but more secure.
+ * @param {Number} [length] The length of the derived key. Defaults to the
+ output size of the hash function.
+ * @param {Object} [Prff=sjcl.misc.hmac] The pseudorandom function family.
+ * @return {bitArray} the derived key.
+ */
+sjcl.misc.pbkdf2 = function (password, salt, count, length, Prff) {
+ count = count || 1000;
+
+ if (length < 0 || count < 0) {
+ throw sjcl.exception.invalid("invalid params to pbkdf2");
+ }
+
+ if (typeof password === "string") {
+ password = sjcl.codec.utf8String.toBits(password);
+ }
+
+ Prff = Prff || sjcl.misc.hmac;
+
+ var prf = new Prff(password),
+ u, ui, i, j, k, out = [], b = sjcl.bitArray;
+
+ for (k = 1; 32 * out.length < (length || 1); k++) {
+ u = ui = prf.encrypt(b.concat(salt,[k]));
+
+ for (i=1; i
+ * This random number generator is a derivative of Ferguson and Schneier's
+ * generator Fortuna. It collects entropy from various events into several
+ * pools, implemented by streaming SHA-256 instances. It differs from
+ * ordinary Fortuna in a few ways, though.
+ *
+ *
+ *
+ * Most importantly, it has an entropy estimator. This is present because
+ * there is a strong conflict here between making the generator available
+ * as soon as possible, and making sure that it doesn't "run on empty".
+ * In Fortuna, there is a saved state file, and the system is likely to have
+ * time to warm up.
+ *
+ *
+ *
+ * Second, because users are unlikely to stay on the page for very long,
+ * and to speed startup time, the number of pools increases logarithmically:
+ * a new pool is created when the previous one is actually used for a reseed.
+ * This gives the same asymptotic guarantees as Fortuna, but gives more
+ * entropy to early reseeds.
+ *
+ *
+ *
+ * The entire mechanism here feels pretty klunky. Furthermore, there are
+ * several improvements that should be made, including support for
+ * dedicated cryptographic functions that may be present in some browsers;
+ * state files in local storage; cookies containing randomness; etc. So
+ * look for improvements in future versions.
+ *
+ */
+sjcl.prng = function(defaultParanoia) {
+
+ /* private */
+ this._pools = [new sjcl.hash.sha256()];
+ this._poolEntropy = [0];
+ this._reseedCount = 0;
+ this._robins = {};
+ this._eventId = 0;
+
+ this._collectorIds = {};
+ this._collectorIdNext = 0;
+
+ this._strength = 0;
+ this._poolStrength = 0;
+ this._nextReseed = 0;
+ this._key = [0,0,0,0,0,0,0,0];
+ this._counter = [0,0,0,0];
+ this._cipher = undefined;
+ this._defaultParanoia = defaultParanoia;
+
+ /* event listener stuff */
+ this._collectorsStarted = false;
+ this._callbacks = {progress: {}, seeded: {}};
+ this._callbackI = 0;
+
+ /* constants */
+ this._NOT_READY = 0;
+ this._READY = 1;
+ this._REQUIRES_RESEED = 2;
+
+ this._MAX_WORDS_PER_BURST = 65536;
+ this._PARANOIA_LEVELS = [0,48,64,96,128,192,256,384,512,768,1024];
+ this._MILLISECONDS_PER_RESEED = 30000;
+ this._BITS_PER_RESEED = 80;
+}
+
+sjcl.prng.prototype = {
+ /** Generate several random words, and return them in an array
+ * @param {Number} nwords The number of words to generate.
+ */
+ randomWords: function (nwords, paranoia) {
+ var out = [], i, readiness = this.isReady(paranoia), g;
+
+ if (readiness === this._NOT_READY) {
+ throw new sjcl.exception.notReady("generator isn't seeded");
+ } else if (readiness & this._REQUIRES_RESEED) {
+ this._reseedFromPools(!(readiness & this._READY));
+ }
+
+ for (i=0; i0) {
+ estimatedEntropy++;
+ tmp = tmp >>> 1;
+ }
+ }
+ }
+ this._pools[robin].update([id,this._eventId++,2,estimatedEntropy,t,data.length].concat(data));
+ }
+ break;
+
+ case "string":
+ if (estimatedEntropy === undefined) {
+ /* English text has just over 1 bit per character of entropy.
+ * But this might be HTML or something, and have far less
+ * entropy than English... Oh well, let's just say one bit.
+ */
+ estimatedEntropy = data.length;
+ }
+ this._pools[robin].update([id,this._eventId++,3,estimatedEntropy,t,data.length]);
+ this._pools[robin].update(data);
+ break;
+
+ default:
+ err=1;
+ }
+ if (err) {
+ throw new sjcl.exception.bug("random: addEntropy only supports number, array of numbers or string");
+ }
+
+ /* record the new strength */
+ this._poolEntropy[robin] += estimatedEntropy;
+ this._poolStrength += estimatedEntropy;
+
+ /* fire off events */
+ if (oldReady === this._NOT_READY) {
+ if (this.isReady() !== this._NOT_READY) {
+ this._fireEvent("seeded", Math.max(this._strength, this._poolStrength));
+ }
+ this._fireEvent("progress", this.getProgress());
+ }
+ },
+
+ /** Is the generator ready? */
+ isReady: function (paranoia) {
+ var entropyRequired = this._PARANOIA_LEVELS[ (paranoia !== undefined) ? paranoia : this._defaultParanoia ];
+
+ if (this._strength && this._strength >= entropyRequired) {
+ return (this._poolEntropy[0] > this._BITS_PER_RESEED && (new Date()).valueOf() > this._nextReseed) ?
+ this._REQUIRES_RESEED | this._READY :
+ this._READY;
+ } else {
+ return (this._poolStrength >= entropyRequired) ?
+ this._REQUIRES_RESEED | this._NOT_READY :
+ this._NOT_READY;
+ }
+ },
+
+ /** Get the generator's progress toward readiness, as a fraction */
+ getProgress: function (paranoia) {
+ var entropyRequired = this._PARANOIA_LEVELS[ paranoia ? paranoia : this._defaultParanoia ];
+
+ if (this._strength >= entropyRequired) {
+ return 1.0;
+ } else {
+ return (this._poolStrength > entropyRequired) ?
+ 1.0 :
+ this._poolStrength / entropyRequired;
+ }
+ },
+
+ /** start the built-in entropy collectors */
+ startCollectors: function () {
+ if (this._collectorsStarted) { return; }
+
+ if (window.addEventListener) {
+ window.addEventListener("load", this._loadTimeCollector, false);
+ window.addEventListener("mousemove", this._mouseCollector, false);
+ } else if (document.attachEvent) {
+ document.attachEvent("onload", this._loadTimeCollector);
+ document.attachEvent("onmousemove", this._mouseCollector);
+ }
+ else {
+ throw new sjcl.exception.bug("can't attach event");
+ }
+
+ this._collectorsStarted = true;
+ },
+
+ /** stop the built-in entropy collectors */
+ stopCollectors: function () {
+ if (!this._collectorsStarted) { return; }
+
+ if (window.removeEventListener) {
+ window.removeEventListener("load", this._loadTimeCollector, false);
+ window.removeEventListener("mousemove", this._mouseCollector, false);
+ } else if (window.detachEvent) {
+ window.detachEvent("onload", this._loadTimeCollector);
+ window.detachEvent("onmousemove", this._mouseCollector);
+ }
+ this._collectorsStarted = false;
+ },
+
+ /* use a cookie to store entropy.
+ useCookie: function (all_cookies) {
+ throw new sjcl.exception.bug("random: useCookie is unimplemented");
+ },*/
+
+ /** add an event listener for progress or seeded-ness. */
+ addEventListener: function (name, callback) {
+ this._callbacks[name][this._callbackI++] = callback;
+ },
+
+ /** remove an event listener for progress or seeded-ness */
+ removeEventListener: function (name, cb) {
+ var i, j, cbs=this._callbacks[name], jsTemp=[];
+
+ /* I'm not sure if this is necessary; in C++, iterating over a
+ * collection and modifying it at the same time is a no-no.
+ */
+
+ for (j in cbs) {
+ if (cbs.hasOwnProperty(j) && cbs[j] === cb) {
+ jsTemp.push(j);
+ }
+ }
+
+ for (i=0; i= 1 << this._pools.length) {
+ this._pools.push(new sjcl.hash.sha256());
+ this._poolEntropy.push(0);
+ }
+
+ /* how strong was this reseed? */
+ this._poolStrength -= strength;
+ if (strength > this._strength) {
+ this._strength = strength;
+ }
+
+ this._reseedCount ++;
+ this._reseed(reseedData);
+ },
+
+ _mouseCollector: function (ev) {
+ var x = ev.x || ev.clientX || ev.offsetX || 0, y = ev.y || ev.clientY || ev.offsetY || 0;
+ sjcl.random.addEntropy([x,y], 2, "mouse");
+ },
+
+ _loadTimeCollector: function (ev) {
+ sjcl.random.addEntropy((new Date()).valueOf(), 2, "loadtime");
+ },
+
+ _fireEvent: function (name, arg) {
+ var j, cbs=sjcl.random._callbacks[name], cbsTemp=[];
+ /* TODO: there is a race condition between removing collectors and firing them */
+
+ /* I'm not sure if this is necessary; in C++, iterating over a
+ * collection and modifying it at the same time is a no-no.
+ */
+
+ for (j in cbs) {
+ if (cbs.hasOwnProperty(j)) {
+ cbsTemp.push(cbs[j]);
+ }
+ }
+
+ for (j=0; j>> 32-n);
+ },
+
+ /**
+ * Perform one cycle of SHA-1.
+ * @param {bitArray} words one block of words.
+ * @private
+ */
+ _block:function (words) {
+ var t, tmp, a, b, c, d, e,
+ w = words.slice(0),
+ h = this._h,
+ k = this._key;
+
+ a = h[0]; b = h[1]; c = h[2]; d = h[3]; e = h[4];
+
+ for (t=0; t<=79; t++) {
+ if (t >= 16) {
+ w[t] = this._S(1, w[t-3] ^ w[t-8] ^ w[t-14] ^ w[t-16]);
+ }
+ tmp = (this._S(5, a) + this._f(t, b, c, d) + e + w[t] +
+ this._key[Math.floor(t/20)]) | 0;
+ e = d;
+ d = c;
+ c = this._S(30, b);
+ b = a;
+ a = tmp;
+ }
+
+ h[0] = (h[0]+a) |0;
+ h[1] = (h[1]+b) |0;
+ h[2] = (h[2]+c) |0;
+ h[3] = (h[3]+d) |0;
+ h[4] = (h[4]+e) |0;
+ }
+};
diff --git a/src/js/sjcl/core/sha256.js b/src/js/sjcl/core/sha256.js
new file mode 100644
index 00000000..6ff52948
--- /dev/null
+++ b/src/js/sjcl/core/sha256.js
@@ -0,0 +1,216 @@
+/** @fileOverview Javascript SHA-256 implementation.
+ *
+ * An older version of this implementation is available in the public
+ * domain, but this one is (c) Emily Stark, Mike Hamburg, Dan Boneh,
+ * Stanford University 2008-2010 and BSD-licensed for liability
+ * reasons.
+ *
+ * Special thanks to Aldo Cortesi for pointing out several bugs in
+ * this code.
+ *
+ * @author Emily Stark
+ * @author Mike Hamburg
+ * @author Dan Boneh
+ */
+
+/**
+ * Context for a SHA-256 operation in progress.
+ * @constructor
+ * @class Secure Hash Algorithm, 256 bits.
+ */
+sjcl.hash.sha256 = function (hash) {
+ if (!this._key[0]) { this._precompute(); }
+ if (hash) {
+ this._h = hash._h.slice(0);
+ this._buffer = hash._buffer.slice(0);
+ this._length = hash._length;
+ } else {
+ this.reset();
+ }
+};
+
+/**
+ * Hash a string or an array of words.
+ * @static
+ * @param {bitArray|String} data the data to hash.
+ * @return {bitArray} The hash value, an array of 16 big-endian words.
+ */
+sjcl.hash.sha256.hash = function (data) {
+ return (new sjcl.hash.sha256()).update(data).finalize();
+};
+
+sjcl.hash.sha256.prototype = {
+ /**
+ * The hash's block size, in bits.
+ * @constant
+ */
+ blockSize: 512,
+
+ /**
+ * Reset the hash state.
+ * @return this
+ */
+ reset:function () {
+ this._h = this._init.slice(0);
+ this._buffer = [];
+ this._length = 0;
+ return this;
+ },
+
+ /**
+ * Input several words to the hash.
+ * @param {bitArray|String} data the data to hash.
+ * @return this
+ */
+ update: function (data) {
+ if (typeof data === "string") {
+ data = sjcl.codec.utf8String.toBits(data);
+ }
+ var i, b = this._buffer = sjcl.bitArray.concat(this._buffer, data),
+ ol = this._length,
+ nl = this._length = ol + sjcl.bitArray.bitLength(data);
+ for (i = 512+ol & -512; i <= nl; i+= 512) {
+ this._block(b.splice(0,16));
+ }
+ return this;
+ },
+
+ /**
+ * Complete hashing and output the hash value.
+ * @return {bitArray} The hash value, an array of 8 big-endian words.
+ */
+ finalize:function () {
+ var i, b = this._buffer, h = this._h;
+
+ // Round out and push the buffer
+ b = sjcl.bitArray.concat(b, [sjcl.bitArray.partial(1,1)]);
+
+ // Round out the buffer to a multiple of 16 words, less the 2 length words.
+ for (i = b.length + 2; i & 15; i++) {
+ b.push(0);
+ }
+
+ // append the length
+ b.push(Math.floor(this._length / 0x100000000));
+ b.push(this._length | 0);
+
+ while (b.length) {
+ this._block(b.splice(0,16));
+ }
+
+ this.reset();
+ return h;
+ },
+
+ /**
+ * The SHA-256 initialization vector, to be precomputed.
+ * @private
+ */
+ _init:[],
+ /*
+ _init:[0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19],
+ */
+
+ /**
+ * The SHA-256 hash key, to be precomputed.
+ * @private
+ */
+ _key:[],
+ /*
+ _key:
+ [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2],
+ */
+
+
+ /**
+ * Function to precompute _init and _key.
+ * @private
+ */
+ _precompute: function () {
+ var i = 0, prime = 2, factor;
+
+ function frac(x) { return (x-Math.floor(x)) * 0x100000000 | 0; }
+
+ outer: for (; i<64; prime++) {
+ for (factor=2; factor*factor <= prime; factor++) {
+ if (prime % factor === 0) {
+ // not a prime
+ continue outer;
+ }
+ }
+
+ if (i<8) {
+ this._init[i] = frac(Math.pow(prime, 1/2));
+ }
+ this._key[i] = frac(Math.pow(prime, 1/3));
+ i++;
+ }
+ },
+
+ /**
+ * Perform one cycle of SHA-256.
+ * @param {bitArray} words one block of words.
+ * @private
+ */
+ _block:function (words) {
+ var i, tmp, a, b,
+ w = words.slice(0),
+ h = this._h,
+ k = this._key,
+ h0 = h[0], h1 = h[1], h2 = h[2], h3 = h[3],
+ h4 = h[4], h5 = h[5], h6 = h[6], h7 = h[7];
+
+ /* Rationale for placement of |0 :
+ * If a value can overflow is original 32 bits by a factor of more than a few
+ * million (2^23 ish), there is a possibility that it might overflow the
+ * 53-bit mantissa and lose precision.
+ *
+ * To avoid this, we clamp back to 32 bits by |'ing with 0 on any value that
+ * propagates around the loop, and on the hash state h[]. I don't believe
+ * that the clamps on h4 and on h0 are strictly necessary, but it's close
+ * (for h4 anyway), and better safe than sorry.
+ *
+ * The clamps on h[] are necessary for the output to be correct even in the
+ * common case and for short inputs.
+ */
+ for (i=0; i<64; i++) {
+ // load up the input word for this round
+ if (i<16) {
+ tmp = w[i];
+ } else {
+ a = w[(i+1 ) & 15];
+ b = w[(i+14) & 15];
+ tmp = w[i&15] = ((a>>>7 ^ a>>>18 ^ a>>>3 ^ a<<25 ^ a<<14) +
+ (b>>>17 ^ b>>>19 ^ b>>>10 ^ b<<15 ^ b<<13) +
+ w[i&15] + w[(i+9) & 15]) | 0;
+ }
+
+ tmp = (tmp + h7 + (h4>>>6 ^ h4>>>11 ^ h4>>>25 ^ h4<<26 ^ h4<<21 ^ h4<<7) + (h6 ^ h4&(h5^h6)) + k[i]); // | 0;
+
+ // shift register
+ h7 = h6; h6 = h5; h5 = h4;
+ h4 = h3 + tmp | 0;
+ h3 = h2; h2 = h1; h1 = h0;
+
+ h0 = (tmp + ((h1&h2) ^ (h3&(h1^h2))) + (h1>>>2 ^ h1>>>13 ^ h1>>>22 ^ h1<<30 ^ h1<<19 ^ h1<<10)) | 0;
+ }
+
+ h[0] = h[0]+h0 | 0;
+ h[1] = h[1]+h1 | 0;
+ h[2] = h[2]+h2 | 0;
+ h[3] = h[3]+h3 | 0;
+ h[4] = h[4]+h4 | 0;
+ h[5] = h[5]+h5 | 0;
+ h[6] = h[6]+h6 | 0;
+ h[7] = h[7]+h7 | 0;
+ }
+};
+
+
diff --git a/src/js/sjcl/core/sha512.js b/src/js/sjcl/core/sha512.js
new file mode 100644
index 00000000..8bd29648
--- /dev/null
+++ b/src/js/sjcl/core/sha512.js
@@ -0,0 +1,348 @@
+/** @fileOverview Javascript SHA-512 implementation.
+ *
+ * This implementation was written for CryptoJS by Jeff Mott and adapted for
+ * SJCL by Stefan Thomas.
+ *
+ * CryptoJS (c) 2009–2012 by Jeff Mott. All rights reserved.
+ * Released with New BSD License
+ *
+ * @author Emily Stark
+ * @author Mike Hamburg
+ * @author Dan Boneh
+ * @author Jeff Mott
+ * @author Stefan Thomas
+ */
+
+/**
+ * Context for a SHA-512 operation in progress.
+ * @constructor
+ * @class Secure Hash Algorithm, 512 bits.
+ */
+sjcl.hash.sha512 = function (hash) {
+ if (!this._key[0]) { this._precompute(); }
+ if (hash) {
+ this._h = hash._h.slice(0);
+ this._buffer = hash._buffer.slice(0);
+ this._length = hash._length;
+ } else {
+ this.reset();
+ }
+};
+
+/**
+ * Hash a string or an array of words.
+ * @static
+ * @param {bitArray|String} data the data to hash.
+ * @return {bitArray} The hash value, an array of 16 big-endian words.
+ */
+sjcl.hash.sha512.hash = function (data) {
+ return (new sjcl.hash.sha512()).update(data).finalize();
+};
+
+sjcl.hash.sha512.prototype = {
+ /**
+ * The hash's block size, in bits.
+ * @constant
+ */
+ blockSize: 1024,
+
+ /**
+ * Reset the hash state.
+ * @return this
+ */
+ reset:function () {
+ this._h = this._init.slice(0);
+ this._buffer = [];
+ this._length = 0;
+ return this;
+ },
+
+ /**
+ * Input several words to the hash.
+ * @param {bitArray|String} data the data to hash.
+ * @return this
+ */
+ update: function (data) {
+ if (typeof data === "string") {
+ data = sjcl.codec.utf8String.toBits(data);
+ }
+ var i, b = this._buffer = sjcl.bitArray.concat(this._buffer, data),
+ ol = this._length,
+ nl = this._length = ol + sjcl.bitArray.bitLength(data);
+ for (i = 1024+ol & -1024; i <= nl; i+= 1024) {
+ this._block(b.splice(0,32));
+ }
+ return this;
+ },
+
+ /**
+ * Complete hashing and output the hash value.
+ * @return {bitArray} The hash value, an array of 16 big-endian words.
+ */
+ finalize:function () {
+ var i, b = this._buffer, h = this._h;
+
+ // Round out and push the buffer
+ b = sjcl.bitArray.concat(b, [sjcl.bitArray.partial(1,1)]);
+
+ // Round out the buffer to a multiple of 32 words, less the 4 length words.
+ for (i = b.length + 4; i & 31; i++) {
+ b.push(0);
+ }
+
+ // append the length
+ b.push(0);
+ b.push(0);
+ b.push(Math.floor(this._length / 0x100000000));
+ b.push(this._length | 0);
+
+ while (b.length) {
+ this._block(b.splice(0,32));
+ }
+
+ this.reset();
+ return h;
+ },
+
+ /**
+ * The SHA-512 initialization vector, to be precomputed.
+ * @private
+ */
+ _init:[],
+
+ /**
+ * Least significant 24 bits of SHA512 initialization values.
+ *
+ * Javascript only has 53 bits of precision, so we compute the 40 most
+ * significant bits and add the remaining 24 bits as constants.
+ *
+ * @private
+ */
+ _initr: [ 0xbcc908, 0xcaa73b, 0x94f82b, 0x1d36f1, 0xe682d1, 0x3e6c1f, 0x41bd6b, 0x7e2179 ],
+
+ /*
+ _init:
+ [0x6a09e667, 0xf3bcc908, 0xbb67ae85, 0x84caa73b, 0x3c6ef372, 0xfe94f82b, 0xa54ff53a, 0x5f1d36f1,
+ 0x510e527f, 0xade682d1, 0x9b05688c, 0x2b3e6c1f, 0x1f83d9ab, 0xfb41bd6b, 0x5be0cd19, 0x137e2179],
+ */
+
+ /**
+ * The SHA-512 hash key, to be precomputed.
+ * @private
+ */
+ _key:[],
+
+ /**
+ * Least significant 24 bits of SHA512 key values.
+ * @private
+ */
+ _keyr:
+ [0x28ae22, 0xef65cd, 0x4d3b2f, 0x89dbbc, 0x48b538, 0x05d019, 0x194f9b, 0x6d8118,
+ 0x030242, 0x706fbe, 0xe4b28c, 0xffb4e2, 0x7b896f, 0x1696b1, 0xc71235, 0x692694,
+ 0xf14ad2, 0x4f25e3, 0x8cd5b5, 0xac9c65, 0x2b0275, 0xa6e483, 0x41fbd4, 0x1153b5,
+ 0x66dfab, 0xb43210, 0xfb213f, 0xef0ee4, 0xa88fc2, 0x0aa725, 0x03826f, 0x0e6e70,
+ 0xd22ffc, 0x26c926, 0xc42aed, 0x95b3df, 0xaf63de, 0x77b2a8, 0xedaee6, 0x82353b,
+ 0xf10364, 0x423001, 0xf89791, 0x54be30, 0xef5218, 0x65a910, 0x71202a, 0xbbd1b8,
+ 0xd2d0c8, 0x41ab53, 0x8eeb99, 0x9b48a8, 0xc95a63, 0x418acb, 0x63e373, 0xb2b8a3,
+ 0xefb2fc, 0x172f60, 0xf0ab72, 0x6439ec, 0x631e28, 0x82bde9, 0xc67915, 0x72532b,
+ 0x26619c, 0xc0c207, 0xe0eb1e, 0x6ed178, 0x176fba, 0xc898a6, 0xf90dae, 0x1c471b,
+ 0x047d84, 0xc72493, 0xc9bebc, 0x100d4c, 0x3e42b6, 0x657e2a, 0xd6faec, 0x475817],
+
+ /*
+ _key:
+ [0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd, 0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc,
+ 0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019, 0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118,
+ 0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe, 0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2,
+ 0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1, 0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694,
+ 0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3, 0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65,
+ 0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483, 0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5,
+ 0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210, 0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4,
+ 0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725, 0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70,
+ 0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926, 0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df,
+ 0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8, 0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b,
+ 0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001, 0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30,
+ 0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910, 0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8,
+ 0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53, 0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8,
+ 0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb, 0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3,
+ 0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60, 0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec,
+ 0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9, 0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b,
+ 0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207, 0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178,
+ 0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6, 0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b,
+ 0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493, 0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c,
+ 0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a, 0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817],
+ */
+
+ /**
+ * Function to precompute _init and _key.
+ * @private
+ */
+ _precompute: function () {
+ // XXX: This code is for precomputing the SHA256 constants, change for
+ // SHA512 and re-enable.
+ var i = 0, prime = 2, factor;
+
+ function frac(x) { return (x-Math.floor(x)) * 0x100000000 | 0; }
+ function frac2(x) { return (x-Math.floor(x)) * 0x10000000000 & 0xff; }
+
+ outer: for (; i<80; prime++) {
+ for (factor=2; factor*factor <= prime; factor++) {
+ if (prime % factor === 0) {
+ // not a prime
+ continue outer;
+ }
+ }
+
+ if (i<8) {
+ this._init[i*2] = frac(Math.pow(prime, 1/2));
+ this._init[i*2+1] = (frac2(Math.pow(prime, 1/2)) << 24) | this._initr[i];
+ }
+ this._key[i*2] = frac(Math.pow(prime, 1/3));
+ this._key[i*2+1] = (frac2(Math.pow(prime, 1/3)) << 24) | this._keyr[i];
+ i++;
+ }
+ },
+
+ /**
+ * Perform one cycle of SHA-512.
+ * @param {bitArray} words one block of words.
+ * @private
+ */
+ _block:function (words) {
+ var i, wrh, wrl,
+ w = words.slice(0),
+ h = this._h,
+ k = this._key,
+ h0h = h[ 0], h0l = h[ 1], h1h = h[ 2], h1l = h[ 3],
+ h2h = h[ 4], h2l = h[ 5], h3h = h[ 6], h3l = h[ 7],
+ h4h = h[ 8], h4l = h[ 9], h5h = h[10], h5l = h[11],
+ h6h = h[12], h6l = h[13], h7h = h[14], h7l = h[15];
+
+ // Working variables
+ var ah = h0h, al = h0l, bh = h1h, bl = h1l,
+ ch = h2h, cl = h2l, dh = h3h, dl = h3l,
+ eh = h4h, el = h4l, fh = h5h, fl = h5l,
+ gh = h6h, gl = h6l, hh = h7h, hl = h7l;
+
+ for (i=0; i<80; i++) {
+ // load up the input word for this round
+ if (i<16) {
+ wrh = w[i * 2];
+ wrl = w[i * 2 + 1];
+ } else {
+ // Gamma0
+ var gamma0xh = w[(i-15) * 2];
+ var gamma0xl = w[(i-15) * 2 + 1];
+ var gamma0h =
+ ((gamma0xl << 31) | (gamma0xh >>> 1)) ^
+ ((gamma0xl << 24) | (gamma0xh >>> 8)) ^
+ (gamma0xh >>> 7);
+ var gamma0l =
+ ((gamma0xh << 31) | (gamma0xl >>> 1)) ^
+ ((gamma0xh << 24) | (gamma0xl >>> 8)) ^
+ ((gamma0xh << 25) | (gamma0xl >>> 7));
+
+ // Gamma1
+ var gamma1xh = w[(i-2) * 2];
+ var gamma1xl = w[(i-2) * 2 + 1];
+ var gamma1h =
+ ((gamma1xl << 13) | (gamma1xh >>> 19)) ^
+ ((gamma1xh << 3) | (gamma1xl >>> 29)) ^
+ (gamma1xh >>> 6);
+ var gamma1l =
+ ((gamma1xh << 13) | (gamma1xl >>> 19)) ^
+ ((gamma1xl << 3) | (gamma1xh >>> 29)) ^
+ ((gamma1xh << 26) | (gamma1xl >>> 6));
+
+ // Shortcuts
+ var wr7h = w[(i-7) * 2];
+ var wr7l = w[(i-7) * 2 + 1];
+
+ var wr16h = w[(i-16) * 2];
+ var wr16l = w[(i-16) * 2 + 1];
+
+ // W(round) = gamma0 + W(round - 7) + gamma1 + W(round - 16)
+ wrl = gamma0l + wr7l;
+ wrh = gamma0h + wr7h + ((wrl >>> 0) < (gamma0l >>> 0) ? 1 : 0);
+ wrl += gamma1l;
+ wrh += gamma1h + ((wrl >>> 0) < (gamma1l >>> 0) ? 1 : 0);
+ wrl += wr16l;
+ wrh += wr16h + ((wrl >>> 0) < (wr16l >>> 0) ? 1 : 0);
+ }
+
+ w[i*2] = wrh |= 0;
+ w[i*2 + 1] = wrl |= 0;
+
+ // Ch
+ var chh = (eh & fh) ^ (~eh & gh);
+ var chl = (el & fl) ^ (~el & gl);
+
+ // Maj
+ var majh = (ah & bh) ^ (ah & ch) ^ (bh & ch);
+ var majl = (al & bl) ^ (al & cl) ^ (bl & cl);
+
+ // Sigma0
+ var sigma0h = ((al << 4) | (ah >>> 28)) ^ ((ah << 30) | (al >>> 2)) ^ ((ah << 25) | (al >>> 7));
+ var sigma0l = ((ah << 4) | (al >>> 28)) ^ ((al << 30) | (ah >>> 2)) ^ ((al << 25) | (ah >>> 7));
+
+ // Sigma1
+ var sigma1h = ((el << 18) | (eh >>> 14)) ^ ((el << 14) | (eh >>> 18)) ^ ((eh << 23) | (el >>> 9));
+ var sigma1l = ((eh << 18) | (el >>> 14)) ^ ((eh << 14) | (el >>> 18)) ^ ((el << 23) | (eh >>> 9));
+
+ // K(round)
+ var krh = k[i*2];
+ var krl = k[i*2+1];
+
+ // t1 = h + sigma1 + ch + K(round) + W(round)
+ var t1l = hl + sigma1l;
+ var t1h = hh + sigma1h + ((t1l >>> 0) < (hl >>> 0) ? 1 : 0);
+ t1l += chl;
+ t1h += chh + ((t1l >>> 0) < (chl >>> 0) ? 1 : 0);
+ t1l += krl;
+ t1h += krh + ((t1l >>> 0) < (krl >>> 0) ? 1 : 0);
+ t1l += wrl;
+ t1h += wrh + ((t1l >>> 0) < (wrl >>> 0) ? 1 : 0);
+
+ // t2 = sigma0 + maj
+ var t2l = sigma0l + majl;
+ var t2h = sigma0h + majh + ((t2l >>> 0) < (sigma0l >>> 0) ? 1 : 0);
+
+ // Update working variables
+ hh = gh;
+ hl = gl;
+ gh = fh;
+ gl = fl;
+ fh = eh;
+ fl = el;
+ el = (dl + t1l) | 0;
+ eh = (dh + t1h + ((el >>> 0) < (dl >>> 0) ? 1 : 0)) | 0;
+ dh = ch;
+ dl = cl;
+ ch = bh;
+ cl = bl;
+ bh = ah;
+ bl = al;
+ al = (t1l + t2l) | 0;
+ ah = (t1h + t2h + ((al >>> 0) < (t1l >>> 0) ? 1 : 0)) | 0;
+ }
+
+ // Intermediate hash
+ h0l = h[1] = (h0l + al) | 0;
+ h[0] = (h0h + ah + ((h0l >>> 0) < (al >>> 0) ? 1 : 0)) | 0;
+ h1l = h[3] = (h1l + bl) | 0;
+ h[2] = (h1h + bh + ((h1l >>> 0) < (bl >>> 0) ? 1 : 0)) | 0;
+ h2l = h[5] = (h2l + cl) | 0;
+ h[4] = (h2h + ch + ((h2l >>> 0) < (cl >>> 0) ? 1 : 0)) | 0;
+ h3l = h[7] = (h3l + dl) | 0;
+ h[6] = (h3h + dh + ((h3l >>> 0) < (dl >>> 0) ? 1 : 0)) | 0;
+ h4l = h[9] = (h4l + el) | 0;
+ h[8] = (h4h + eh + ((h4l >>> 0) < (el >>> 0) ? 1 : 0)) | 0;
+ h5l = h[11] = (h5l + fl) | 0;
+ h[10] = (h5h + fh + ((h5l >>> 0) < (fl >>> 0) ? 1 : 0)) | 0;
+ h6l = h[13] = (h6l + gl) | 0;
+ h[12] = (h6h + gh + ((h6l >>> 0) < (gl >>> 0) ? 1 : 0)) | 0;
+ h7l = h[15] = (h7l + hl) | 0;
+ h[14] = (h7h + hh + ((h7l >>> 0) < (hl >>> 0) ? 1 : 0)) | 0;
+ }
+};
+
+
diff --git a/src/js/sjcl/core/sjcl.js b/src/js/sjcl/core/sjcl.js
new file mode 100644
index 00000000..d2da8e9c
--- /dev/null
+++ b/src/js/sjcl/core/sjcl.js
@@ -0,0 +1,73 @@
+/** @fileOverview Javascript cryptography implementation.
+ *
+ * Crush to remove comments, shorten variable names and
+ * generally reduce transmission size.
+ *
+ * @author Emily Stark
+ * @author Mike Hamburg
+ * @author Dan Boneh
+ */
+
+"use strict";
+/*jslint indent: 2, bitwise: false, nomen: false, plusplus: false, white: false, regexp: false */
+/*global document, window, escape, unescape */
+
+/** @namespace The Stanford Javascript Crypto Library, top-level namespace. */
+var sjcl = {
+ /** @namespace Symmetric ciphers. */
+ cipher: {},
+
+ /** @namespace Hash functions. Right now only SHA256 is implemented. */
+ hash: {},
+
+ /** @namespace Key exchange functions. Right now only SRP is implemented. */
+ keyexchange: {},
+
+ /** @namespace Block cipher modes of operation. */
+ mode: {},
+
+ /** @namespace Miscellaneous. HMAC and PBKDF2. */
+ misc: {},
+
+ /**
+ * @namespace Bit array encoders and decoders.
+ *
+ * @description
+ * The members of this namespace are functions which translate between
+ * SJCL's bitArrays and other objects (usually strings). Because it
+ * isn't always clear which direction is encoding and which is decoding,
+ * the method names are "fromBits" and "toBits".
+ */
+ codec: {},
+
+ /** @namespace Exceptions. */
+ exception: {
+ /** @constructor Ciphertext is corrupt. */
+ corrupt: function(message) {
+ this.toString = function() { return "CORRUPT: "+this.message; };
+ this.message = message;
+ },
+
+ /** @constructor Invalid parameter. */
+ invalid: function(message) {
+ this.toString = function() { return "INVALID: "+this.message; };
+ this.message = message;
+ },
+
+ /** @constructor Bug or missing feature in SJCL. @constructor */
+ bug: function(message) {
+ this.toString = function() { return "BUG: "+this.message; };
+ this.message = message;
+ },
+
+ /** @constructor Something isn't ready. */
+ notReady: function(message) {
+ this.toString = function() { return "NOT READY: "+this.message; };
+ this.message = message;
+ }
+ }
+};
+
+if(typeof module != 'undefined' && module.exports){
+ module.exports = sjcl;
+}
diff --git a/src/js/sjcl/core/srp.js b/src/js/sjcl/core/srp.js
new file mode 100644
index 00000000..1b5a4b8a
--- /dev/null
+++ b/src/js/sjcl/core/srp.js
@@ -0,0 +1,113 @@
+/** @fileOverview Javascript SRP implementation.
+ *
+ * This file contains a partial implementation of the SRP (Secure Remote
+ * Password) password-authenticated key exchange protocol. Given a user
+ * identity, salt, and SRP group, it generates the SRP verifier that may
+ * be sent to a remote server to establish and SRP account.
+ *
+ * For more information, see http://srp.stanford.edu/.
+ *
+ * @author Quinn Slack
+ */
+
+/**
+ * Compute the SRP verifier from the username, password, salt, and group.
+ * @class SRP
+ */
+sjcl.keyexchange.srp = {
+ /**
+ * Calculates SRP v, the verifier.
+ * v = g^x mod N [RFC 5054]
+ * @param {String} I The username.
+ * @param {String} P The password.
+ * @param {Object} s A bitArray of the salt.
+ * @param {Object} group The SRP group. Use sjcl.keyexchange.srp.knownGroup
+ to obtain this object.
+ * @return {Object} A bitArray of SRP v.
+ */
+ makeVerifier: function(I, P, s, group) {
+ var x;
+ x = sjcl.keyexchange.srp.makeX(I, P, s);
+ x = sjcl.bn.fromBits(x);
+ return group.g.powermod(x, group.N);
+ },
+
+ /**
+ * Calculates SRP x.
+ * x = SHA1( | SHA( | ":" | )) [RFC 2945]
+ * @param {String} I The username.
+ * @param {String} P The password.
+ * @param {Object} s A bitArray of the salt.
+ * @return {Object} A bitArray of SRP x.
+ */
+ makeX: function(I, P, s) {
+ var inner = sjcl.hash.sha1.hash(I + ':' + P);
+ return sjcl.hash.sha1.hash(sjcl.bitArray.concat(s, inner));
+ },
+
+ /**
+ * Returns the known SRP group with the given size (in bits).
+ * @param {String} i The size of the known SRP group.
+ * @return {Object} An object with "N" and "g" properties.
+ */
+ knownGroup:function(i) {
+ if (typeof i !== "string") { i = i.toString(); }
+ if (!sjcl.keyexchange.srp._didInitKnownGroups) { sjcl.keyexchange.srp._initKnownGroups(); }
+ return sjcl.keyexchange.srp._knownGroups[i];
+ },
+
+ /**
+ * Initializes bignum objects for known group parameters.
+ * @private
+ */
+ _didInitKnownGroups: false,
+ _initKnownGroups:function() {
+ var i, size, group;
+ for (i=0; i < sjcl.keyexchange.srp._knownGroupSizes.length; i++) {
+ size = sjcl.keyexchange.srp._knownGroupSizes[i].toString();
+ group = sjcl.keyexchange.srp._knownGroups[size];
+ group.N = new sjcl.bn(group.N);
+ group.g = new sjcl.bn(group.g);
+ }
+ sjcl.keyexchange.srp._didInitKnownGroups = true;
+ },
+
+ _knownGroupSizes: [1024, 1536, 2048],
+ _knownGroups: {
+ 1024: {
+ N: "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C" +
+ "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4" +
+ "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29" +
+ "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A" +
+ "FD5138FE8376435B9FC61D2FC0EB06E3",
+ g:2
+ },
+
+ 1536: {
+ N: "9DEF3CAFB939277AB1F12A8617A47BBBDBA51DF499AC4C80BEEEA961" +
+ "4B19CC4D5F4F5F556E27CBDE51C6A94BE4607A291558903BA0D0F843" +
+ "80B655BB9A22E8DCDF028A7CEC67F0D08134B1C8B97989149B609E0B" +
+ "E3BAB63D47548381DBC5B1FC764E3F4B53DD9DA1158BFD3E2B9C8CF5" +
+ "6EDF019539349627DB2FD53D24B7C48665772E437D6C7F8CE442734A" +
+ "F7CCB7AE837C264AE3A9BEB87F8A2FE9B8B5292E5A021FFF5E91479E" +
+ "8CE7A28C2442C6F315180F93499A234DCF76E3FED135F9BB",
+ g: 2
+ },
+
+ 2048: {
+ N: "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC319294" +
+ "3DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310D" +
+ "CD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FB" +
+ "D5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF74" +
+ "7359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A" +
+ "436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D" +
+ "5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E73" +
+ "03CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB6" +
+ "94B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F" +
+ "9E4AFF73",
+ g: 2
+ }
+ }
+
+};
+
diff --git a/src/js/sjcl/demo/alpha-arrow.png b/src/js/sjcl/demo/alpha-arrow.png
new file mode 100644
index 00000000..e4334a7d
Binary files /dev/null and b/src/js/sjcl/demo/alpha-arrow.png differ
diff --git a/src/js/sjcl/demo/example.css b/src/js/sjcl/demo/example.css
new file mode 100644
index 00000000..7fcfb737
--- /dev/null
+++ b/src/js/sjcl/demo/example.css
@@ -0,0 +1,179 @@
+* {
+ margin: 0px;
+ padding: 0px;
+ font-family: Arial, Helvetica, FreeSans, sans;
+}
+
+h1 {
+ text-align: center;
+ background: #eee;
+ padding: 5px;
+ margin-bottom: 0.6em;
+ font-size: 1.5em;
+}
+
+.header {
+ width: 650px;
+ margin: 0px auto 1em;
+}
+
+p+p {
+ margin-top: 1em;
+}
+
+.explanation {
+ color: #555;
+ margin-top: 0.3em;
+}
+
+.section+.section, .explanation+.section {
+ margin-top: 1.5em;
+}
+
+.hex {
+ text-transform: uppercase;
+}
+
+.hex, .base64, #ciphertext {
+ font-family: 'Courier', mono;
+}
+
+.wide, textarea {
+ width: 100%;
+ margin: 0px -4px;
+ font-size: inherit;
+ text-align: left;
+}
+
+textarea+*, .wide+* {
+ margin-top: 0.3em;
+}
+
+/* bulk object placement */
+#theForm {
+ position: relative;
+ width: 940px;
+ margin: 0px auto;
+ font-size: 0.8em;
+}
+
+.column {
+ top: 0px;
+ width: 300px;
+}
+
+.box {
+ border: 2px solid #999;
+ padding: 7px;
+ margin-bottom: 20px;
+ -moz-border-radius: 7px;
+ -webkit-border-radius: 7px;
+}
+
+#cmode { position: absolute; left: 640px; }
+#ctexts { position: absolute; left: 320px; }
+
+.floatright {
+ float: right;
+ text-align: right;
+}
+
+a {
+ cursor: pointer;
+ color: #282;
+}
+
+a.random, #buttons a { text-decoration: none; }
+a.random:hover, a.random:focus { text-decoration: underline; }
+
+h2 {
+ margin: -7px -7px 3px -7px;
+ text-align: center;
+ font-size: 1.2em;
+ color: white;
+ background: #999;
+}
+
+#pplaintext { border-color: #f65; }
+#pplaintext h2 { background: #f65; }
+
+#ppassword { border-color: #4a4; }
+#ppassword h2 { background: #4a4; }
+
+#pciphertext { border-color: #78f; }
+#pciphertext h2 { background: #78f; }
+
+#buttons { text-align: center; margin-top: -20px; }
+
+a#doPbkdf2, a#encrypt, a#decrypt {
+ display: inline-block;
+ text-align: center;
+ height: 43px;
+ padding-top: 20px;
+ width: 50px;
+ background: url('alpha-arrow.png') no-repeat bottom center;
+ vertical-align: middle;
+ border: none;
+ color: white;
+ overflow: hidden;
+}
+
+.turnDown {
+ display: inline-block;
+ padding-bottom: 3px;
+ -moz-transform: rotate(90deg);
+ -webkit-transform: rotate(90deg);
+ transform: rotate(90deg);
+ background-color: inherit;
+}
+
+.turnUp {
+ display: inline-block;
+ padding-bottom: 3px;
+ -moz-transform: rotate(-90deg);
+ -webkit-transform: rotate(-90deg);
+ transform: rotate(-90deg);
+ background-color: inherit;
+}
+
+.buttons a.disabled {
+ background-color: #ccc ! important;
+ cursor: inherit ! important;
+}
+
+a#encrypt { background-color: #f65; margin-bottom: 2px; }
+a#encrypt:hover, a#encrypt:focus { background-color: #f76; }
+a#encrypt:active { background-color: #f87; }
+
+a#decrypt {
+ height: 36px;
+ padding-top: 27px;
+ background: url('alpha-arrow.png') no-repeat top center;
+ background-color: #78f;
+ margin-top: 2px;
+}
+a#decrypt:hover { background-color: #89f; }
+a#decrypt:focus { background-color: #89f; }
+a#decrypt:active { background-color: #9af; }
+
+#ppassword, #pkey, #pmode, #pplaintext, #pciphertext {
+ -moz-border-radius: 7px;
+ -webkit-border-radius: 7px;
+}
+input[type='text'], input[type='password'], textarea {
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ font-size: inherit;
+ border: 1px solid #444;
+ padding: 3px;
+}
+
+input[type='text']:focus, input[type='password']:focus, textarea:focus {
+ border-color: red;
+}
+
+input[type="radio"], input[type="checkbox"] {
+ position: relative;
+ top: 0.15em;
+ margin-right: -0.15em;
+}
diff --git a/src/js/sjcl/demo/example.js b/src/js/sjcl/demo/example.js
new file mode 100644
index 00000000..940402b0
--- /dev/null
+++ b/src/js/sjcl/demo/example.js
@@ -0,0 +1,153 @@
+/* keep track of which salts have been used. */
+var form, usedIvs = {'':1}, usedSalts = {'':1};
+
+/* enter actions */
+var enterActions = {
+ password: doPbkdf2,
+ salt: doPbkdf2,
+ iter: doPbkdf2
+};
+
+function loaded() {
+ form = new formHandler('theForm', enterActions);
+ form._extendedKey = [];
+ sjcl.random.startCollectors();
+ document.getElementById("password").focus();
+}
+
+/* there's probaby a better way to tell the user something, but oh well */
+function error(x) {
+ alert(x);
+}
+
+/* compute PBKDF2 on the password. */
+function doPbkdf2(decrypting) {
+ var v = form.get(), salt=v.salt, key, hex = sjcl.codec.hex.fromBits, p={},
+ password = v.password;
+
+ p.iter = v.iter;
+
+ if (password.length == 0) {
+ if (decrypting) { error("Can't decrypt: need a password!"); }
+ return;
+ }
+
+ if (salt.length === 0 && decrypting) {
+ error("Can't decrypt: need a salt for PBKDF2!");
+ return;
+ }
+
+ if (decrypting || !v.freshsalt || !usedSalts[v.salt]) {
+ p.salt = v.salt;
+ }
+
+ p = sjcl.misc.cachedPbkdf2(password, p);
+ form._extendedKey = p.key;
+ v.key = p.key.slice(0, v.keysize/32);
+ v.salt = p.salt;
+
+ form.set(v);
+ form.plaintext.el.select();
+}
+/* Encrypt a message */
+function doEncrypt() {
+ var v = form.get(), iv = v.iv, password = v.password, key = v.key, adata = v.adata, aes, plaintext=v.plaintext, rp = {}, ct, p;
+
+ if (plaintext === '' && v.ciphertext.length) { return; }
+ if (key.length == 0 && password.length == 0) {
+ error("need a password or key!");
+ return;
+ }
+
+ p = { adata:v.adata,
+ iter:v.iter,
+ mode:v.mode,
+ ts:parseInt(v.tag),
+ ks:parseInt(v.keysize) };
+ if (!v.freshiv || !usedIvs[v.iv]) { p.iv = v.iv; }
+ if (!v.freshsalt || !usedSalts[v.salt]) { p.salt = v.salt; }
+ ct = sjcl.encrypt(password || key, plaintext, p, rp).replace(/,/g,",\n");
+
+ v.iv = rp.iv;
+ usedIvs[rp.iv] = 1;
+ if (rp.salt) {
+ v.salt = rp.salt;
+ usedSalts[rp.salt] = 1;
+ }
+ v.key = rp.key;
+
+ if (v.json) {
+ v.ciphertext = ct;
+ v.adata = '';
+ } else {
+ v.ciphertext = ct.match(/"ct":"([^"]*)"/)[1]; //"
+ }
+
+ v.plaintext = '';
+
+ form.set(v);
+ form.ciphertext.el.select();
+}
+
+/* Decrypt a message */
+function doDecrypt() {
+ var v = form.get(), iv = v.iv, key = v.key, adata = v.adata, aes, ciphertext=v.ciphertext, rp = {};
+
+ if (ciphertext.length === 0) { return; }
+ if (!v.password && !v.key.length) {
+ error("Can't decrypt: need a password or key!"); return;
+ }
+
+ if (ciphertext.match("{")) {
+ /* it's jsonized */
+ try {
+ v.plaintext = sjcl.decrypt(v.password || v.key, ciphertext, {}, rp);
+ } catch(e) {
+ error("Can't decrypt: "+e);
+ return;
+ }
+ v.mode = rp.mode;
+ v.iv = rp.iv;
+ v.adata = rp.adata;
+ if (v.password) {
+ v.salt = rp.salt;
+ v.iter = rp.iter;
+ v.keysize = rp.ks;
+ v.tag = rp.ts;
+ }
+ v.key = rp.key;
+ v.ciphertext = "";
+ document.getElementById('plaintext').select();
+ } else {
+ /* it's raw */
+ ciphertext = sjcl.codec.base64.toBits(ciphertext);
+ if (iv.length === 0) {
+ error("Can't decrypt: need an IV!"); return;
+ }
+ if (key.length === 0) {
+ if (v.password.length) {
+ doPbkdf2(true);
+ key = v.key;
+ }
+ }
+ aes = new sjcl.cipher.aes(key);
+
+ try {
+ v.plaintext = sjcl.codec.utf8String.fromBits(sjcl.mode[v.mode].decrypt(aes, ciphertext, iv, v.adata, v.tag));
+ v.ciphertext = "";
+ document.getElementById('plaintext').select();
+ } catch (e) {
+ error("Can't decrypt: " + e);
+ }
+ }
+ form.set(v);
+}
+
+function extendKey(size) {
+ form.key.set(form._extendedKey.slice(0,size));
+}
+
+function randomize(field, words, paranoia) {
+ form[field].set(sjcl.random.randomWords(words, paranoia));
+ if (field == 'salt') { form.key.set([]); }
+}
diff --git a/src/js/sjcl/demo/form.js b/src/js/sjcl/demo/form.js
new file mode 100644
index 00000000..0cd4224f
--- /dev/null
+++ b/src/js/sjcl/demo/form.js
@@ -0,0 +1,137 @@
+/* Hackish form handling system. */
+function hasClass(e, cl) {
+ return (" "+e.className+" ").match(" "+cl+" ");
+}
+
+function stopPropagation(e) {
+ e.preventDefault && e.preventDefault();
+ e.cancelBubble = true;
+}
+
+/* proxy for a form object, with appropriate encoder/decoder */
+function formElement(el) {
+ this.el = el;
+}
+formElement.prototype = {
+ get: function() {
+ var el = this.el;
+ if (el.type == "checkbox") {
+ return el.checked;
+ } else if (hasClass(el, "numeric")) {
+ return parseInt(el.value);
+ } else if (hasClass(el, "hex")) {
+ return sjcl.codec.hex.toBits(el.value);
+ } else if (hasClass(el, "base64")) {
+ return sjcl.codec.base64.toBits(el.value);
+ } else {
+ return el.value;
+ }
+ },
+
+ set: function(x) {
+ var el = this.el;
+ if (el.type == "checkbox") {
+ el.checked = x; return;
+ } else if (hasClass(el, "hex")) {
+ if (typeof x !== 'string') {
+ x = sjcl.codec.hex.fromBits(x);
+ }
+ x = x.toUpperCase().replace(/ /g,'').replace(/(.{8})/g, "$1 ").replace(/ $/, '');
+ } else if (hasClass(el, "base64")) {
+ if (typeof x !== 'string') {
+ x = sjcl.codec.base64.fromBits(x);
+ }
+ x = x.replace(/\s/g,'').replace(/(.{32})/g, "$1\n").replace(/\n$/, '');
+ }
+ el.value = x;
+ }
+}
+
+function radioGroup(name) {
+ this.name = name;
+}
+radioGroup.prototype = {
+ get: function() {
+ var els = document.getElementsByName(this.name), i;
+ for (i=0; i
+
+
+
+ SJCL demo
+
+
+
+
+
+
+
SJCL demo
+
+
+
This page is a demo of the Stanford Javascript Crypto Library. To get started, just type in a password in the left pane and a secret message in the middle pane, then click "encrypt". Encryption takes place in your browser and we never see the plaintext.
+
+
SJCL has lots of other options, many of which are shown in the grey boxes.