mirror of
https://github.com/openpgpjs/openpgpjs.git
synced 2026-03-08 01:51:34 +00:00
adding restructured GPG4Browsers code
- created a test suite available at test/index.html - fixed a bug in MD5 calculation
This commit is contained in:
502
LICENSE
502
LICENSE
@@ -0,0 +1,502 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 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.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
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 and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, 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 library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete 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 distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
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 Library or any portion
|
||||
of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
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 Library, 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 Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you 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.
|
||||
|
||||
If distribution of 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 satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be 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.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library 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.
|
||||
|
||||
9. 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 Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
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 with
|
||||
this License.
|
||||
|
||||
11. 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 Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library 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 Library.
|
||||
|
||||
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.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library 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.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser 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 Library
|
||||
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 Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
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
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "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
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. 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 LIBRARY 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
|
||||
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. 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.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; 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.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
||||
133
plugins/chrome/background.html
Executable file
133
plugins/chrome/background.html
Executable file
@@ -0,0 +1,133 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
//GPG4Browsers - An OpenPGP implementation in javascript
|
||||
//Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
//This library is free software; you can redistribute it and/or
|
||||
//modify it under the terms of the GNU Lesser General Public
|
||||
//License as published by the Free Software Foundation; either
|
||||
//version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
//This library 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
|
||||
//Lesser General Public License for more details.
|
||||
//
|
||||
//You should have received a copy of the GNU Lesser General Public
|
||||
//License along with this library; if not, write to the Free Software
|
||||
//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
var tab_registry = new Array();
|
||||
|
||||
var account_name = null;
|
||||
|
||||
/**
|
||||
* Event listener for chrom.extension message interface.
|
||||
* This is the main data exchange interface for communication between windows.
|
||||
*/
|
||||
function onRequest(request, sender, sendResponse) {
|
||||
// only the extension itself
|
||||
if (document.URL.split("/")[2] != sender.id)
|
||||
return;
|
||||
|
||||
/* the following code is currently not working, but a check for incognito mode would be nice to have here.
|
||||
|
||||
if (chrome.extension.inIncognitoContext != true)
|
||||
alert("enable incognito mode for GPG4Browsers Extension!"+JSON.stringify(chrome.extension.inIncognitoContext));
|
||||
*/
|
||||
|
||||
|
||||
// Show the page action for the tab that the sender (content script)
|
||||
// was on.
|
||||
if (tab_registry[sender.tab.id] != null) {
|
||||
|
||||
sendResponse(tab_registry[sender.tab.id]);
|
||||
tab_registry[sender.tab.id] = null;
|
||||
return;
|
||||
}
|
||||
// page action... open the pgp tab with compose
|
||||
if (request.action == 0) {
|
||||
openComposeWindow(request);
|
||||
sendResponse({});
|
||||
return;
|
||||
}
|
||||
// request from contentscript on gmail interface to open a openpgp window with a message to decrypt/verify
|
||||
if (request.action == 1) {
|
||||
openComposeWindow(request);
|
||||
sendResponse({});
|
||||
return;
|
||||
}
|
||||
|
||||
// openpgp is requesting to open a gmail compose window
|
||||
if (request.action == 2 && sender.tab.id) {
|
||||
openGmailComposeWindow(request);
|
||||
sendResponse({});
|
||||
return;
|
||||
}
|
||||
// contentscript on gmail compose window requesting the message
|
||||
// not used due to missing implemenation
|
||||
if (request.action == 3 && sender.tab.id) {
|
||||
sendResponse(tab_registry[sender.tab.id]);
|
||||
return;
|
||||
}
|
||||
|
||||
account_name = request.account;
|
||||
chrome.pageAction.show(sender.tab.id);
|
||||
|
||||
// Return nothing to let the connection be cleaned up.
|
||||
sendResponse({});
|
||||
}
|
||||
|
||||
chrome.pageAction.onClicked.addListener(pageActionListener);
|
||||
|
||||
/**
|
||||
* opens the Gmail ComposeWindow and transmits the email data
|
||||
* @param to string of recipient email addresses separated by ", "
|
||||
* @param cc string of recipient email addresses separated by ", " receiving a copy
|
||||
* @param cc string of recipient email addresses separated by ", " receiving a blind copy
|
||||
* @param subject email subject as string
|
||||
*/
|
||||
function openGmailComposeWindow(request) {
|
||||
var tab = chrome.tabs.create(
|
||||
{url: "https://mail.google.com/mail/?view=cm&fs=1&tf=1&to="+
|
||||
encodeURIComponent(request.to)+"&cc="+
|
||||
encodeURIComponent(request.cc)+"&bcc="+
|
||||
encodeURIComponent(request.bcc)+"&su="+
|
||||
encodeURIComponent(request.subject)+"&body="+
|
||||
// TODO: long bodys result in an error on the google mail server because the URL gets too long
|
||||
encodeURIComponent(request.body)+"&shva=1", selected: true});
|
||||
// its a good idea to store the request...
|
||||
// once the gmail compose window has opened, the content
|
||||
// script could fetch the request to insert message data
|
||||
// into the forms this would be a proper solution to the
|
||||
// "url too long" issue. Problem: the page is rendered
|
||||
// within an iframe so contentscript has no access to
|
||||
// fill in the data. We have'nt tried the basic html
|
||||
// approach yet.. see action == "3"
|
||||
tab_registry[tab.id] = request;
|
||||
}
|
||||
|
||||
/**
|
||||
* the page action listener event handler:
|
||||
* opens a compose window (openpgp.html)
|
||||
*/
|
||||
function pageActionListener(tab) {
|
||||
openComposeWindow({action: 0, account: account_name});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function openComposeWindow(request) {
|
||||
var tab = chrome.tabs.create({url: "openpgp.html", selected: true }, function(tab) {
|
||||
tab_registry[tab.id] = request;
|
||||
});
|
||||
}
|
||||
|
||||
// Listen for the content script to send a message to the background page.
|
||||
chrome.extension.onRequest.addListener(onRequest);
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
||||
244
plugins/chrome/contentscripts.js
Executable file
244
plugins/chrome/contentscripts.js
Executable file
@@ -0,0 +1,244 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
if (window.location.href.indexOf("https://mail.google.com/mail/?view=cm") == 0) {
|
||||
// we are running in the compose window
|
||||
} else {
|
||||
// we are running in the normal interface
|
||||
chrome.extension.sendRequest({account: document.getElementsByTagName("script")[4].text.split(",")[10].replace(/"/g,"").trim()}, function(response) {});
|
||||
|
||||
}
|
||||
|
||||
var current_message_type = -1;
|
||||
var current_message = null;
|
||||
|
||||
/**
|
||||
* searches the given text for a pgp message. If a message is available the openpgp message dialog is shown
|
||||
* @param text text to be searched
|
||||
*/
|
||||
function find_openpgp(text) {
|
||||
text = text.replace(/\r\n/g,"\n");
|
||||
if (document.location.hash != current_message) {
|
||||
if (/-----BEGIN PGP MESSAGE-----/.test(text) && /-----END PGP MESSAGE-----/.test(text)) {
|
||||
current_message= document.location.hash;
|
||||
current_message_type = 0;
|
||||
current_pgp_block = text.substring(text.indexOf("-----BEGIN PGP MESSAGE-----"), text.indexOf("-----END PGP MESSAGE-----")+25);
|
||||
current_pgp_block = current_pgp_block.replace(/\n/g,"").replace(/<br>/g,"\n").replace(/<wbr>/g,"");
|
||||
if (pgp_verifyCheckSum(current_pgp_block))
|
||||
show_pgp_alert();
|
||||
|
||||
} else if (/-----BEGIN PGP SIGNED MESSAGE-----/.test(text) && /-----END PGP SIGNATURE-----/.test(text)) {
|
||||
current_message= document.location.hash;
|
||||
current_message_type = 1;
|
||||
current_pgp_block = text.substring(text.indexOf("-----BEGIN PGP SIGNED MESSAGE-----"), text.indexOf("-----END PGP SIGNATURE-----")+26);
|
||||
current_pgp_block = current_pgp_block.replace(/\n/g,"").replace(/<br>/g,"\n").replace(/<wbr>/g,"");
|
||||
if (pgp_verifyCheckSum(current_pgp_block.substring(current_pgp_block.indexOf("-----BEGIN PGP SIGNATURE-----"))))
|
||||
show_pgp_alert();
|
||||
} else {
|
||||
hide_pgp_alert();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var doc = null;
|
||||
|
||||
/**
|
||||
* call routine to open the openpgp.html page for handling a message
|
||||
* @return null
|
||||
*/
|
||||
function start_pgp_dialog() {
|
||||
//Gmail does not provide a generic way. to get message data out of the HTML interface so we parse the DOM
|
||||
Gmail.getMail(function(msg) {
|
||||
msg.action = 1;
|
||||
chrome.extension.sendRequest(msg, function(response) {
|
||||
// hide_pgp_alert(); // hide pgp alert after opening the openpgp window
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* showing the pgp alert
|
||||
* @return
|
||||
*/
|
||||
function show_pgp_alert() {
|
||||
var div = document.createElement("div");
|
||||
var buttonyes = document.createElement("button");
|
||||
var buttonno = document.createElement("button");
|
||||
buttonyes.setAttribute("type", "submit");
|
||||
buttonyes.addEventListener("mousedown", function () {
|
||||
var msg = start_pgp_dialog();
|
||||
});
|
||||
buttonno.setAttribute("type", "submit");
|
||||
buttonno.addEventListener("mousedown", function() { hide_pgp_alert(); }, true);
|
||||
buttonyes.appendChild(document.createTextNode("Yes"));
|
||||
buttonno.appendChild(document.createTextNode("No"));
|
||||
div.setAttribute("id", "gpg4browsers_alert");
|
||||
div.setAttribute("style","position: fixed; top: 0px; width: 100%; background-color: #eeeeff; border-bottom: 1px solid #aaa;");
|
||||
if (current_message_type == 0)
|
||||
div.appendChild(document.createTextNode("This mail is encrypted. Do you want to open it with GPG4Browsers?"));
|
||||
else if (current_message_type == 1)
|
||||
div.appendChild(document.createTextNode("This mail is signed. Do you want to open it with GPG4Browsers?"));
|
||||
div.appendChild(buttonyes);
|
||||
div.appendChild(buttonno);
|
||||
document.body.appendChild(div);
|
||||
};
|
||||
|
||||
/**
|
||||
* hiding the pgp alert
|
||||
* @return
|
||||
*/
|
||||
function hide_pgp_alert() {
|
||||
if (document.getElementById("gpg4browsers_alert") != null) {
|
||||
document.getElementById("gpg4browsers_alert").parentNode.removeChild(document.getElementById("gpg4browsers_alert"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* background process timer to constantly check the displayed page for pgp messages
|
||||
*/
|
||||
window.setInterval(function() {
|
||||
find_openpgp(document.body.innerHTML);
|
||||
if (document.getElementById("canvas_frame") != null)
|
||||
find_openpgp(document.getElementById("canvas_frame").contentDocument.body.innerHTML);
|
||||
}, 1000);
|
||||
|
||||
|
||||
/**
|
||||
* verifies the checksum of an base64 encrypted pgp block
|
||||
* @param text containing the base64 block and the base64 encoded checksum
|
||||
* @return true if the checksum was correct, false otherwise
|
||||
*/
|
||||
function pgp_verifyCheckSum(text) {
|
||||
var splittedtext = text.split('-----');
|
||||
var data = r2s(splittedtext[2].split('\n\n')[1].split("\n=")[0]);
|
||||
var checksum = splittedtext[2].split('\n\n')[1].split("\n=")[1].replace(/\n/g,"");
|
||||
var c = getCheckSum(data);
|
||||
var d = checksum;
|
||||
return c[0] == d[0] && c[1] == d[1] && c[2] == d[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* calculates the checksum over a given block of data
|
||||
* @param data block to be used
|
||||
* @return a string containing the base64 encoded checksum
|
||||
*/
|
||||
function getCheckSum(data) {
|
||||
var c = createcrc24(data);
|
||||
var str = "" + String.fromCharCode(c >> 16)+
|
||||
String.fromCharCode((c >> 8) & 0xFF)+
|
||||
String.fromCharCode(c & 0xFF);
|
||||
return s2r(str);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* calculation routine for a CRC-24 checksum
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
function createcrc24 (data) {
|
||||
var crc = 0xB704CE;
|
||||
var i;
|
||||
var mypos = 0;
|
||||
var len = data.length;
|
||||
while (len--) {
|
||||
crc ^= (data[mypos++].charCodeAt()) << 16;
|
||||
for (i = 0; i < 8; i++) {
|
||||
crc <<= 1;
|
||||
if (crc & 0x1000000)
|
||||
crc ^= 0x1864CFB;
|
||||
}
|
||||
}
|
||||
return crc & 0xFFFFFF;
|
||||
}
|
||||
|
||||
// base64 implementation
|
||||
|
||||
var b64s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||
|
||||
/**
|
||||
* Converting Base64 data to a string
|
||||
* @param t base64 encoded data string
|
||||
* @return data string
|
||||
*/
|
||||
function r2s(t) {
|
||||
var c, n;
|
||||
var r = '', s = 0, a = 0;
|
||||
var tl = t.length;
|
||||
|
||||
for (n = 0; n < tl; n++) {
|
||||
c = b64s.indexOf(t.charAt(n));
|
||||
if (c >= 0) {
|
||||
if (s)
|
||||
r += String.fromCharCode(a | (c >> (6 - s)) & 255);
|
||||
s = (s + 2) & 7;
|
||||
a = (c << s) & 255;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converting a data string to a base64 encoded string
|
||||
* @param t data string
|
||||
* @return base64 encoded data string
|
||||
*/
|
||||
function s2r(t) {
|
||||
var a, c, n;
|
||||
var r = '', l = 0, s = 0;
|
||||
var tl = t.length;
|
||||
|
||||
for (n = 0; n < tl; n++) {
|
||||
c = t.charCodeAt(n);
|
||||
if (s == 0) {
|
||||
r += b64s.charAt((c >> 2) & 63);
|
||||
a = (c & 3) << 4;
|
||||
} else if (s == 1) {
|
||||
r += b64s.charAt((a | (c >> 4) & 15));
|
||||
a = (c & 15) << 2;
|
||||
} else if (s == 2) {
|
||||
r += b64s.charAt(a | ((c >> 6) & 3));
|
||||
l += 1;
|
||||
if ((l % 60) == 0)
|
||||
r += "\n";
|
||||
r += b64s.charAt(c & 63);
|
||||
}
|
||||
l += 1;
|
||||
if ((l % 60) == 0)
|
||||
r += "\n";
|
||||
|
||||
s += 1;
|
||||
if (s == 3)
|
||||
s = 0;
|
||||
}
|
||||
if (s > 0) {
|
||||
r += b64s.charAt(a);
|
||||
l += 1;
|
||||
if ((l % 60) == 0)
|
||||
r += "\n";
|
||||
r += '=';
|
||||
l += 1;
|
||||
}
|
||||
if (s == 1) {
|
||||
if ((l % 60) == 0)
|
||||
r += "\n";
|
||||
r += '=';
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
18
plugins/chrome/jquery.min.js
vendored
Executable file
18
plugins/chrome/jquery.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
32
plugins/chrome/manifest.json
Executable file
32
plugins/chrome/manifest.json
Executable file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"name" : "GPG4Browsers",
|
||||
"version" : "0.1",
|
||||
"description" : "An OpenPGP implementation in javascript",
|
||||
"background_page" : "background.html",
|
||||
"options_page": "options.html",
|
||||
"page_action" :
|
||||
{
|
||||
"default_icon" : "images/icons/logo.png",
|
||||
"default_title" : "Create encrypted Message"
|
||||
},
|
||||
"content_scripts" : [
|
||||
{
|
||||
"matches" : [
|
||||
"https://mail.google.com/*"
|
||||
],
|
||||
"js" : ["jquery.min.js", "contentscripts.js", "gmail.js"],
|
||||
"run_at" : "document_idle",
|
||||
"all_frames" : false
|
||||
}
|
||||
],
|
||||
"incoginto": "split",
|
||||
"permissions": [
|
||||
"https://mail.google.com/*",
|
||||
"http://keyserver.linux.it/*",
|
||||
"unlimitedStorage"
|
||||
],
|
||||
"icons" : {
|
||||
"48" : "images/icons/logo.png",
|
||||
"128" : "images/icons/logo.png"
|
||||
}
|
||||
}
|
||||
565
plugins/chrome/openpgp.html
Executable file
565
plugins/chrome/openpgp.html
Executable file
@@ -0,0 +1,565 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<script type="text/javascript" src="jquery.min.js"></script>
|
||||
<script type="text/javascript" src="js/ciphers/hash/sha.js"></script>
|
||||
<script type="text/javascript" src="js/ciphers/hash/md5.js"></script>
|
||||
<script type="text/javascript" src="js/ciphers/hash/ripe-md.js"></script>
|
||||
|
||||
<!-- crypto libs -->
|
||||
<script type="text/javascript" src="js/ciphers/symmetricencryption/aes.js"></script>
|
||||
<script type="text/javascript" src="js/ciphers/symmetricencryption/cast5.js"></script>
|
||||
<script type="text/javascript" src="js/ciphers/symmetricencryption/dessrc.js"></script>
|
||||
<script type="text/javascript" src="js/ciphers/symmetricencryption/twofish.js"></script>
|
||||
<script type="text/javascript" src="js/ciphers/symmetricencryption/blowfish.js"></script>
|
||||
|
||||
<script type="text/javascript" src="js/ciphers/asymetricencryption/jsbn.js"></script>
|
||||
<script type="text/javascript" src="js/ciphers/asymetricencryption/jsbn2.js"></script>
|
||||
<script type="text/javascript" src="js/ciphers/asymetricencryption/dsa.js"></script>
|
||||
<script type="text/javascript" src="js/ciphers/asymetricencryption/elgamal.js"></script>
|
||||
<script type="text/javascript" src="js/ciphers/asymetricencryption/rsa.js"></script>
|
||||
|
||||
<script type="text/javascript" src="js/ciphers/openpgp.crypto.js"></script>
|
||||
<script type="text/javascript" src="js/ciphers/openpgp.cfb.js"></script>
|
||||
|
||||
<!-- compression -->
|
||||
|
||||
<!-- encoding -->
|
||||
<script type="text/javascript" src="js/encoding/base64.js"></script>
|
||||
<script type="text/javascript" src="js/encoding/openpgp.encoding.asciiarmor.js"></script>
|
||||
<script type="text/javascript" src="js/encoding/openpgp.encoding.js"></script>
|
||||
|
||||
<!-- openpgp types -->
|
||||
<script type="text/javascript" src="js/type/openpgp.type.keyid.js"></script>
|
||||
<script type="text/javascript" src="js/type/openpgp.type.mpi.js"></script>
|
||||
<script type="text/javascript" src="js/type/openpgp.type.s2k.js"></script>
|
||||
|
||||
<!-- openpgp packets -->
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.compressed.js"></script>
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.encrypteddata.js"></script>
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.encryptedintegrityprotecteddata.js"></script>
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.encryptedsessionkey.js"></script>
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.keymaterial.js"></script>
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.literaldata.js"></script>
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.marker.js"></script>
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.modificationdetectioncode.js"></script>
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.onepasssignature.js"></script>
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.signature.js"></script>
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.userattribute.js"></script>
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.userid.js"></script>
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.js"></script>
|
||||
|
||||
<!-- openpgp impl. -->
|
||||
<script type="text/javascript" src="js/openpgp.js"></script>
|
||||
<script type="text/javascript" src="js/openpgp.config.js"></script>
|
||||
<script type="text/javascript" src="js/openpgp.keyring.js"></script>
|
||||
<script type="text/javascript" src="js/openpgp.msg.message.js"></script>
|
||||
<script type="text/javascript" src="js/openpgp.msg.privatekey.js"></script>
|
||||
<script type="text/javascript" src="js/openpgp.msg.publickey.js"></script>
|
||||
<script type="text/javascript" src="js/util.js"></script>
|
||||
|
||||
<title>GPG4Browsers</title>
|
||||
</head>
|
||||
<style>
|
||||
|
||||
#enterPassword {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-top: -10px;
|
||||
margin-left: -300px;
|
||||
background-color: #8888FF;
|
||||
z-index:4;
|
||||
border: 2px solid white;
|
||||
box-shadow: 0px 0px 4px 4px #666;
|
||||
background-color: #fff;
|
||||
border: 2px solid white; box-shadow: 0px 0px 4px 4px #666;
|
||||
padding: 3px;
|
||||
}
|
||||
#keyselect {
|
||||
display: none;
|
||||
margin: 0 auto;
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
font-size: 89%;
|
||||
margin-top: -235px;
|
||||
margin-left: -300px;
|
||||
background-color: #8888FF;
|
||||
z-index:4;
|
||||
border: 2px solid white;
|
||||
box-shadow: 0px 0px 4px 4px #666;
|
||||
background-color: #fff;
|
||||
width: 600px;
|
||||
height: 470px;
|
||||
}
|
||||
#keyselecttable {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#keyselecttable th {
|
||||
background-color: #eee;
|
||||
border-bottom: 1px solid #000;
|
||||
padding: 2px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#keyselecttable td {
|
||||
padding: 2px;
|
||||
border-bottom: 1px solid #aaa;
|
||||
}
|
||||
|
||||
#reciepientTable {
|
||||
border: none;
|
||||
border-spacing: 2px;
|
||||
overflow: auto;
|
||||
}
|
||||
input, select {
|
||||
width: 570px;
|
||||
}
|
||||
.reciepientSelect {
|
||||
width: 50px;
|
||||
}
|
||||
.disabledkeys, .keys, .otherkeys {
|
||||
width: 15px;
|
||||
}
|
||||
.reciepientAdd {
|
||||
width: 21px;
|
||||
height: 21px;
|
||||
}
|
||||
#displayWindow, #composeWindow {
|
||||
margin-top: 2px;
|
||||
border: 1px solid #AAA;
|
||||
background-color: white;
|
||||
box-shadow: 2px 2px 5px #888;
|
||||
z-index: 2;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-radius: 5px;
|
||||
width: 670px;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #EFEFEF;
|
||||
}
|
||||
|
||||
#keyselecttable tbody {
|
||||
overflow: auto;
|
||||
}
|
||||
#displaySender, #displayCC,
|
||||
</style>
|
||||
<script language="javascript">
|
||||
|
||||
// we rely on jquery here
|
||||
var current_message = null;
|
||||
var account_email = null;
|
||||
|
||||
function start() {
|
||||
openpgp.init();
|
||||
chrome.extension.sendRequest({},
|
||||
function(response) {
|
||||
request = response;
|
||||
if (request.action == 0) { // compose message
|
||||
account_email = request.account;
|
||||
show_compose_window();
|
||||
} else if (request.action == 1) { // decrypt message
|
||||
current_message = request;
|
||||
account_email = request.account;
|
||||
show_message_window(response);
|
||||
} else {
|
||||
show_compose_window();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function show_compose_window() {
|
||||
$("#composerAddress").html(openpgp_encoding_html_encode(account_email));
|
||||
$("#displayWindow").hide();
|
||||
$("#composeWindow").show();
|
||||
if (openpgp.config.config.composition_behavior == 0) {
|
||||
$('#sign_message').attr("checked","checked");
|
||||
$('#encrypt_message').attr("checked","checked");
|
||||
} else if (openpgp.config.config.composition_behavior == 1) {
|
||||
$('#sign_message').attr("checked","checked");
|
||||
$('#encrypt_message').removeAttr("checked");
|
||||
} else if (openpgp.config.config.composition_behavior == 2) {
|
||||
$('#encrypt_message').attr("checked","checked");
|
||||
$('#sign_message').removeAttr("checked");
|
||||
}
|
||||
}
|
||||
var msg = null;
|
||||
function rfn(result) {
|
||||
if (result == -2)
|
||||
util.print_warning("unable to decrypt message: no private key available");
|
||||
else if (result == -1)
|
||||
util.print_error("No valid passphrase supplied");
|
||||
else if (result == -3)
|
||||
util.print_error("unable to decrypt message: error during decryption");
|
||||
else {
|
||||
current_message.decrypted = result;
|
||||
$("#displayMessage").html(openpgp_encoding_html_encode(result));
|
||||
}
|
||||
}
|
||||
|
||||
function show_message_window(request) {
|
||||
current_request = request;
|
||||
$("#composeWindow").hide();
|
||||
$("#displayWindow").show();
|
||||
$("#displaySender").html(openpgp_encoding_html_encode(request.from));
|
||||
for (var i = 0; i < request.to.length; i++)
|
||||
$("#displayReceipients").html(openpgp_encoding_html_encode(request.to[i]));
|
||||
if (request.cc != null && request.cc.length > 0) {
|
||||
$("#displayCC").html("");
|
||||
for (var i = 0; i < request.cc.length; i++)
|
||||
$("#displayCC").append(openpgp_encoding_html_encode(request.cc[i]));
|
||||
$("#displayCC").show();
|
||||
} else {
|
||||
$("#displayCC").hide();
|
||||
}
|
||||
if (request.bcc != null) {
|
||||
$("#displayBCC").html(openpgp_encoding_html_encode(request.bcc));
|
||||
$("#displayBCC").show();
|
||||
} else {
|
||||
$("#displayBCC").hide();
|
||||
}
|
||||
$("#displaySubject").html(openpgp_encoding_html_encode(request.subject));
|
||||
$("#displayMessage").html(openpgp_encoding_html_encode(request.body));
|
||||
|
||||
msg = openpgp.read_message(request.body);
|
||||
if (msg != null)
|
||||
for (var m = 0; m < msg.length; m++) {
|
||||
if (!(msg[m].sessionKeys == null)) {
|
||||
var found = false;
|
||||
for (var i = 0; i < msg[m].sessionKeys.length; i++) {
|
||||
if (openpgp.keyring.getPrivateKeyForKeyId(msg[m].sessionKeys[i].keyId)) {
|
||||
var key = openpgp.keyring.getPrivateKeyForKeyId(msg[m].sessionKeys[i].keyId);
|
||||
if (key.length != 0)
|
||||
found = true;
|
||||
for (var j = 0; j < key.length; j++) {
|
||||
if (!key[j].keymaterial.hasUnencryptedSecretKeyData) {
|
||||
get_password(key[j], msg[m], msg[m].sessionKeys[i], rfn);
|
||||
} else {
|
||||
rfn(msg[m].decrypt_message(key[j], null));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rfn(-2);
|
||||
}
|
||||
}
|
||||
if (!found || openpgp.keyring.privateKeys.length == 0)
|
||||
rfn(-2);
|
||||
} else if (msg[m].type == 2) {
|
||||
if (msg[m].verifySignature())
|
||||
rfn(msg[m].text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var encryptionkeys = new Array();
|
||||
var otherkeys = new Array();
|
||||
var reciepient_count = 2;
|
||||
|
||||
function add_reciepient() {
|
||||
add_reciepient(null,null,null);
|
||||
}
|
||||
|
||||
function add_reciepient(method, name, isdisabled) {
|
||||
|
||||
$("#reciepientTable").append("<tr class=\"reciepientsRow\"><td><select class=\"reciepientSelect\" "+((isdisabled != null) ? "disabled=\"disabled\" ":"")+"id=\"reciepient_method_"+reciepient_count+"\">"+
|
||||
"<option value=\"0\""+((method == 0) ? " selected=\"selected\"" : "")+">To:</option>"+
|
||||
"<option value=\"1\""+((method == 1) ? " selected=\"selected\"" : "")+">Cc:</option>"+
|
||||
"<option value=\"2\""+((method == 2) ? " selected=\"selected\"" : "")+">Bcc:</option>"+
|
||||
"</select></td><td>"+
|
||||
"<input name=\"recepient_"+reciepient_count+"\" type=\"text\" value=\""+((name != null) ? name : "")+"\"></input>"+
|
||||
"</td><td><input class=\"reciepientAdd\" id=\"reciepientAdd_"+reciepient_count+"\" type=\"button\" value=\"+\" onmousedown=\"add_reciepient();\"></input></td></tr>");
|
||||
|
||||
for (var i =1; i < reciepient_count; i++) $("#reciepientAdd_"+i).remove();
|
||||
reciepient_count++;
|
||||
}
|
||||
|
||||
function prepare_send_mail() {
|
||||
var i = 1;
|
||||
var addr = new Array();
|
||||
while ($('[name="recepient_'+i+'"]').val() != null) {
|
||||
addr[i-1] = $('[name="recepient_'+i+'"]').val();
|
||||
i++;
|
||||
}
|
||||
if ($('#encrypt_message').attr('checked') != null)
|
||||
showKeySelection(addr);
|
||||
else
|
||||
showEncryptionConfirmation();
|
||||
}
|
||||
|
||||
function show_reply(reply_all) {
|
||||
if (reply_all) {
|
||||
// adding replys "To"
|
||||
if (current_message.to.length < 2)
|
||||
add_reciepient(0,current_message.to[0], null);
|
||||
else for (var i = 0; i < request.to.length; i++)
|
||||
if (!getEmailAddress(request.to[i]).match(account_email)) {
|
||||
add_reciepient(0,current_message.to[i], null);
|
||||
}
|
||||
// adding reply copies (CC)
|
||||
if (current_request.cc != null)
|
||||
for (var i = 0; i < current_request.cc.length; i++)
|
||||
if (!getEmailAddress(current_request.cc[i]).match(account_email)) {
|
||||
add_reciepient(1,current_message.cc[i], null);
|
||||
}
|
||||
}
|
||||
$("#subjectInput").val("Re: "+current_message.subject);
|
||||
$("#composerAddress").html(openpgp_encoding_html_encode(account_email));
|
||||
$("#messageBody").html(openpgp_encoding_html_encode(quote_message(current_message.from, new Date(current_message.date), current_message.decrypted)));
|
||||
$("#firstto").val(current_message.from);
|
||||
$("#displayWindow").hide();
|
||||
show_compose_window();
|
||||
}
|
||||
|
||||
function quote_message (sender, date, msg) {
|
||||
return "\n\nOn "+date.toLocaleDateString()+" "+date.toLocaleTimeString()+" \""+getName(sender)+"\" wrote:"+"\n> "+msg.replace(/\n/g,"\n> ");
|
||||
}
|
||||
|
||||
function get_password(key, msg, sessionkey, successfn) {
|
||||
$("#enterPasswordSubmit").removeAttr("disabled");
|
||||
$("#enterPasswordInput").removeAttr("disabled");
|
||||
$("#enterPasswordInput").attr("value","");
|
||||
$('#enterPassword').css('background-color','#fff');
|
||||
var count = 0;
|
||||
$("#enterPasswordText").html("Please enter password for keyID: 0x"+util.hexstrdump(key.key.obj.getKeyId()));
|
||||
$("#enterPasswordKeyId").html(key.key.obj.userIds[0]);
|
||||
|
||||
$("#enterPasswordSubmit").click(function() {
|
||||
$("#enterPassword").fadeOut(100);
|
||||
$("#enterPasswordSubmit").attr("disabled","disabled");
|
||||
$("#enterPasswordInput").attr("disabled","disabled");
|
||||
if (key.keymaterial.decryptSecretMPIs($("#enterPasswordInput").val())) {
|
||||
$("#block-bg").hide();
|
||||
if (msg == null) {
|
||||
successfn();
|
||||
}
|
||||
successfn(msg.decrypt(key, sessionkey));
|
||||
} else {
|
||||
if (count == 2) {
|
||||
$("#block-bg").hide();
|
||||
successfn(-1);
|
||||
current_message.decrypted = current_message.body;
|
||||
count = 0;
|
||||
return;
|
||||
}
|
||||
$('#enterPassword').css('background-color','#f88');
|
||||
$("#enterPasswordSubmit").removeAttr("disabled");
|
||||
$("#enterPasswordInput").removeAttr("disabled");
|
||||
$("#enterPasswordText").html("enterered Password was wrong. try again for keyID: 0x"+util.hexstrdump(key.key.keyId));
|
||||
|
||||
$('#enterPasswordInput').focus();
|
||||
$('#enterPassword').fadeIn(100);
|
||||
count++;
|
||||
}
|
||||
|
||||
});
|
||||
$("#block-bg").show();
|
||||
$("#enterPassword").show();
|
||||
$('#enterPasswordInput').focus();
|
||||
}
|
||||
|
||||
function send_mail(encrypted_text) {
|
||||
var i = 1;
|
||||
var to = "";
|
||||
var cc = "";
|
||||
var bcc = "";
|
||||
while($('[name="recepient_'+i+'"]').val() != null) {
|
||||
if ($('#reciepient_method_'+i).val() == 0)
|
||||
if (to != "")
|
||||
to += ", "+$('[name="recepient_'+i+'"]').val();
|
||||
else
|
||||
to = $('[name="recepient_'+i+'"]').val();
|
||||
else if ($('#reciepient_method_'+i).val() == 1)
|
||||
if (cc != "")
|
||||
cc += ", "+$('[name="recepient_'+i+'"]').val();
|
||||
else
|
||||
cc = $('[name="recepient_'+i+'"]').val();
|
||||
else if ($('#reciepient_method_'+i).val() == 2)
|
||||
if (bcc != "")
|
||||
bcc += ", "+$('[name="recepient_'+i+'"]').val();
|
||||
else
|
||||
bcc = $('[name="recepient_'+i+'"]').val();
|
||||
i++;
|
||||
}
|
||||
var subject = $("#subjectInput").val();
|
||||
$("#enterPassword").hide();
|
||||
chrome.extension.sendRequest({action: 2, to: to, bcc: bcc, cc: cc, subject: subject, body: encrypted_text}, function() {});
|
||||
window.close();
|
||||
}
|
||||
|
||||
function getName(email_address) {
|
||||
var o = email_address.indexOf("<");
|
||||
if (o == -1)
|
||||
return email_address;
|
||||
return email_address.split("<")[0].trim();
|
||||
}
|
||||
|
||||
function getEmailAddress(reciepient) {
|
||||
var o = reciepient.indexOf("<");
|
||||
var c = reciepient.indexOf(">");
|
||||
if (o == -1 || c == -1)
|
||||
return reciepient;
|
||||
return reciepient.substring(o+1,u);
|
||||
}
|
||||
|
||||
function showMessages(html) {
|
||||
if ($('#displayWindow').is(':visible'))
|
||||
$('#MessageDisplayOpenPGP').append(html);
|
||||
else if ($('#composeWindow').is(':visible'))
|
||||
$('#MessageComposeOpenPGP').append(html);
|
||||
}
|
||||
|
||||
function doDownload(mimetype, data) {
|
||||
window.open("data:"+mimetype+";fileName=\"msg.txt\";charset=\"ISO8859-1\";base64,"+s2r(data));
|
||||
}
|
||||
|
||||
function showKeySelection(emailaddresses) {
|
||||
$('#keyselecttable').empty();
|
||||
$('#keyselecttable').append('<tr><th><input class="disabledkeys" type="checkbox" disabled="disabled" checked="checked"></input></th><th>Account / User ID</th><th>Trust</th><th>Key ID</th></tr>');
|
||||
encryptionkeys = new Array();
|
||||
otherkeys = new Array();
|
||||
for (var j = 0; j < emailaddresses.length; j++) {
|
||||
var addr = emailaddresses[j].match(/([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+)/gi);
|
||||
for (var i = 0; i < openpgp.keyring.publicKeys.length; i++) {
|
||||
for (var k = 0; k < openpgp.keyring.publicKeys[i].obj.userIds.length; k++) {
|
||||
if (openpgp.keyring.publicKeys[i].obj.userIds[k].verify(openpgp.keyring.publicKeys[i].obj.publicKeyPacket) != 0)
|
||||
continue;
|
||||
if (addr == openpgp.keyring.publicKeys[i].obj.userIds[k].text.match(/([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+)/gi)) {
|
||||
encryptionkeys[keys.length] = openpgp.keyring.publicKeys[i];
|
||||
emailaddresses.splice(j,1);
|
||||
} else {
|
||||
otherkeys[otherkeys.length] = openpgp.keyring.publicKeys[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we got all keys
|
||||
if (emailaddresses.length == 0) {
|
||||
showEncryptionConfirmation();
|
||||
}
|
||||
$('#keyselecttext').empty();
|
||||
|
||||
$('#keyselecttext').append("Select keys for the following email addresses:<br>");
|
||||
for (var i= 0; i < emailaddresses.length; i++) {
|
||||
$('#keyselecttext').append("<i>"+openpgp_encoding_html_encode(emailaddresses[i])+"</i>, ");
|
||||
}
|
||||
|
||||
for (var i=0; i < encryptionkeys.length; i++)
|
||||
$('#keyselecttable').append('<tr class="validkey"><td><input class="keys" value="'+i+'" type="checkbox" checked="checked"></input></td><td></td>'+
|
||||
openpgp_encoding_html_encode(encryptionkeys[i].obj.userIds[0].text)+'<td>valid</td><td>0x'+openpgp_encoding_html_encode(util.hexstrdump(encryptionkeys[i].obj.getKeyId()).substring(8))+'</td></tr>');
|
||||
for (var i = 0; i < otherkeys.length; i++) {
|
||||
if (!otherkeys[i].obj.verifyBasicSignatures()) {
|
||||
$('#keyselecttable').append('<tr class="invalidkey"><td><input class="disabledkeys" type="checkbox" disabled="disabled"></input></td><td><i style="color: #888;">'+
|
||||
openpgp_encoding_html_encode(otherkeys[i].obj.userIds[0].text)+'</i></td><td>invalid</td><td>0x'+openpgp_encoding_html_encode(util.hexstrdump(otherkeys[i].obj.getKeyId()).substring(8))+'</td></tr>');
|
||||
} else {
|
||||
$('#keyselecttable').append('<tr class="validkey"><td><input class="otherkeys" value="'+i+'"type="checkbox"></input></td><td>'+
|
||||
openpgp_encoding_html_encode(otherkeys[i].obj.userIds[0].text)+'</td><td>valid</td><td>0x'+openpgp_encoding_html_encode(util.hexstrdump(otherkeys[i].obj.getKeyId()).substring(8))+'</td></tr>');
|
||||
}
|
||||
}
|
||||
$('#keyselect').show();
|
||||
$('#block-bg').show();
|
||||
}
|
||||
|
||||
|
||||
|
||||
function showEncryptionConfirmation() {
|
||||
if ($('#encrypt_message').attr('checked') != null) {
|
||||
$('#keyselect').hide();
|
||||
var keys = new Array();
|
||||
var input1 = $('input.keys:checked');
|
||||
var input2 = $('input.otherkeys:checked');
|
||||
for (var i = 0; i < input1.length; i++) {
|
||||
keys[keys.length] = encryptionkeys[parseInt(input1[i].getAttribute("value"))].obj;
|
||||
}
|
||||
for (var i = 0; i < input2.length; i++) {
|
||||
keys[keys.length] = otherkeys[parseInt(input2[i].getAttribute("value"))].obj;
|
||||
}
|
||||
|
||||
if ($('#sign_message').attr('checked') != null) {
|
||||
var privatekey = openpgp.keyring.getPrivateKeyForAddress(account_email);
|
||||
if (privatekey.length == 0) {
|
||||
alert("no private key found! Go to options and import or create one.");
|
||||
showEncryptioncancel();
|
||||
}
|
||||
|
||||
get_password({ key: privatekey[0], keymaterial: privatekey[0].obj.privateKeyPacket},null,null, function(ret) {
|
||||
if (!(ret < 0))
|
||||
send_mail(openpgp.write_signed_and_encrypted_message(privatekey[0].obj, keys, $('#messageBody').val()));
|
||||
});
|
||||
} else {
|
||||
send_mail(openpgp.write_encrypted_message(keys, $('#messageBody').val()));
|
||||
}
|
||||
} else {
|
||||
var privatekey = openpgp.keyring.getPrivateKeyForAddress(account_email);
|
||||
if (privatekey.length == 0) {
|
||||
alert("no private key found! Go to options and import or create one.");
|
||||
showEncryptioncancel();
|
||||
}
|
||||
get_password({ key: privatekey[0], keymaterial: privatekey[0].obj.privateKeyPacket},null,null, function(ret) {
|
||||
if (!(ret < 0))
|
||||
send_mail(openpgp.write_signed_message(privatekey[0].obj, $('#messageBody').val()));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function showEncryptionCancel() {
|
||||
$('#keyselect').hide();
|
||||
$('#block-bg').hide();
|
||||
}
|
||||
|
||||
</script>
|
||||
<body onload="start();" style="font-family: sans-serif;">
|
||||
<table id="displayWindow">
|
||||
<tr><td colspan="2"><button type="submit" onmousedown="show_reply(false);" style="width: 80px; height: 50px"> <- Reply</button> <button type="submit" onmousedown="show_reply(true);" style="width: 100px; height: 50px"> <= Reply All</button> <button type="submit" onmousedown="forward();" style="width: 80px; height: 50px">Forward -></button></td></tr>
|
||||
<tr><td>From:</td><td id="displaySender" style="font-weight: bold;"></td></tr>
|
||||
<tr><td>To:</td><td id="displayReceipients" style="font-weight: bold;"></td></tr>
|
||||
<tr><td>CC:</td><td id="displayCC" style="display: none;"></td></tr>
|
||||
<tr><td>BCC:</td><td id="displayBCC" style="display: none;"></td></tr>
|
||||
<tr><td>Subject:</td><td id="displaySubject"></td></tr>
|
||||
<tr><td id="MessageDisplayOpenPGP" colspan="2"></td></tr>
|
||||
<tr><td colspan="2"><textarea cols="80" rows="30" readonly="readonly" id="displayMessage"></textarea></td></tr>
|
||||
<tr><td colspan="2"><button type="button" onclick="doDownload('application/octet-stream',$('#displayMessage').val());">Download</button></td></tr>
|
||||
</table>
|
||||
|
||||
|
||||
<table id="composeWindow">
|
||||
<tr><td>
|
||||
<table id="reciepientTable">
|
||||
<tr><td style="text-align: left;"><button id="encrypt" style="width: 50px; height: 50px" onmousedown="prepare_send_mail();">send</button></td><td colspan="2" style="text-align: left; font-size: 89%; border-bottom: 1px solid #aaa"><input style="width: 20px;" type="checkbox" id="sign_message"> Sign message <br/><input style="width: 20px;" type="checkbox" id="encrypt_message"> Encrypt message </td></tr>
|
||||
<tr class="reciepientsRow"><td>From:</td><td id="composerAddress"></td></tr>
|
||||
<tr class="reciepientsRow"><td><select class="reciepientSelect" id="reciepient_method_1" disabled="disabled"><option value="0">To:</option><option value="1">Cc:</option><option value="2">Bcc:</option></select></td><td><input id="firstto" name="recepient_1" type="text"></input></td><td><input class="reciepientAdd" id="reciepientAdd_1" type="button" value="+" onmousedown="add_reciepient();"></input></td></tr>
|
||||
</table></td></tr>
|
||||
<tr><td id="composeSubject">Subject:<input id="subjectInput" type="text" name="subject"></input></td></tr>
|
||||
<tr><td id="MessageComposeOpenPGP" colspan="2"></td></tr>
|
||||
<tr><td><textarea rows="30" cols="80" id="messageBody"></textarea></td></tr>
|
||||
</table>
|
||||
|
||||
<div id="enterPassword">
|
||||
<span id="enterPasswordText">Enter your Password for key</span> <span id="enterPasswordKeyId"></span>:<br/>
|
||||
<input type="password" id="enterPasswordInput" onkeypress="if (event.keyCode == 13) $('#enterPasswordSubmit').click(); "><button type="submit" id="enterPasswordSubmit">OK</button>
|
||||
</div>
|
||||
<div id="keyselect">
|
||||
<div id="keyselecttext" style="margin: 5px;"></div>
|
||||
<div style="overflow: auto; height: 390px;">
|
||||
<table id="keyselecttable">
|
||||
</table>
|
||||
</div>
|
||||
<div style="text-align: right; margin: 5px;">
|
||||
<button type="submit" onmousedown="showEncryptionConfirmation();">OK</button>
|
||||
<button type="submit" onmousedown="showEncryptionCancel();">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="encryptionConfirmation">
|
||||
</div>
|
||||
<div id="block-bg" style=" width: 100%; height: 100%; z-index: 2; display: none; position: fixed; top: 0px; background-color: black; opacity: 0.5;"></div>
|
||||
</body>
|
||||
</html>
|
||||
446
plugins/chrome/options.html
Executable file
446
plugins/chrome/options.html
Executable file
@@ -0,0 +1,446 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>GPG4Browsers - PGP Message Options</title>
|
||||
</head>
|
||||
<script type="text/javascript" src="jquery.min.js"></script>
|
||||
<script type="text/javascript" src="js/ciphers/hash/sha.js"></script>
|
||||
<script type="text/javascript" src="js/ciphers/hash/md5.js"></script>
|
||||
<script type="text/javascript" src="js/ciphers/hash/ripe-md.js"></script>
|
||||
|
||||
<!-- crypto libs -->
|
||||
<script type="text/javascript" src="js/ciphers/symmetricencryption/aes.js"></script>
|
||||
<script type="text/javascript" src="js/ciphers/symmetricencryption/cast5.js"></script>
|
||||
<script type="text/javascript" src="js/ciphers/symmetricencryption/dessrc.js"></script>
|
||||
<script type="text/javascript" src="js/ciphers/symmetricencryption/twofish.js"></script>
|
||||
<script type="text/javascript" src="js/ciphers/symmetricencryption/blowfish.js"></script>
|
||||
|
||||
<script type="text/javascript" src="js/ciphers/asymetricencryption/jsbn.js"></script>
|
||||
<script type="text/javascript" src="js/ciphers/asymetricencryption/jsbn2.js"></script>
|
||||
<script type="text/javascript" src="js/ciphers/asymetricencryption/dsa.js"></script>
|
||||
<script type="text/javascript" src="js/ciphers/asymetricencryption/elgamal.js"></script>
|
||||
<script type="text/javascript" src="js/ciphers/asymetricencryption/rsa.js"></script>
|
||||
|
||||
<script type="text/javascript" src="js/ciphers/openpgp.crypto.js"></script>
|
||||
<script type="text/javascript" src="js/ciphers/openpgp.cfb.js"></script>
|
||||
|
||||
<!-- compression -->
|
||||
|
||||
<!-- encoding -->
|
||||
<script type="text/javascript" src="js/encoding/base64.js"></script>
|
||||
<script type="text/javascript" src="js/encoding/openpgp.encoding.asciiarmor.js"></script>
|
||||
<script type="text/javascript" src="js/encoding/openpgp.encoding.js"></script>
|
||||
|
||||
<!-- openpgp types -->
|
||||
<script type="text/javascript" src="js/type/openpgp.type.keyid.js"></script>
|
||||
<script type="text/javascript" src="js/type/openpgp.type.mpi.js"></script>
|
||||
<script type="text/javascript" src="js/type/openpgp.type.s2k.js"></script>
|
||||
|
||||
<!-- openpgp packets -->
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.compressed.js"></script>
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.encrypteddata.js"></script>
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.encryptedintegrityprotecteddata.js"></script>
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.encryptedsessionkey.js"></script>
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.keymaterial.js"></script>
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.literaldata.js"></script>
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.marker.js"></script>
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.modificationdetectioncode.js"></script>
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.onepasssignature.js"></script>
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.signature.js"></script>
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.userattribute.js"></script>
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.userid.js"></script>
|
||||
<script type="text/javascript" src="js/packet/openpgp.packet.js"></script>
|
||||
|
||||
<!-- openpgp impl. -->
|
||||
<script type="text/javascript" src="js/openpgp.js"></script>
|
||||
<script type="text/javascript" src="js/openpgp.config.js"></script>
|
||||
<script type="text/javascript" src="js/openpgp.keyring.js"></script>
|
||||
<script type="text/javascript" src="js/openpgp.msg.message.js"></script>
|
||||
<script type="text/javascript" src="js/openpgp.msg.privatekey.js"></script>
|
||||
<script type="text/javascript" src="js/openpgp.msg.publickey.js"></script>
|
||||
<script type="text/javascript" src="js/util.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
// Saves options to localStorage.
|
||||
function save_options() {
|
||||
openpgp.keyring.store();
|
||||
}
|
||||
|
||||
function getAlgorithmString(publicKey) {
|
||||
var result = publicKey.publicKeyPacket.MPIs[0].mpiByteLength*8+"/";
|
||||
switch (publicKey.publicKeyPacket.publicKeyAlgorithm) {
|
||||
case 1:
|
||||
result += "RSA(S/E)";
|
||||
break;
|
||||
case 2:
|
||||
result +="RSA(E)";
|
||||
break;
|
||||
case 3:
|
||||
result += "RSA(S)";
|
||||
break;
|
||||
case 16:
|
||||
result += "Elg";
|
||||
break;
|
||||
case 17:
|
||||
result += "DSA";
|
||||
break;
|
||||
}
|
||||
if (publicKey.subKeys.length > 0) {
|
||||
result += ", "+(publicKey.subKeys[0].MPIs[0].mpiByteLength * 8)+"/";
|
||||
switch (publicKey.subKeys[0].publicKeyAlgorithm) {
|
||||
case 1:
|
||||
result += "(RSA(S/E)";
|
||||
break;
|
||||
case 2:
|
||||
result +="RSA(E)";
|
||||
break;
|
||||
case 3:
|
||||
result += "RSA(S)";
|
||||
break;
|
||||
case 16:
|
||||
result += "Elg.";
|
||||
break;
|
||||
case 17:
|
||||
result += "DSA";
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function encodeForHtml(text) {
|
||||
if (text == null)
|
||||
return "";
|
||||
return $('<div/>').text(text+"").html();
|
||||
}
|
||||
|
||||
function importPublicKey(key) {
|
||||
openpgp.keyring.importPublicKey(key);
|
||||
save_options();
|
||||
update_tables();
|
||||
}
|
||||
|
||||
function importPrivateKey(key) {
|
||||
openpgp.keyring.importPrivateKey(key);
|
||||
save_options();
|
||||
update_tables();
|
||||
}
|
||||
|
||||
// Restores select box state to saved value from localStorage.
|
||||
function restore_options() {
|
||||
openpgp.init();
|
||||
update_tables();
|
||||
$('#cipher_alg_select').val(""+openpgp.config.config.encryption_cipher);
|
||||
$('#hash_alg_select').val(""+openpgp.config.config.prefer_hash_algorithm);
|
||||
$('#compression_alg_select').val(""+openpgp.config.config.compression);
|
||||
$('#integrity').attr("checked", openpgp.config.config.integrity_protect);
|
||||
$('#aaversion').attr("checked", openpgp.config.config.show_version);
|
||||
$('#keyserver').val(""+openpgp.config.config.keyserver);
|
||||
show_tab(0);
|
||||
}
|
||||
|
||||
function show_userIds(k) {
|
||||
var publicKey = openpgp.keyring.publicKeys[k];
|
||||
var certsigs = publicKey.obj.verifyCertificationSignatures();
|
||||
$('#show_ids_'+k).empty();
|
||||
for (var i = 0; i < publicKey.obj.userIds.length; i++) {
|
||||
if (certsigs[i].indexOf(6) != -1)
|
||||
$('#show_ids_'+k).append("<tr style=\"background-color: #fdd\"><td>rev</td><td class=\"uid_revoked\" colspan=\"2\"><s>"+encodeForHtml(publicKey.obj.userIds[i].text)+"</s></td></tr>");
|
||||
else if (certsigs[i].indexOf(5) != -1)
|
||||
$('#show_ids_'+k).append("<tr style=\"background-color: #ffd\"><td>exp</td><td class=\"uid_expired\" colspan=\"2\"><i>"+encodeForHtml(publicKey.obj.userIds[i].text)+"</i></td></tr>");
|
||||
else
|
||||
$('#show_ids_'+k).append("<tr style=\"background-color: #dfd\"><td>uid</td><td class=\"uid_normal\" colspan=\"2\"><b>"+encodeForHtml(publicKey.obj.userIds[i].text)+"</b></td></tr>");
|
||||
for (var j = 0; j < publicKey.obj.userIds[i].certificationSignatures.length; j++) {
|
||||
var istr = util.hexstrdump(publicKey.obj.userIds[i].certificationSignatures[j].getIssuer());
|
||||
var issuer = publicKey.obj.userIds[i].certificationSignatures[j].getIssuerKey();
|
||||
var sigclass = publicKey.obj.userIds[i].certificationSignatures[j].signatureType - 0x10;
|
||||
if (issuer != null)
|
||||
istr = issuer.obj.userIds[0].text;
|
||||
if (certsigs[i][j] == 0)
|
||||
$('#show_ids_'+k).append("<tr><td>sig"+(sigclass == 0 ? "" : sigclass)+"</td><td>BAD</td><td class=\"sig_bad\">"+encodeForHtml(istr)+"</td></tr>");
|
||||
if (certsigs[i][j] == 1)
|
||||
$('#show_ids_'+k).append("<tr><td>sig"+(sigclass == 0 ? "" : sigclass)+"</td><td>exp</td><td class=\"sig_exp\"><i>"+encodeForHtml(istr)+"</i></td></tr>");
|
||||
if (certsigs[i][j] == 2)
|
||||
$('#show_ids_'+k).append("<tr><td>sig"+(sigclass == 0 ? "" : sigclass)+"</td><td>unk</td><td class=\"sig_unk\">"+encodeForHtml(istr)+"</td></tr>");
|
||||
if (certsigs[i][j] == 3)
|
||||
$('#show_ids_'+k).append("<tr><td>sig"+(sigclass == 0 ? "" : sigclass)+"</td><td>rev</td><td class=\"sig_unk\"><s>"+encodeForHtml(istr)+"</s></td></tr>");
|
||||
if (certsigs[i][j] == 4)
|
||||
$('#show_ids_'+k).append("<tr><td>sig"+(sigclass == 0 ? "" : sigclass)+"</td><td></td><td class=\"sig_normal\">"+encodeForHtml(istr)+"</td></tr>");
|
||||
}
|
||||
}
|
||||
$('#show_ids_'+k).toggle();
|
||||
}
|
||||
|
||||
function update_tables() {
|
||||
$('#publicKeyTable').empty();
|
||||
$('#publicKeyTable').append("<tr><th>Key ID</th><th>Person</th><th>Length/Alg.</th><th>Status</th><th>Action</th></tr>");
|
||||
for (var i = 0; i < openpgp.keyring.publicKeys.length; i++) {
|
||||
var status = openpgp.keyring.publicKeys[i].obj.verifyBasicSignatures();
|
||||
var result = "<tr><td>0x"+
|
||||
util.hexstrdump(openpgp.keyring.publicKeys[i].obj.getKeyId()).toUpperCase().substring(8)+ "</td>";
|
||||
result += "<td><button id=\"show_button"+i+"\" onmousedown=\"show_userIds("+i+");\">+</button>"+encodeForHtml(openpgp.keyring.publicKeys[i].obj.userIds[0].text)+"<table style=\"display: none;\" id=\"show_ids_"+i+"\"></table></td>";
|
||||
result += "<td>"+getAlgorithmString(openpgp.keyring.publicKeys[i].obj)+"</td>";
|
||||
result += "<td>"+(status ? "valid" : "invalid")+"</td>";
|
||||
result += "<td><a href=\"#\" onmousedown=\"openpgp.keyring.removePublicKey("+i+"); update_tables();\">remove</a></td>";
|
||||
$("#publicKeyTable").append(result+"</tr>");
|
||||
}
|
||||
$('#privateKeyTable').empty();
|
||||
$('#privateKeyTable').append("<tr><th>Key ID</th><th>Person</th><th>Length/Alg.</th><th>Expires on</th><th>Action</th></tr>");
|
||||
for (var i = 0; i < openpgp.keyring.privateKeys.length; i++) {
|
||||
for (var j = 0; j < openpgp.keyring.privateKeys[i].obj.userIds.length; j++) {
|
||||
$("#privateKeyTable").append("<tr><td>"
|
||||
+util.hexstrdump(openpgp.keyring.privateKeys[i].obj.getKeyId())+ "</td><td>"+
|
||||
": "+encodeForHtml(openpgp.keyring.privateKeys[i].obj.userIds[j].text)+"</td></tr>");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var current_tab = -1;
|
||||
function show_tab(num) {
|
||||
if (current_tab != num) {
|
||||
$("#tab_"+current_tab).hide();
|
||||
$('#tabref_'+current_tab).attr("class","tabref");
|
||||
$("#tab_"+num).show();
|
||||
$('#tabref_'+num).attr("class","tabref-select");
|
||||
}
|
||||
current_tab = num;
|
||||
}
|
||||
function importKeyId(string) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
var searchtext = $('#searchKeyText').val();
|
||||
xhr.open("GET", "http://"+encodeURIComponent(openpgp.config.config.keyserver)+"/pks/lookup?op=get&search=0x"+encodeURIComponent(string)+"&options=mr",true);
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState == 4) {
|
||||
var key = xhr.responseText.split('<pre>')[1];
|
||||
importPublicKey(key);
|
||||
}
|
||||
};
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
function showMessages(html) {
|
||||
$('#debug').append(html);
|
||||
}
|
||||
|
||||
function show_search_results() {
|
||||
$('#searchKeyResults').empty();
|
||||
var xhr = new XMLHttpRequest();
|
||||
var searchtext = $('#searchKeyText').val();
|
||||
xhr.open("GET", "http://"+encodeURIComponent(openpgp.config.config.keyserver)+"/pks/lookup?op=index&search="+encodeURIComponent(searchtext)+"&options=mr",true);
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState == 4) {
|
||||
$('#searchKeyResults').append("<tr><th>Key ID</th><th>Person</th><th>Length/Alg.</th><th>CreatedOn</th><th>Action</th></tr>");
|
||||
var text = xhr.responseText.split('\n');
|
||||
for (var i =1; i < text.length; i++) {
|
||||
var col = text[i].split(":");
|
||||
var keyId = null;
|
||||
var created = null;
|
||||
var algorithm = null;
|
||||
var length = null;
|
||||
var uids = null;
|
||||
var revoked = null;
|
||||
var r = 1;
|
||||
if (col[0] == "pub") {
|
||||
keyId = col[1];
|
||||
algorithm = col[2];
|
||||
length = col[3];
|
||||
created = new Date(parseInt(col[4]+"000"));
|
||||
revoked = !(col[6].indexOf('r') < 0);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
uids = "";
|
||||
while (text[i+r].split(":")[0] == "uid") {
|
||||
uids += encodeForHtml(text[i+r].split(":")[1])+"<br>";
|
||||
r++;
|
||||
}
|
||||
i += r-1;
|
||||
$('#searchKeyResults').append("<tr><td>"+keyId+"</td>"+
|
||||
"<td>"+uids+"</td>"+
|
||||
"<td>"+length+"/"+(algorithm == "1" ? "RSA" : "DSA-Elgamal")+"</td>"+
|
||||
"<td>"+created+"</td>"+
|
||||
"<td>"+
|
||||
(!revoked ? "<a href=\"#\" onclick=\"importKeyId('"+encodeForHtml(keyId).trim()+"');\"> Import Key</a>" : "key is revoked")+"</td></tr>");
|
||||
}
|
||||
$('#searchKeyResults').show();
|
||||
}
|
||||
};
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
background-color: #efefef;
|
||||
}
|
||||
* {
|
||||
font-size: 98%;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
.tabref, .tabref-select {
|
||||
border: 1px solid #aaa;
|
||||
border-bottom: none;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
margin-left: 3px;
|
||||
margin-bottom: 0px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.tabref {
|
||||
background-color: #eee;
|
||||
border: 1px solid #aaa;
|
||||
}
|
||||
#options_header {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
#publicKeyTable, #privateKeyTable, #searchKeyResults {
|
||||
border: 1px solid #aaa;
|
||||
}
|
||||
|
||||
#publicKeyTable th, #privateKeyTable th, #searchKeyResults th {
|
||||
background-color: #eee;
|
||||
border-bottom: 1px solid #000;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
#publicKeyTable td, #privateKeyTable td, #searchKeyResults td {
|
||||
padding: 3px;
|
||||
border-bottom: 1px solid #aaa;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.tabref-select {
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #fff;
|
||||
}
|
||||
|
||||
h2 {
|
||||
|
||||
font: 1.5em;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #888;
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
font: 1.5em "Impact";
|
||||
|
||||
}
|
||||
|
||||
#tab_1, #tab_2, #tab_3, #tab_0 {
|
||||
margin-top: 2px;
|
||||
border: 1px solid #aaa;
|
||||
background-color: #fff;
|
||||
box-shadow: 2px 2px 5px #888;
|
||||
z-index: 2;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
</style>
|
||||
<body onload="restore_options()">
|
||||
<div id="options_header">
|
||||
<a href="#" class="tabref" id="tabref_0" onmousedown="show_tab(0);">Settings</a>
|
||||
<a href="#" class="tabref" id="tabref_1" onmousedown="show_tab(1);">Public Keys</a>
|
||||
<a href="#" class="tabref" id="tabref_2" onmousedown="show_tab(2);">Private Keys</a>
|
||||
</div>
|
||||
<div id="tab_0" style="display: none">
|
||||
<h2>Composition Settings</h2>
|
||||
<ul><li><select id="composition_behavior" onchange="openpgp.config.config.composition_behavior = parseInt($('#composition_behavior').val()); openpgp.config.write();">
|
||||
<option value="0"> Sign & Encrypt</option>
|
||||
<option value="1"> Sign only</option>
|
||||
<option value="2"> Encrypt only</option>
|
||||
</select> when creating messages </li>
|
||||
<li><input type="checkbox" id="integrity" onchange="openpgp.config.config.integrity_protect = ($('#integrity').attr('checked') ? true: false); openpgp.config.write();">Generate integrity protected messages<br></li>
|
||||
<li><input type="checkbox" id="aaversion" onchange="openpgp.config.config.show_version = ($('#aaversion').attr('checked') ? true: false); openpgp.config.write();">Insert version into ASCII Armor<br></li>
|
||||
<li>PGP Key Server Host (no slashes): http://<input type="text" id="keyserver"><button type="submit" onclick="openpgp.config.config.keyserver = $('#keyserver').val(); openpgp.config.write();">Save</button></li>
|
||||
</ul>
|
||||
<h2>Encryption Algorithms</h2>
|
||||
<table><tr><td>Preferred Hash Algorithm:</td>
|
||||
<td><select id="hash_alg_select" onchange=" openpgp.config.config.prefer_hash_algorithm = parseInt($('#hash_alg_select').val()); openpgp.config.write();">
|
||||
<option value="1">MD5 (deprecated)</option>
|
||||
<option value="3">RIPE-MD/160</option>
|
||||
<option value="2">SHA-1 (GnuPG default)</option>
|
||||
<option value="11">SHA224</option>
|
||||
<option value="8">SHA256</option>
|
||||
<option value="9">SHA384</option>
|
||||
<option value="10">SHA512</option>
|
||||
</select></td></tr>
|
||||
<tr><td>Symmetric Cipher Algorithm:</td>
|
||||
<td><select id="cipher_alg_select" onchange="openpgp.config.config.encryption_cipher = parseInt($('#cipher_alg_select').val()); openpgp.config.write();">
|
||||
<option value="2">TripleDES (compatible mode)</option>
|
||||
<option value="3">CAST5</option>
|
||||
<option value="4">Blowfish</option>
|
||||
<option value="7">AES with 128-bit key</option>
|
||||
<option value="8">AES with 192-bit key</option>
|
||||
<option value="9">AES with 256-bit key (GnuPG default)</option>
|
||||
<option value="10">Twofish</option>
|
||||
</select></td></tr>
|
||||
<tr><td>Message Compression:</td>
|
||||
<td><select id="compression_alg_select" onchange="openpgp.config.config.compression = parseInt($('#compression_alg_select').val()); openpgp.config.write();">
|
||||
<option value="0">Plaintext (no compression)</option>
|
||||
<!-- <option value="1">ZIP </option> -->
|
||||
</select></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="tab_1" style="display: none">
|
||||
<h2>Public Keys in Keyring</h2>
|
||||
<table id="publicKeyTable">
|
||||
<tr><th>Key ID</th><th>Person</th><th>Length/Alg.</th><th>Status</th><th>Action</th></tr>
|
||||
</table>
|
||||
<h2>Import a Public Key</h2>
|
||||
<b><a href="#" onclick="$('#importSearchedKey').toggle();">Search Key</a></b><br>
|
||||
<div id="importSearchedKey" style="display: none;margin-left: 5px; border-left: 1px solid #aaa; padding-left: 5px;">
|
||||
KeyID or UserId: <input type="text" id="searchKeyText"></input><button type="submit" onclick="show_search_results();">search</button>
|
||||
<table id="searchKeyResults" style="display: none">
|
||||
<tr><th>Key ID</th><th>Person</th><th>Length/Alg.</th><th>CreatedOn</th><th>Action</th></tr>
|
||||
</table>
|
||||
</div>
|
||||
<b><a href="#" onclick="$('#importPastedPublicKey').toggle();">Import pasted public key</a></b><br>
|
||||
<div id="importPastedPublicKey" style="display: none; margin-left: 5px; border-left: 1px solid #aaa; padding-left: 5px;">
|
||||
<textarea rows="25" cols="80" id="importKeyTextfield"></textarea>
|
||||
<button onclick="importPublicKey($('#importKeyTextfield').val());">Import</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tab_2" style="display: none; ">
|
||||
<h2>Private Keys in Keyring</h2>
|
||||
<table id="privateKeyTable">
|
||||
<tr><th>Key ID</th><th>Person</th><th>Length/Alg.</th><th>Expires on</th></tr>
|
||||
</table>
|
||||
<h2>Add a Private Key</h2>
|
||||
<b><a href="#" onclick="$('#generatePrivateKey').toggle();">Generate a new private key</a></b><br>
|
||||
<div id="generatePrivateKey" style="display: none; margin-left: 5px; border-left: 1px solid #aaa; padding-left: 5px;">
|
||||
<table>
|
||||
<tr><td>Length in Bits:</td>
|
||||
<td><select><option value="1024">1024</option><option value="2048" selected="selected">2048</option><option value="4096">4096</option></select></td></tr>
|
||||
<tr><td>Algorithm:</td>
|
||||
<td><input type="radio" checked="checked" name="algorithm" value="16"> DSA / Elgamal (Sign & Encrypt)<br>
|
||||
<input type="radio" name="algorithm" value="17"> DSA (Sign Only)<br>
|
||||
<input type="radio" name="algorithm" value="1"> RSA (Sign & Encrypt)<br></td></tr>
|
||||
<tr><td>Username:</td><td><input type="text" name="username"></input> (e.g "John Doe")</td></tr>
|
||||
<tr><td>Alias:</td><td><input type="text" name="alias"></input> (e.g "Johns Company")</td></tr>
|
||||
<tr><td>Email Address:</td><td><input type="text" name="email"></input> (e.g "john@doe.com")</td></tr>
|
||||
<tr><td>Expires on:</td><td><input type="radio" name="expiry" value="0" onclick="$('#expiryDate').attr('disabled','disabled');" checked="checked"></input>Never | <input type="radio" name="expiry" value="1" onclick="$('#expiryDate').removeAttr('disabled');">Date: <input type="text" id="expiryDate" disabled="disabled"></td></tr>
|
||||
<tr><td></td><td><button type="submit" onclick="generateKey();">Generate Key</button></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<b><a href="#" onclick="$('#pastePrivateKey').toggle();">Paste a private key</a></b><br>
|
||||
<div id="pastePrivateKey" style="display: none; margin-left: 5px; border-left: 1px solid #aaa; padding-left: 5px;">
|
||||
<textarea rows="30" cols="80" id="importPrivateKeyTextfield"></textarea>
|
||||
<button onclick="importPrivateKey($('#importPrivateKeyTextfield').val()); $('#generatePrivateKey').toggle();">Import Key</button>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<div id="debug"></div>
|
||||
</body>
|
||||
</html>
|
||||
18
resources/jquery.min.js
vendored
Executable file
18
resources/jquery.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
151
src/ciphers/asymmetric/dsa.js
Executable file
151
src/ciphers/asymmetric/dsa.js
Executable file
@@ -0,0 +1,151 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
// A Digital signature algorithm implementation
|
||||
|
||||
function DSA() {
|
||||
// s1 = ((g**s) mod p) mod q
|
||||
// s1 = ((s**-1)*(sha-1(m)+(s1*x) mod q)
|
||||
function sign(hashalgo, m, g, p, q, x) {
|
||||
// If the output size of the chosen hash is larger than the number of
|
||||
// bits of q, the hash result is truncated to fit by taking the number
|
||||
// of leftmost bits equal to the number of bits of q. This (possibly
|
||||
// truncated) hash function result is treated as a number and used
|
||||
// directly in the DSA signature algorithm.
|
||||
var hashed_data = util.getLeftNBits(openpgp_crypto_hashData(hashalgo,m),q.bitLength());
|
||||
var hash = new BigInteger(util.hexstrdump(hashed_data), 16);
|
||||
var k = openpgp_crypto_getRandomBigIntegerInRange(BigInteger.ONE.add(BigInteger.ONE), q.subtract(BigInteger.ONE));
|
||||
var s1 = (g.modPow(k,p)).mod(q);
|
||||
var s2 = (k.modInverse(q).multiply(hash.add(x.multiply(s1)))).mod(q);
|
||||
var result = new Array();
|
||||
result[0] = s1.toMPI();
|
||||
result[1] = s2.toMPI();
|
||||
return result;
|
||||
}
|
||||
function select_hash_algorithm(q) {
|
||||
var usersetting = openpgp.config.config.prefer_hash_algorithm;
|
||||
/*
|
||||
* 1024-bit key, 160-bit q, SHA-1, SHA-224, SHA-256, SHA-384, or SHA-512 hash
|
||||
* 2048-bit key, 224-bit q, SHA-224, SHA-256, SHA-384, or SHA-512 hash
|
||||
* 2048-bit key, 256-bit q, SHA-256, SHA-384, or SHA-512 hash
|
||||
* 3072-bit key, 256-bit q, SHA-256, SHA-384, or SHA-512 hash
|
||||
*/
|
||||
switch (Math.round(q.bitLength() / 8)) {
|
||||
case 20: // 1024 bit
|
||||
if (usersetting != 2 &&
|
||||
usersetting > 11 &&
|
||||
usersetting != 10 &&
|
||||
usersetting < 8)
|
||||
return 2; // prefer sha1
|
||||
return usersetting;
|
||||
case 28: // 2048 bit
|
||||
if (usersetting > 11 &&
|
||||
usersetting < 8)
|
||||
return 11;
|
||||
return usersetting;
|
||||
case 32: // 4096 bit // prefer sha224
|
||||
if (usersetting > 10 &&
|
||||
usersetting < 8)
|
||||
return 8; // prefer sha256
|
||||
return usersetting;
|
||||
default:
|
||||
util.print_debug("DSA select hash algorithm: returning null for an unknown length of q");
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
this.select_hash_algorithm = select_hash_algorithm;
|
||||
|
||||
function verify(hashalgo, s1,s2,m,p,q,g,y) {
|
||||
var hashed_data = util.getLeftNBits(openpgp_crypto_hashData(hashalgo,m),q.bitLength());
|
||||
var hash = new BigInteger(util.hexstrdump(hashed_data), 16);
|
||||
if (BigInteger.ZERO.compareTo(s1) > 0 ||
|
||||
s1.compareTo(q) > 0 ||
|
||||
BigInteger.ZERO.compareTo(s2) > 0 ||
|
||||
s2.compareTo(q) > 0) {
|
||||
util.print_error("invalid DSA Signature");
|
||||
return null;
|
||||
}
|
||||
var w = s2.modInverse(q);
|
||||
var u1 = hash.multiply(w).mod(q);
|
||||
var u2 = s1.multiply(w).mod(q);
|
||||
return g.modPow(u1,p).multiply(y.modPow(u2,p)).mod(p).mod(q);
|
||||
}
|
||||
|
||||
/*
|
||||
* unused code. This can be used as a start to write a key generator
|
||||
* function.
|
||||
|
||||
function generateKey(bitcount) {
|
||||
var qi = new BigInteger(bitcount, primeCenterie);
|
||||
var pi = generateP(q, 512);
|
||||
var gi = generateG(p, q, bitcount);
|
||||
var xi;
|
||||
do {
|
||||
xi = new BigInteger(q.bitCount(), rand);
|
||||
} while (x.compareTo(BigInteger.ZERO) != 1 && x.compareTo(q) != -1);
|
||||
var yi = g.modPow(x, p);
|
||||
return {x: xi, q: qi, p: pi, g: gi, y: yi};
|
||||
}
|
||||
|
||||
function generateP(q, bitlength, randomfn) {
|
||||
if (bitlength % 64 != 0) {
|
||||
return false;
|
||||
}
|
||||
var pTemp;
|
||||
var pTemp2;
|
||||
do {
|
||||
pTemp = randomfn(bitcount, true);
|
||||
pTemp2 = pTemp.subtract(BigInteger.ONE);
|
||||
pTemp = pTemp.subtract(pTemp2.remainder(q));
|
||||
} while (!pTemp.isProbablePrime(primeCenterie) || pTemp.bitLength() != l);
|
||||
return pTemp;
|
||||
}
|
||||
|
||||
function generateG(p, q, bitlength, randomfn) {
|
||||
var aux = p.subtract(BigInteger.ONE);
|
||||
var pow = aux.divide(q);
|
||||
var gTemp;
|
||||
do {
|
||||
gTemp = randomfn(bitlength);
|
||||
} while (gTemp.compareTo(aux) != -1 && gTemp.compareTo(BigInteger.ONE) != 1);
|
||||
return gTemp.modPow(pow, p);
|
||||
}
|
||||
|
||||
function generateK(q, bitlength, randomfn) {
|
||||
var tempK;
|
||||
do {
|
||||
tempK = randomfn(bitlength, false);
|
||||
} while (tempK.compareTo(q) != -1 && tempK.compareTo(BigInteger.ZERO) != 1);
|
||||
return tempK;
|
||||
}
|
||||
|
||||
function generateR(q,p) {
|
||||
k = generateK(q);
|
||||
var r = g.modPow(k, p).mod(q);
|
||||
return r;
|
||||
}
|
||||
|
||||
function generateS(hashfn,k,r,m,q,x) {
|
||||
var hash = hashfn(m);
|
||||
s = (k.modInverse(q).multiply(hash.add(x.multiply(r)))).mod(q);
|
||||
return s;
|
||||
} */
|
||||
this.sign = sign;
|
||||
this.verify = verify;
|
||||
// this.generate = generateKey;
|
||||
}
|
||||
48
src/ciphers/asymmetric/elgamal.js
Executable file
48
src/ciphers/asymmetric/elgamal.js
Executable file
@@ -0,0 +1,48 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
// ElGamal implementation
|
||||
|
||||
function Elgamal() {
|
||||
|
||||
function encrypt(m,g,p,y) {
|
||||
// choose k in {2,...,p-2}
|
||||
var two = BigInteger.ONE.add(BigInteger.ONE);
|
||||
var pMinus2 = p.subtract(two);
|
||||
var k = openpgp_crypto_getRandomBigIntegerInRange(two, pMinus2);
|
||||
var k = k.mod(pMinus2).add(BigInteger.ONE);
|
||||
var c = new Array();
|
||||
c[0] = g.modPow(k, p);
|
||||
c[1] = y.modPow(k, p).multiply(m).mod(p).toMPI();
|
||||
c[0] = c[0].toMPI();
|
||||
return c;
|
||||
}
|
||||
|
||||
function decrypt(c1,c2,p,x) {
|
||||
util.print_debug("Elgamal Decrypt:\nc1:"+util.hexstrdump(c1.toMPI())+"\n"+
|
||||
"c2:"+util.hexstrdump(c2.toMPI())+"\n"+
|
||||
"p:"+util.hexstrdump(p.toMPI())+"\n"+
|
||||
"x:"+util.hexstrdump(x.toMPI()));
|
||||
return (c1.modPow(x, p).modInverse(p)).multiply(c2).mod(p);
|
||||
//var c = c1.pow(x).modInverse(p); // c0^-a mod p
|
||||
//return c.multiply(c2).mod(p);
|
||||
}
|
||||
|
||||
// signing and signature verification using Elgamal is not required by OpenPGP.
|
||||
this.encrypt = encrypt;
|
||||
this.decrypt = decrypt;
|
||||
}
|
||||
589
src/ciphers/asymmetric/jsbn.js
Executable file
589
src/ciphers/asymmetric/jsbn.js
Executable file
@@ -0,0 +1,589 @@
|
||||
/*
|
||||
* Copyright (c) 2003-2005 Tom Wu (tjw@cs.Stanford.EDU)
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Modified by Recurity Labs GmbH
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
|
||||
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
|
||||
* INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
|
||||
* THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
|
||||
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* In addition, the following condition applies:
|
||||
*
|
||||
* All redistributions must retain an intact copy of this copyright notice
|
||||
* and disclaimer.
|
||||
*/
|
||||
|
||||
// Basic JavaScript BN library - subset useful for RSA encryption.
|
||||
|
||||
// Bits per digit
|
||||
var dbits;
|
||||
|
||||
// JavaScript engine analysis
|
||||
var canary = 0xdeadbeefcafe;
|
||||
var j_lm = ((canary&0xffffff)==0xefcafe);
|
||||
|
||||
// (public) Constructor
|
||||
function BigInteger(a,b,c) {
|
||||
if(a != null)
|
||||
if("number" == typeof a) this.fromNumber(a,b,c);
|
||||
else if(b == null && "string" != typeof a) this.fromString(a,256);
|
||||
else this.fromString(a,b);
|
||||
}
|
||||
|
||||
// return new, unset BigInteger
|
||||
function nbi() { return new BigInteger(null); }
|
||||
|
||||
// am: Compute w_j += (x*this_i), propagate carries,
|
||||
// c is initial carry, returns final carry.
|
||||
// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
|
||||
// We need to select the fastest one that works in this environment.
|
||||
|
||||
// am1: use a single mult and divide to get the high bits,
|
||||
// max digit bits should be 26 because
|
||||
// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
|
||||
function am1(i,x,w,j,c,n) {
|
||||
while(--n >= 0) {
|
||||
var v = x*this[i++]+w[j]+c;
|
||||
c = Math.floor(v/0x4000000);
|
||||
w[j++] = v&0x3ffffff;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
// am2 avoids a big mult-and-extract completely.
|
||||
// Max digit bits should be <= 30 because we do bitwise ops
|
||||
// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
|
||||
function am2(i,x,w,j,c,n) {
|
||||
var xl = x&0x7fff, xh = x>>15;
|
||||
while(--n >= 0) {
|
||||
var l = this[i]&0x7fff;
|
||||
var h = this[i++]>>15;
|
||||
var m = xh*l+h*xl;
|
||||
l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff);
|
||||
c = (l>>>30)+(m>>>15)+xh*h+(c>>>30);
|
||||
w[j++] = l&0x3fffffff;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
// Alternately, set max digit bits to 28 since some
|
||||
// browsers slow down when dealing with 32-bit numbers.
|
||||
function am3(i,x,w,j,c,n) {
|
||||
var xl = x&0x3fff, xh = x>>14;
|
||||
while(--n >= 0) {
|
||||
var l = this[i]&0x3fff;
|
||||
var h = this[i++]>>14;
|
||||
var m = xh*l+h*xl;
|
||||
l = xl*l+((m&0x3fff)<<14)+w[j]+c;
|
||||
c = (l>>28)+(m>>14)+xh*h;
|
||||
w[j++] = l&0xfffffff;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
|
||||
BigInteger.prototype.am = am2;
|
||||
dbits = 30;
|
||||
}
|
||||
else if(j_lm && (navigator.appName != "Netscape")) {
|
||||
BigInteger.prototype.am = am1;
|
||||
dbits = 26;
|
||||
}
|
||||
else { // Mozilla/Netscape seems to prefer am3
|
||||
BigInteger.prototype.am = am3;
|
||||
dbits = 28;
|
||||
}
|
||||
|
||||
BigInteger.prototype.DB = dbits;
|
||||
BigInteger.prototype.DM = ((1<<dbits)-1);
|
||||
BigInteger.prototype.DV = (1<<dbits);
|
||||
|
||||
var BI_FP = 52;
|
||||
BigInteger.prototype.FV = Math.pow(2,BI_FP);
|
||||
BigInteger.prototype.F1 = BI_FP-dbits;
|
||||
BigInteger.prototype.F2 = 2*dbits-BI_FP;
|
||||
|
||||
// Digit conversions
|
||||
var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
var BI_RC = new Array();
|
||||
var rr,vv;
|
||||
rr = "0".charCodeAt(0);
|
||||
for(vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
|
||||
rr = "a".charCodeAt(0);
|
||||
for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
|
||||
rr = "A".charCodeAt(0);
|
||||
for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
|
||||
|
||||
function int2char(n) { return BI_RM.charAt(n); }
|
||||
function intAt(s,i) {
|
||||
var c = BI_RC[s.charCodeAt(i)];
|
||||
return (c==null)?-1:c;
|
||||
}
|
||||
|
||||
// (protected) copy this to r
|
||||
function bnpCopyTo(r) {
|
||||
for(var i = this.t-1; i >= 0; --i) r[i] = this[i];
|
||||
r.t = this.t;
|
||||
r.s = this.s;
|
||||
}
|
||||
|
||||
// (protected) set from integer value x, -DV <= x < DV
|
||||
function bnpFromInt(x) {
|
||||
this.t = 1;
|
||||
this.s = (x<0)?-1:0;
|
||||
if(x > 0) this[0] = x;
|
||||
else if(x < -1) this[0] = x+DV;
|
||||
else this.t = 0;
|
||||
}
|
||||
|
||||
// return bigint initialized to value
|
||||
function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
|
||||
|
||||
// (protected) set from string and radix
|
||||
function bnpFromString(s,b) {
|
||||
var k;
|
||||
if(b == 16) k = 4;
|
||||
else if(b == 8) k = 3;
|
||||
else if(b == 256) k = 8; // byte array
|
||||
else if(b == 2) k = 1;
|
||||
else if(b == 32) k = 5;
|
||||
else if(b == 4) k = 2;
|
||||
else { this.fromRadix(s,b); return; }
|
||||
this.t = 0;
|
||||
this.s = 0;
|
||||
var i = s.length, mi = false, sh = 0;
|
||||
while(--i >= 0) {
|
||||
var x = (k==8)?s[i]&0xff:intAt(s,i);
|
||||
if(x < 0) {
|
||||
if(s.charAt(i) == "-") mi = true;
|
||||
continue;
|
||||
}
|
||||
mi = false;
|
||||
if(sh == 0)
|
||||
this[this.t++] = x;
|
||||
else if(sh+k > this.DB) {
|
||||
this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<<sh;
|
||||
this[this.t++] = (x>>(this.DB-sh));
|
||||
}
|
||||
else
|
||||
this[this.t-1] |= x<<sh;
|
||||
sh += k;
|
||||
if(sh >= this.DB) sh -= this.DB;
|
||||
}
|
||||
if(k == 8 && (s[0]&0x80) != 0) {
|
||||
this.s = -1;
|
||||
if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh;
|
||||
}
|
||||
this.clamp();
|
||||
if(mi) BigInteger.ZERO.subTo(this,this);
|
||||
}
|
||||
|
||||
// (protected) clamp off excess high words
|
||||
function bnpClamp() {
|
||||
var c = this.s&this.DM;
|
||||
while(this.t > 0 && this[this.t-1] == c) --this.t;
|
||||
}
|
||||
|
||||
// (public) return string representation in given radix
|
||||
function bnToString(b) {
|
||||
if(this.s < 0) return "-"+this.negate().toString(b);
|
||||
var k;
|
||||
if(b == 16) k = 4;
|
||||
else if(b == 8) k = 3;
|
||||
else if(b == 2) k = 1;
|
||||
else if(b == 32) k = 5;
|
||||
else if(b == 4) k = 2;
|
||||
else return this.toRadix(b);
|
||||
var km = (1<<k)-1, d, m = false, r = "", i = this.t;
|
||||
var p = this.DB-(i*this.DB)%k;
|
||||
if(i-- > 0) {
|
||||
if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); }
|
||||
while(i >= 0) {
|
||||
if(p < k) {
|
||||
d = (this[i]&((1<<p)-1))<<(k-p);
|
||||
d |= this[--i]>>(p+=this.DB-k);
|
||||
}
|
||||
else {
|
||||
d = (this[i]>>(p-=k))&km;
|
||||
if(p <= 0) { p += this.DB; --i; }
|
||||
}
|
||||
if(d > 0) m = true;
|
||||
if(m) r += int2char(d);
|
||||
}
|
||||
}
|
||||
return m?r:"0";
|
||||
}
|
||||
|
||||
// (public) -this
|
||||
function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }
|
||||
|
||||
// (public) |this|
|
||||
function bnAbs() { return (this.s<0)?this.negate():this; }
|
||||
|
||||
// (public) return + if this > a, - if this < a, 0 if equal
|
||||
function bnCompareTo(a) {
|
||||
var r = this.s-a.s;
|
||||
if(r != 0) return r;
|
||||
var i = this.t;
|
||||
r = i-a.t;
|
||||
if(r != 0) return r;
|
||||
while(--i >= 0) if((r=this[i]-a[i]) != 0) return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// returns bit length of the integer x
|
||||
function nbits(x) {
|
||||
var r = 1, t;
|
||||
if((t=x>>>16) != 0) { x = t; r += 16; }
|
||||
if((t=x>>8) != 0) { x = t; r += 8; }
|
||||
if((t=x>>4) != 0) { x = t; r += 4; }
|
||||
if((t=x>>2) != 0) { x = t; r += 2; }
|
||||
if((t=x>>1) != 0) { x = t; r += 1; }
|
||||
return r;
|
||||
}
|
||||
|
||||
// (public) return the number of bits in "this"
|
||||
function bnBitLength() {
|
||||
if(this.t <= 0) return 0;
|
||||
return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM));
|
||||
}
|
||||
|
||||
// (protected) r = this << n*DB
|
||||
function bnpDLShiftTo(n,r) {
|
||||
var i;
|
||||
for(i = this.t-1; i >= 0; --i) r[i+n] = this[i];
|
||||
for(i = n-1; i >= 0; --i) r[i] = 0;
|
||||
r.t = this.t+n;
|
||||
r.s = this.s;
|
||||
}
|
||||
|
||||
// (protected) r = this >> n*DB
|
||||
function bnpDRShiftTo(n,r) {
|
||||
for(var i = n; i < this.t; ++i) r[i-n] = this[i];
|
||||
r.t = Math.max(this.t-n,0);
|
||||
r.s = this.s;
|
||||
}
|
||||
|
||||
// (protected) r = this << n
|
||||
function bnpLShiftTo(n,r) {
|
||||
var bs = n%this.DB;
|
||||
var cbs = this.DB-bs;
|
||||
var bm = (1<<cbs)-1;
|
||||
var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i;
|
||||
for(i = this.t-1; i >= 0; --i) {
|
||||
r[i+ds+1] = (this[i]>>cbs)|c;
|
||||
c = (this[i]&bm)<<bs;
|
||||
}
|
||||
for(i = ds-1; i >= 0; --i) r[i] = 0;
|
||||
r[ds] = c;
|
||||
r.t = this.t+ds+1;
|
||||
r.s = this.s;
|
||||
r.clamp();
|
||||
}
|
||||
|
||||
// (protected) r = this >> n
|
||||
function bnpRShiftTo(n,r) {
|
||||
r.s = this.s;
|
||||
var ds = Math.floor(n/this.DB);
|
||||
if(ds >= this.t) { r.t = 0; return; }
|
||||
var bs = n%this.DB;
|
||||
var cbs = this.DB-bs;
|
||||
var bm = (1<<bs)-1;
|
||||
r[0] = this[ds]>>bs;
|
||||
for(var i = ds+1; i < this.t; ++i) {
|
||||
r[i-ds-1] |= (this[i]&bm)<<cbs;
|
||||
r[i-ds] = this[i]>>bs;
|
||||
}
|
||||
if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs;
|
||||
r.t = this.t-ds;
|
||||
r.clamp();
|
||||
}
|
||||
|
||||
// (protected) r = this - a
|
||||
function bnpSubTo(a,r) {
|
||||
var i = 0, c = 0, m = Math.min(a.t,this.t);
|
||||
while(i < m) {
|
||||
c += this[i]-a[i];
|
||||
r[i++] = c&this.DM;
|
||||
c >>= this.DB;
|
||||
}
|
||||
if(a.t < this.t) {
|
||||
c -= a.s;
|
||||
while(i < this.t) {
|
||||
c += this[i];
|
||||
r[i++] = c&this.DM;
|
||||
c >>= this.DB;
|
||||
}
|
||||
c += this.s;
|
||||
}
|
||||
else {
|
||||
c += this.s;
|
||||
while(i < a.t) {
|
||||
c -= a[i];
|
||||
r[i++] = c&this.DM;
|
||||
c >>= this.DB;
|
||||
}
|
||||
c -= a.s;
|
||||
}
|
||||
r.s = (c<0)?-1:0;
|
||||
if(c < -1) r[i++] = this.DV+c;
|
||||
else if(c > 0) r[i++] = c;
|
||||
r.t = i;
|
||||
r.clamp();
|
||||
}
|
||||
|
||||
// (protected) r = this * a, r != this,a (HAC 14.12)
|
||||
// "this" should be the larger one if appropriate.
|
||||
function bnpMultiplyTo(a,r) {
|
||||
var x = this.abs(), y = a.abs();
|
||||
var i = x.t;
|
||||
r.t = i+y.t;
|
||||
while(--i >= 0) r[i] = 0;
|
||||
for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t);
|
||||
r.s = 0;
|
||||
r.clamp();
|
||||
if(this.s != a.s) BigInteger.ZERO.subTo(r,r);
|
||||
}
|
||||
|
||||
// (protected) r = this^2, r != this (HAC 14.16)
|
||||
function bnpSquareTo(r) {
|
||||
var x = this.abs();
|
||||
var i = r.t = 2*x.t;
|
||||
while(--i >= 0) r[i] = 0;
|
||||
for(i = 0; i < x.t-1; ++i) {
|
||||
var c = x.am(i,x[i],r,2*i,0,1);
|
||||
if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) {
|
||||
r[i+x.t] -= x.DV;
|
||||
r[i+x.t+1] = 1;
|
||||
}
|
||||
}
|
||||
if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1);
|
||||
r.s = 0;
|
||||
r.clamp();
|
||||
}
|
||||
|
||||
// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
|
||||
// r != q, this != m. q or r may be null.
|
||||
function bnpDivRemTo(m,q,r) {
|
||||
var pm = m.abs();
|
||||
if(pm.t <= 0) return;
|
||||
var pt = this.abs();
|
||||
if(pt.t < pm.t) {
|
||||
if(q != null) q.fromInt(0);
|
||||
if(r != null) this.copyTo(r);
|
||||
return;
|
||||
}
|
||||
if(r == null) r = nbi();
|
||||
var y = nbi(), ts = this.s, ms = m.s;
|
||||
var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus
|
||||
if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); }
|
||||
else { pm.copyTo(y); pt.copyTo(r); }
|
||||
var ys = y.t;
|
||||
var y0 = y[ys-1];
|
||||
if(y0 == 0) return;
|
||||
var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0);
|
||||
var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
|
||||
var i = r.t, j = i-ys, t = (q==null)?nbi():q;
|
||||
y.dlShiftTo(j,t);
|
||||
if(r.compareTo(t) >= 0) {
|
||||
r[r.t++] = 1;
|
||||
r.subTo(t,r);
|
||||
}
|
||||
BigInteger.ONE.dlShiftTo(ys,t);
|
||||
t.subTo(y,y); // "negative" y so we can replace sub with am later
|
||||
while(y.t < ys) y[y.t++] = 0;
|
||||
while(--j >= 0) {
|
||||
// Estimate quotient digit
|
||||
var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);
|
||||
if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out
|
||||
y.dlShiftTo(j,t);
|
||||
r.subTo(t,r);
|
||||
while(r[i] < --qd) r.subTo(t,r);
|
||||
}
|
||||
}
|
||||
if(q != null) {
|
||||
r.drShiftTo(ys,q);
|
||||
if(ts != ms) BigInteger.ZERO.subTo(q,q);
|
||||
}
|
||||
r.t = ys;
|
||||
r.clamp();
|
||||
if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder
|
||||
if(ts < 0) BigInteger.ZERO.subTo(r,r);
|
||||
}
|
||||
|
||||
// (public) this mod a
|
||||
function bnMod(a) {
|
||||
var r = nbi();
|
||||
this.abs().divRemTo(a,null,r);
|
||||
if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r);
|
||||
return r;
|
||||
}
|
||||
|
||||
// Modular reduction using "classic" algorithm
|
||||
function Classic(m) { this.m = m; }
|
||||
function cConvert(x) {
|
||||
if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
|
||||
else return x;
|
||||
}
|
||||
function cRevert(x) { return x; }
|
||||
function cReduce(x) { x.divRemTo(this.m,null,x); }
|
||||
function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
|
||||
function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
|
||||
|
||||
Classic.prototype.convert = cConvert;
|
||||
Classic.prototype.revert = cRevert;
|
||||
Classic.prototype.reduce = cReduce;
|
||||
Classic.prototype.mulTo = cMulTo;
|
||||
Classic.prototype.sqrTo = cSqrTo;
|
||||
|
||||
// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
|
||||
// justification:
|
||||
// xy == 1 (mod m)
|
||||
// xy = 1+km
|
||||
// xy(2-xy) = (1+km)(1-km)
|
||||
// x[y(2-xy)] = 1-k^2m^2
|
||||
// x[y(2-xy)] == 1 (mod m^2)
|
||||
// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
|
||||
// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
|
||||
// JS multiply "overflows" differently from C/C++, so care is needed here.
|
||||
function bnpInvDigit() {
|
||||
if(this.t < 1) return 0;
|
||||
var x = this[0];
|
||||
if((x&1) == 0) return 0;
|
||||
var y = x&3; // y == 1/x mod 2^2
|
||||
y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4
|
||||
y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8
|
||||
y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16
|
||||
// last step - calculate inverse mod DV directly;
|
||||
// assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
|
||||
y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits
|
||||
// we really want the negative inverse, and -DV < y < DV
|
||||
return (y>0)?this.DV-y:-y;
|
||||
}
|
||||
|
||||
// Montgomery reduction
|
||||
function Montgomery(m) {
|
||||
this.m = m;
|
||||
this.mp = m.invDigit();
|
||||
this.mpl = this.mp&0x7fff;
|
||||
this.mph = this.mp>>15;
|
||||
this.um = (1<<(m.DB-15))-1;
|
||||
this.mt2 = 2*m.t;
|
||||
}
|
||||
|
||||
// xR mod m
|
||||
function montConvert(x) {
|
||||
var r = nbi();
|
||||
x.abs().dlShiftTo(this.m.t,r);
|
||||
r.divRemTo(this.m,null,r);
|
||||
if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r);
|
||||
return r;
|
||||
}
|
||||
|
||||
// x/R mod m
|
||||
function montRevert(x) {
|
||||
var r = nbi();
|
||||
x.copyTo(r);
|
||||
this.reduce(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
// x = x/R mod m (HAC 14.32)
|
||||
function montReduce(x) {
|
||||
while(x.t <= this.mt2) // pad x so am has enough room later
|
||||
x[x.t++] = 0;
|
||||
for(var i = 0; i < this.m.t; ++i) {
|
||||
// faster way of calculating u0 = x[i]*mp mod DV
|
||||
var j = x[i]&0x7fff;
|
||||
var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM;
|
||||
// use am to combine the multiply-shift-add into one call
|
||||
j = i+this.m.t;
|
||||
x[j] += this.m.am(0,u0,x,i,0,this.m.t);
|
||||
// propagate carry
|
||||
while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; }
|
||||
}
|
||||
x.clamp();
|
||||
x.drShiftTo(this.m.t,x);
|
||||
if(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
|
||||
}
|
||||
|
||||
// r = "x^2/R mod m"; x != r
|
||||
function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
|
||||
|
||||
// r = "xy/R mod m"; x,y != r
|
||||
function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
|
||||
|
||||
Montgomery.prototype.convert = montConvert;
|
||||
Montgomery.prototype.revert = montRevert;
|
||||
Montgomery.prototype.reduce = montReduce;
|
||||
Montgomery.prototype.mulTo = montMulTo;
|
||||
Montgomery.prototype.sqrTo = montSqrTo;
|
||||
|
||||
// (protected) true iff this is even
|
||||
function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; }
|
||||
|
||||
// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
|
||||
function bnpExp(e,z) {
|
||||
if(e > 0xffffffff || e < 1) return BigInteger.ONE;
|
||||
var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1;
|
||||
g.copyTo(r);
|
||||
while(--i >= 0) {
|
||||
z.sqrTo(r,r2);
|
||||
if((e&(1<<i)) > 0) z.mulTo(r2,g,r);
|
||||
else { var t = r; r = r2; r2 = t; }
|
||||
}
|
||||
return z.revert(r);
|
||||
}
|
||||
|
||||
// (public) this^e % m, 0 <= e < 2^32
|
||||
function bnModPowInt(e,m) {
|
||||
var z;
|
||||
if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
|
||||
return this.exp(e,z);
|
||||
}
|
||||
|
||||
// protected
|
||||
BigInteger.prototype.copyTo = bnpCopyTo;
|
||||
BigInteger.prototype.fromInt = bnpFromInt;
|
||||
BigInteger.prototype.fromString = bnpFromString;
|
||||
BigInteger.prototype.clamp = bnpClamp;
|
||||
BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
|
||||
BigInteger.prototype.drShiftTo = bnpDRShiftTo;
|
||||
BigInteger.prototype.lShiftTo = bnpLShiftTo;
|
||||
BigInteger.prototype.rShiftTo = bnpRShiftTo;
|
||||
BigInteger.prototype.subTo = bnpSubTo;
|
||||
BigInteger.prototype.multiplyTo = bnpMultiplyTo;
|
||||
BigInteger.prototype.squareTo = bnpSquareTo;
|
||||
BigInteger.prototype.divRemTo = bnpDivRemTo;
|
||||
BigInteger.prototype.invDigit = bnpInvDigit;
|
||||
BigInteger.prototype.isEven = bnpIsEven;
|
||||
BigInteger.prototype.exp = bnpExp;
|
||||
|
||||
// public
|
||||
BigInteger.prototype.toString = bnToString;
|
||||
BigInteger.prototype.negate = bnNegate;
|
||||
BigInteger.prototype.abs = bnAbs;
|
||||
BigInteger.prototype.compareTo = bnCompareTo;
|
||||
BigInteger.prototype.bitLength = bnBitLength;
|
||||
BigInteger.prototype.mod = bnMod;
|
||||
BigInteger.prototype.modPowInt = bnModPowInt;
|
||||
|
||||
// "constants"
|
||||
BigInteger.ZERO = nbv(0);
|
||||
BigInteger.ONE = nbv(1);
|
||||
|
||||
714
src/ciphers/asymmetric/jsbn2.js
Executable file
714
src/ciphers/asymmetric/jsbn2.js
Executable file
@@ -0,0 +1,714 @@
|
||||
/*
|
||||
* Copyright (c) 2003-2005 Tom Wu (tjw@cs.Stanford.EDU)
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Modified by Recurity Labs GmbH
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
|
||||
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
|
||||
* INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
|
||||
* THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
|
||||
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* In addition, the following condition applies:
|
||||
*
|
||||
* All redistributions must retain an intact copy of this copyright notice
|
||||
* and disclaimer.
|
||||
*/
|
||||
// Extended JavaScript BN functions, required for RSA private ops.
|
||||
|
||||
// Version 1.1: new BigInteger("0", 10) returns "proper" zero
|
||||
// Version 1.2: square() API, isProbablePrime fix
|
||||
|
||||
// (public)
|
||||
function bnClone() { var r = nbi(); this.copyTo(r); return r; }
|
||||
|
||||
// (public) return value as integer
|
||||
function bnIntValue() {
|
||||
if(this.s < 0) {
|
||||
if(this.t == 1) return this[0]-this.DV;
|
||||
else if(this.t == 0) return -1;
|
||||
}
|
||||
else if(this.t == 1) return this[0];
|
||||
else if(this.t == 0) return 0;
|
||||
// assumes 16 < DB < 32
|
||||
return ((this[1]&((1<<(32-this.DB))-1))<<this.DB)|this[0];
|
||||
}
|
||||
|
||||
// (public) return value as byte
|
||||
function bnByteValue() { return (this.t==0)?this.s:(this[0]<<24)>>24; }
|
||||
|
||||
// (public) return value as short (assumes DB>=16)
|
||||
function bnShortValue() { return (this.t==0)?this.s:(this[0]<<16)>>16; }
|
||||
|
||||
// (protected) return x s.t. r^x < DV
|
||||
function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); }
|
||||
|
||||
// (public) 0 if this == 0, 1 if this > 0
|
||||
function bnSigNum() {
|
||||
if(this.s < 0) return -1;
|
||||
else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
|
||||
else return 1;
|
||||
}
|
||||
|
||||
// (protected) convert to radix string
|
||||
function bnpToRadix(b) {
|
||||
if(b == null) b = 10;
|
||||
if(this.signum() == 0 || b < 2 || b > 36) return "0";
|
||||
var cs = this.chunkSize(b);
|
||||
var a = Math.pow(b,cs);
|
||||
var d = nbv(a), y = nbi(), z = nbi(), r = "";
|
||||
this.divRemTo(d,y,z);
|
||||
while(y.signum() > 0) {
|
||||
r = (a+z.intValue()).toString(b).substr(1) + r;
|
||||
y.divRemTo(d,y,z);
|
||||
}
|
||||
return z.intValue().toString(b) + r;
|
||||
}
|
||||
|
||||
// (protected) convert from radix string
|
||||
function bnpFromRadix(s,b) {
|
||||
this.fromInt(0);
|
||||
if(b == null) b = 10;
|
||||
var cs = this.chunkSize(b);
|
||||
var d = Math.pow(b,cs), mi = false, j = 0, w = 0;
|
||||
for(var i = 0; i < s.length; ++i) {
|
||||
var x = intAt(s,i);
|
||||
if(x < 0) {
|
||||
if(s.charAt(i) == "-" && this.signum() == 0) mi = true;
|
||||
continue;
|
||||
}
|
||||
w = b*w+x;
|
||||
if(++j >= cs) {
|
||||
this.dMultiply(d);
|
||||
this.dAddOffset(w,0);
|
||||
j = 0;
|
||||
w = 0;
|
||||
}
|
||||
}
|
||||
if(j > 0) {
|
||||
this.dMultiply(Math.pow(b,j));
|
||||
this.dAddOffset(w,0);
|
||||
}
|
||||
if(mi) BigInteger.ZERO.subTo(this,this);
|
||||
}
|
||||
|
||||
// (protected) alternate constructor
|
||||
function bnpFromNumber(a,b,c) {
|
||||
if("number" == typeof b) {
|
||||
// new BigInteger(int,int,RNG)
|
||||
if(a < 2) this.fromInt(1);
|
||||
else {
|
||||
this.fromNumber(a,c);
|
||||
if(!this.testBit(a-1)) // force MSB set
|
||||
this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this);
|
||||
if(this.isEven()) this.dAddOffset(1,0); // force odd
|
||||
while(!this.isProbablePrime(b)) {
|
||||
this.dAddOffset(2,0);
|
||||
if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// new BigInteger(int,RNG)
|
||||
var x = new Array(), t = a&7;
|
||||
x.length = (a>>3)+1;
|
||||
b.nextBytes(x);
|
||||
if(t > 0) x[0] &= ((1<<t)-1); else x[0] = 0;
|
||||
this.fromString(x,256);
|
||||
}
|
||||
}
|
||||
|
||||
// (public) convert to bigendian byte array
|
||||
function bnToByteArray() {
|
||||
var i = this.t, r = new Array();
|
||||
r[0] = this.s;
|
||||
var p = this.DB-(i*this.DB)%8, d, k = 0;
|
||||
if(i-- > 0) {
|
||||
if(p < this.DB && (d = this[i]>>p) != (this.s&this.DM)>>p)
|
||||
r[k++] = d|(this.s<<(this.DB-p));
|
||||
while(i >= 0) {
|
||||
if(p < 8) {
|
||||
d = (this[i]&((1<<p)-1))<<(8-p);
|
||||
d |= this[--i]>>(p+=this.DB-8);
|
||||
}
|
||||
else {
|
||||
d = (this[i]>>(p-=8))&0xff;
|
||||
if(p <= 0) { p += this.DB; --i; }
|
||||
}
|
||||
//if((d&0x80) != 0) d |= -256;
|
||||
//if(k == 0 && (this.s&0x80) != (d&0x80)) ++k;
|
||||
if(k > 0 || d != this.s) r[k++] = d;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
function bnEquals(a) { return(this.compareTo(a)==0); }
|
||||
function bnMin(a) { return(this.compareTo(a)<0)?this:a; }
|
||||
function bnMax(a) { return(this.compareTo(a)>0)?this:a; }
|
||||
|
||||
// (protected) r = this op a (bitwise)
|
||||
function bnpBitwiseTo(a,op,r) {
|
||||
var i, f, m = Math.min(a.t,this.t);
|
||||
for(i = 0; i < m; ++i) r[i] = op(this[i],a[i]);
|
||||
if(a.t < this.t) {
|
||||
f = a.s&this.DM;
|
||||
for(i = m; i < this.t; ++i) r[i] = op(this[i],f);
|
||||
r.t = this.t;
|
||||
}
|
||||
else {
|
||||
f = this.s&this.DM;
|
||||
for(i = m; i < a.t; ++i) r[i] = op(f,a[i]);
|
||||
r.t = a.t;
|
||||
}
|
||||
r.s = op(this.s,a.s);
|
||||
r.clamp();
|
||||
}
|
||||
|
||||
// (public) this & a
|
||||
function op_and(x,y) { return x&y; }
|
||||
function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; }
|
||||
|
||||
// (public) this | a
|
||||
function op_or(x,y) { return x|y; }
|
||||
function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; }
|
||||
|
||||
// (public) this ^ a
|
||||
function op_xor(x,y) { return x^y; }
|
||||
function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; }
|
||||
|
||||
// (public) this & ~a
|
||||
function op_andnot(x,y) { return x&~y; }
|
||||
function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; }
|
||||
|
||||
// (public) ~this
|
||||
function bnNot() {
|
||||
var r = nbi();
|
||||
for(var i = 0; i < this.t; ++i) r[i] = this.DM&~this[i];
|
||||
r.t = this.t;
|
||||
r.s = ~this.s;
|
||||
return r;
|
||||
}
|
||||
|
||||
// (public) this << n
|
||||
function bnShiftLeft(n) {
|
||||
var r = nbi();
|
||||
if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r);
|
||||
return r;
|
||||
}
|
||||
|
||||
// (public) this >> n
|
||||
function bnShiftRight(n) {
|
||||
var r = nbi();
|
||||
if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r);
|
||||
return r;
|
||||
}
|
||||
|
||||
// return index of lowest 1-bit in x, x < 2^31
|
||||
function lbit(x) {
|
||||
if(x == 0) return -1;
|
||||
var r = 0;
|
||||
if((x&0xffff) == 0) { x >>= 16; r += 16; }
|
||||
if((x&0xff) == 0) { x >>= 8; r += 8; }
|
||||
if((x&0xf) == 0) { x >>= 4; r += 4; }
|
||||
if((x&3) == 0) { x >>= 2; r += 2; }
|
||||
if((x&1) == 0) ++r;
|
||||
return r;
|
||||
}
|
||||
|
||||
// (public) returns index of lowest 1-bit (or -1 if none)
|
||||
function bnGetLowestSetBit() {
|
||||
for(var i = 0; i < this.t; ++i)
|
||||
if(this[i] != 0) return i*this.DB+lbit(this[i]);
|
||||
if(this.s < 0) return this.t*this.DB;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// return number of 1 bits in x
|
||||
function cbit(x) {
|
||||
var r = 0;
|
||||
while(x != 0) { x &= x-1; ++r; }
|
||||
return r;
|
||||
}
|
||||
|
||||
// (public) return number of set bits
|
||||
function bnBitCount() {
|
||||
var r = 0, x = this.s&this.DM;
|
||||
for(var i = 0; i < this.t; ++i) r += cbit(this[i]^x);
|
||||
return r;
|
||||
}
|
||||
|
||||
// (public) true iff nth bit is set
|
||||
function bnTestBit(n) {
|
||||
var j = Math.floor(n/this.DB);
|
||||
if(j >= this.t) return(this.s!=0);
|
||||
return((this[j]&(1<<(n%this.DB)))!=0);
|
||||
}
|
||||
|
||||
// (protected) this op (1<<n)
|
||||
function bnpChangeBit(n,op) {
|
||||
var r = BigInteger.ONE.shiftLeft(n);
|
||||
this.bitwiseTo(r,op,r);
|
||||
return r;
|
||||
}
|
||||
|
||||
// (public) this | (1<<n)
|
||||
function bnSetBit(n) { return this.changeBit(n,op_or); }
|
||||
|
||||
// (public) this & ~(1<<n)
|
||||
function bnClearBit(n) { return this.changeBit(n,op_andnot); }
|
||||
|
||||
// (public) this ^ (1<<n)
|
||||
function bnFlipBit(n) { return this.changeBit(n,op_xor); }
|
||||
|
||||
// (protected) r = this + a
|
||||
function bnpAddTo(a,r) {
|
||||
var i = 0, c = 0, m = Math.min(a.t,this.t);
|
||||
while(i < m) {
|
||||
c += this[i]+a[i];
|
||||
r[i++] = c&this.DM;
|
||||
c >>= this.DB;
|
||||
}
|
||||
if(a.t < this.t) {
|
||||
c += a.s;
|
||||
while(i < this.t) {
|
||||
c += this[i];
|
||||
r[i++] = c&this.DM;
|
||||
c >>= this.DB;
|
||||
}
|
||||
c += this.s;
|
||||
}
|
||||
else {
|
||||
c += this.s;
|
||||
while(i < a.t) {
|
||||
c += a[i];
|
||||
r[i++] = c&this.DM;
|
||||
c >>= this.DB;
|
||||
}
|
||||
c += a.s;
|
||||
}
|
||||
r.s = (c<0)?-1:0;
|
||||
if(c > 0) r[i++] = c;
|
||||
else if(c < -1) r[i++] = this.DV+c;
|
||||
r.t = i;
|
||||
r.clamp();
|
||||
}
|
||||
|
||||
// (public) this + a
|
||||
function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; }
|
||||
|
||||
// (public) this - a
|
||||
function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; }
|
||||
|
||||
// (public) this * a
|
||||
function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; }
|
||||
|
||||
// (public) this^2
|
||||
function bnSquare() { var r = nbi(); this.squareTo(r); return r; }
|
||||
|
||||
// (public) this / a
|
||||
function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; }
|
||||
|
||||
// (public) this % a
|
||||
function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; }
|
||||
|
||||
// (public) [this/a,this%a]
|
||||
function bnDivideAndRemainder(a) {
|
||||
var q = nbi(), r = nbi();
|
||||
this.divRemTo(a,q,r);
|
||||
return new Array(q,r);
|
||||
}
|
||||
|
||||
// (protected) this *= n, this >= 0, 1 < n < DV
|
||||
function bnpDMultiply(n) {
|
||||
this[this.t] = this.am(0,n-1,this,0,0,this.t);
|
||||
++this.t;
|
||||
this.clamp();
|
||||
}
|
||||
|
||||
// (protected) this += n << w words, this >= 0
|
||||
function bnpDAddOffset(n,w) {
|
||||
if(n == 0) return;
|
||||
while(this.t <= w) this[this.t++] = 0;
|
||||
this[w] += n;
|
||||
while(this[w] >= this.DV) {
|
||||
this[w] -= this.DV;
|
||||
if(++w >= this.t) this[this.t++] = 0;
|
||||
++this[w];
|
||||
}
|
||||
}
|
||||
|
||||
// A "null" reducer
|
||||
function NullExp() {}
|
||||
function nNop(x) { return x; }
|
||||
function nMulTo(x,y,r) { x.multiplyTo(y,r); }
|
||||
function nSqrTo(x,r) { x.squareTo(r); }
|
||||
|
||||
NullExp.prototype.convert = nNop;
|
||||
NullExp.prototype.revert = nNop;
|
||||
NullExp.prototype.mulTo = nMulTo;
|
||||
NullExp.prototype.sqrTo = nSqrTo;
|
||||
|
||||
// (public) this^e
|
||||
function bnPow(e) { return this.exp(e,new NullExp()); }
|
||||
|
||||
// (protected) r = lower n words of "this * a", a.t <= n
|
||||
// "this" should be the larger one if appropriate.
|
||||
function bnpMultiplyLowerTo(a,n,r) {
|
||||
var i = Math.min(this.t+a.t,n);
|
||||
r.s = 0; // assumes a,this >= 0
|
||||
r.t = i;
|
||||
while(i > 0) r[--i] = 0;
|
||||
var j;
|
||||
for(j = r.t-this.t; i < j; ++i) r[i+this.t] = this.am(0,a[i],r,i,0,this.t);
|
||||
for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a[i],r,i,0,n-i);
|
||||
r.clamp();
|
||||
}
|
||||
|
||||
// (protected) r = "this * a" without lower n words, n > 0
|
||||
// "this" should be the larger one if appropriate.
|
||||
function bnpMultiplyUpperTo(a,n,r) {
|
||||
--n;
|
||||
var i = r.t = this.t+a.t-n;
|
||||
r.s = 0; // assumes a,this >= 0
|
||||
while(--i >= 0) r[i] = 0;
|
||||
for(i = Math.max(n-this.t,0); i < a.t; ++i)
|
||||
r[this.t+i-n] = this.am(n-i,a[i],r,0,0,this.t+i-n);
|
||||
r.clamp();
|
||||
r.drShiftTo(1,r);
|
||||
}
|
||||
|
||||
// Barrett modular reduction
|
||||
function Barrett(m) {
|
||||
// setup Barrett
|
||||
this.r2 = nbi();
|
||||
this.q3 = nbi();
|
||||
BigInteger.ONE.dlShiftTo(2*m.t,this.r2);
|
||||
this.mu = this.r2.divide(m);
|
||||
this.m = m;
|
||||
}
|
||||
|
||||
function barrettConvert(x) {
|
||||
if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m);
|
||||
else if(x.compareTo(this.m) < 0) return x;
|
||||
else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; }
|
||||
}
|
||||
|
||||
function barrettRevert(x) { return x; }
|
||||
|
||||
// x = x mod m (HAC 14.42)
|
||||
function barrettReduce(x) {
|
||||
x.drShiftTo(this.m.t-1,this.r2);
|
||||
if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); }
|
||||
this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3);
|
||||
this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);
|
||||
while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1);
|
||||
x.subTo(this.r2,x);
|
||||
while(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
|
||||
}
|
||||
|
||||
// r = x^2 mod m; x != r
|
||||
function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
|
||||
|
||||
// r = x*y mod m; x,y != r
|
||||
function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
|
||||
|
||||
Barrett.prototype.convert = barrettConvert;
|
||||
Barrett.prototype.revert = barrettRevert;
|
||||
Barrett.prototype.reduce = barrettReduce;
|
||||
Barrett.prototype.mulTo = barrettMulTo;
|
||||
Barrett.prototype.sqrTo = barrettSqrTo;
|
||||
|
||||
// (public) this^e % m (HAC 14.85)
|
||||
function bnModPow(e,m) {
|
||||
var i = e.bitLength(), k, r = nbv(1), z;
|
||||
if(i <= 0) return r;
|
||||
else if(i < 18) k = 1;
|
||||
else if(i < 48) k = 3;
|
||||
else if(i < 144) k = 4;
|
||||
else if(i < 768) k = 5;
|
||||
else k = 6;
|
||||
if(i < 8)
|
||||
z = new Classic(m);
|
||||
else if(m.isEven())
|
||||
z = new Barrett(m);
|
||||
else
|
||||
z = new Montgomery(m);
|
||||
|
||||
// precomputation
|
||||
var g = new Array(), n = 3, k1 = k-1, km = (1<<k)-1;
|
||||
g[1] = z.convert(this);
|
||||
if(k > 1) {
|
||||
var g2 = nbi();
|
||||
z.sqrTo(g[1],g2);
|
||||
while(n <= km) {
|
||||
g[n] = nbi();
|
||||
z.mulTo(g2,g[n-2],g[n]);
|
||||
n += 2;
|
||||
}
|
||||
}
|
||||
|
||||
var j = e.t-1, w, is1 = true, r2 = nbi(), t;
|
||||
i = nbits(e[j])-1;
|
||||
while(j >= 0) {
|
||||
if(i >= k1) w = (e[j]>>(i-k1))&km;
|
||||
else {
|
||||
w = (e[j]&((1<<(i+1))-1))<<(k1-i);
|
||||
if(j > 0) w |= e[j-1]>>(this.DB+i-k1);
|
||||
}
|
||||
|
||||
n = k;
|
||||
while((w&1) == 0) { w >>= 1; --n; }
|
||||
if((i -= n) < 0) { i += this.DB; --j; }
|
||||
if(is1) { // ret == 1, don't bother squaring or multiplying it
|
||||
g[w].copyTo(r);
|
||||
is1 = false;
|
||||
}
|
||||
else {
|
||||
while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; }
|
||||
if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; }
|
||||
z.mulTo(r2,g[w],r);
|
||||
}
|
||||
|
||||
while(j >= 0 && (e[j]&(1<<i)) == 0) {
|
||||
z.sqrTo(r,r2); t = r; r = r2; r2 = t;
|
||||
if(--i < 0) { i = this.DB-1; --j; }
|
||||
}
|
||||
}
|
||||
return z.revert(r);
|
||||
}
|
||||
|
||||
// (public) gcd(this,a) (HAC 14.54)
|
||||
function bnGCD(a) {
|
||||
var x = (this.s<0)?this.negate():this.clone();
|
||||
var y = (a.s<0)?a.negate():a.clone();
|
||||
if(x.compareTo(y) < 0) { var t = x; x = y; y = t; }
|
||||
var i = x.getLowestSetBit(), g = y.getLowestSetBit();
|
||||
if(g < 0) return x;
|
||||
if(i < g) g = i;
|
||||
if(g > 0) {
|
||||
x.rShiftTo(g,x);
|
||||
y.rShiftTo(g,y);
|
||||
}
|
||||
while(x.signum() > 0) {
|
||||
if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x);
|
||||
if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y);
|
||||
if(x.compareTo(y) >= 0) {
|
||||
x.subTo(y,x);
|
||||
x.rShiftTo(1,x);
|
||||
}
|
||||
else {
|
||||
y.subTo(x,y);
|
||||
y.rShiftTo(1,y);
|
||||
}
|
||||
}
|
||||
if(g > 0) y.lShiftTo(g,y);
|
||||
return y;
|
||||
}
|
||||
|
||||
// (protected) this % n, n < 2^26
|
||||
function bnpModInt(n) {
|
||||
if(n <= 0) return 0;
|
||||
var d = this.DV%n, r = (this.s<0)?n-1:0;
|
||||
if(this.t > 0)
|
||||
if(d == 0) r = this[0]%n;
|
||||
else for(var i = this.t-1; i >= 0; --i) r = (d*r+this[i])%n;
|
||||
return r;
|
||||
}
|
||||
|
||||
// (public) 1/this % m (HAC 14.61)
|
||||
function bnModInverse(m) {
|
||||
var ac = m.isEven();
|
||||
if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
|
||||
var u = m.clone(), v = this.clone();
|
||||
var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
|
||||
while(u.signum() != 0) {
|
||||
while(u.isEven()) {
|
||||
u.rShiftTo(1,u);
|
||||
if(ac) {
|
||||
if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); }
|
||||
a.rShiftTo(1,a);
|
||||
}
|
||||
else if(!b.isEven()) b.subTo(m,b);
|
||||
b.rShiftTo(1,b);
|
||||
}
|
||||
while(v.isEven()) {
|
||||
v.rShiftTo(1,v);
|
||||
if(ac) {
|
||||
if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); }
|
||||
c.rShiftTo(1,c);
|
||||
}
|
||||
else if(!d.isEven()) d.subTo(m,d);
|
||||
d.rShiftTo(1,d);
|
||||
}
|
||||
if(u.compareTo(v) >= 0) {
|
||||
u.subTo(v,u);
|
||||
if(ac) a.subTo(c,a);
|
||||
b.subTo(d,b);
|
||||
}
|
||||
else {
|
||||
v.subTo(u,v);
|
||||
if(ac) c.subTo(a,c);
|
||||
d.subTo(b,d);
|
||||
}
|
||||
}
|
||||
if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
|
||||
if(d.compareTo(m) >= 0) return d.subtract(m);
|
||||
if(d.signum() < 0) d.addTo(m,d); else return d;
|
||||
if(d.signum() < 0) return d.add(m); else return d;
|
||||
}
|
||||
|
||||
var lowprimes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997];
|
||||
var lplim = (1<<26)/lowprimes[lowprimes.length-1];
|
||||
|
||||
// (public) test primality with certainty >= 1-.5^t
|
||||
function bnIsProbablePrime(t) {
|
||||
var i, x = this.abs();
|
||||
if(x.t == 1 && x[0] <= lowprimes[lowprimes.length-1]) {
|
||||
for(i = 0; i < lowprimes.length; ++i)
|
||||
if(x[0] == lowprimes[i]) return true;
|
||||
return false;
|
||||
}
|
||||
if(x.isEven()) return false;
|
||||
i = 1;
|
||||
while(i < lowprimes.length) {
|
||||
var m = lowprimes[i], j = i+1;
|
||||
while(j < lowprimes.length && m < lplim) m *= lowprimes[j++];
|
||||
m = x.modInt(m);
|
||||
while(i < j) if(m%lowprimes[i++] == 0) return false;
|
||||
}
|
||||
return x.millerRabin(t);
|
||||
}
|
||||
|
||||
/* added by Recurity Labs */
|
||||
|
||||
function nbits(x) {
|
||||
var n = 1, t;
|
||||
if ((t = x >>> 16) != 0) {
|
||||
x = t;
|
||||
n += 16;
|
||||
}
|
||||
if ((t = x >> 8) != 0) {
|
||||
x = t;
|
||||
n += 8;
|
||||
}
|
||||
if ((t = x >> 4) != 0) {
|
||||
x = t;
|
||||
n += 4;
|
||||
}
|
||||
if ((t = x >> 2) != 0) {
|
||||
x = t;
|
||||
n += 2;
|
||||
}
|
||||
if ((t = x >> 1) != 0) {
|
||||
x = t;
|
||||
n += 1;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
function bnToMPI () {
|
||||
var ba = this.toByteArray();
|
||||
var size = (ba.length-1)*8+nbits(ba[0]);
|
||||
var result = "";
|
||||
result += String.fromCharCode((size & 0xFF00) >> 8);
|
||||
result += String.fromCharCode(size & 0xFF);
|
||||
result += util.bin2str(ba);
|
||||
return result;
|
||||
}
|
||||
/* END of addition */
|
||||
|
||||
// (protected) true if probably prime (HAC 4.24, Miller-Rabin)
|
||||
function bnpMillerRabin(t) {
|
||||
var n1 = this.subtract(BigInteger.ONE);
|
||||
var k = n1.getLowestSetBit();
|
||||
if(k <= 0) return false;
|
||||
var r = n1.shiftRight(k);
|
||||
t = (t+1)>>1;
|
||||
if(t > lowprimes.length) t = lowprimes.length;
|
||||
var a = nbi();
|
||||
for(var i = 0; i < t; ++i) {
|
||||
//Pick bases at random, instead of starting at 2
|
||||
a.fromInt(lowprimes[Math.floor(Math.random()*lowprimes.length)]);
|
||||
var y = a.modPow(r,this);
|
||||
if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {
|
||||
var j = 1;
|
||||
while(j++ < k && y.compareTo(n1) != 0) {
|
||||
y = y.modPowInt(2,this);
|
||||
if(y.compareTo(BigInteger.ONE) == 0) return false;
|
||||
}
|
||||
if(y.compareTo(n1) != 0) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// protected
|
||||
BigInteger.prototype.chunkSize = bnpChunkSize;
|
||||
BigInteger.prototype.toRadix = bnpToRadix;
|
||||
BigInteger.prototype.fromRadix = bnpFromRadix;
|
||||
BigInteger.prototype.fromNumber = bnpFromNumber;
|
||||
BigInteger.prototype.bitwiseTo = bnpBitwiseTo;
|
||||
BigInteger.prototype.changeBit = bnpChangeBit;
|
||||
BigInteger.prototype.addTo = bnpAddTo;
|
||||
BigInteger.prototype.dMultiply = bnpDMultiply;
|
||||
BigInteger.prototype.dAddOffset = bnpDAddOffset;
|
||||
BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo;
|
||||
BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo;
|
||||
BigInteger.prototype.modInt = bnpModInt;
|
||||
BigInteger.prototype.millerRabin = bnpMillerRabin;
|
||||
|
||||
// public
|
||||
BigInteger.prototype.clone = bnClone;
|
||||
BigInteger.prototype.intValue = bnIntValue;
|
||||
BigInteger.prototype.byteValue = bnByteValue;
|
||||
BigInteger.prototype.shortValue = bnShortValue;
|
||||
BigInteger.prototype.signum = bnSigNum;
|
||||
BigInteger.prototype.toByteArray = bnToByteArray;
|
||||
BigInteger.prototype.equals = bnEquals;
|
||||
BigInteger.prototype.min = bnMin;
|
||||
BigInteger.prototype.max = bnMax;
|
||||
BigInteger.prototype.and = bnAnd;
|
||||
BigInteger.prototype.or = bnOr;
|
||||
BigInteger.prototype.xor = bnXor;
|
||||
BigInteger.prototype.andNot = bnAndNot;
|
||||
BigInteger.prototype.not = bnNot;
|
||||
BigInteger.prototype.shiftLeft = bnShiftLeft;
|
||||
BigInteger.prototype.shiftRight = bnShiftRight;
|
||||
BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit;
|
||||
BigInteger.prototype.bitCount = bnBitCount;
|
||||
BigInteger.prototype.testBit = bnTestBit;
|
||||
BigInteger.prototype.setBit = bnSetBit;
|
||||
BigInteger.prototype.clearBit = bnClearBit;
|
||||
BigInteger.prototype.flipBit = bnFlipBit;
|
||||
BigInteger.prototype.add = bnAdd;
|
||||
BigInteger.prototype.subtract = bnSubtract;
|
||||
BigInteger.prototype.multiply = bnMultiply;
|
||||
BigInteger.prototype.divide = bnDivide;
|
||||
BigInteger.prototype.remainder = bnRemainder;
|
||||
BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder;
|
||||
BigInteger.prototype.modPow = bnModPow;
|
||||
BigInteger.prototype.modInverse = bnModInverse;
|
||||
BigInteger.prototype.pow = bnPow;
|
||||
BigInteger.prototype.gcd = bnGCD;
|
||||
BigInteger.prototype.isProbablePrime = bnIsProbablePrime;
|
||||
BigInteger.prototype.toMPI = bnToMPI;
|
||||
|
||||
// JSBN-specific extension
|
||||
BigInteger.prototype.square = bnSquare;
|
||||
75
src/ciphers/asymmetric/rsa.js
Executable file
75
src/ciphers/asymmetric/rsa.js
Executable file
@@ -0,0 +1,75 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
// RSA implementation
|
||||
|
||||
function RSA() {
|
||||
/**
|
||||
* This function uses jsbn Big Num library to decrypt RSA
|
||||
* @param m
|
||||
* message
|
||||
* @param d
|
||||
* RSA d as BigInteger
|
||||
* @param p
|
||||
* RSA p as BigInteger
|
||||
* @param q
|
||||
* RSA q as BigInteger
|
||||
* @param u
|
||||
* RSA u as BigInteger
|
||||
* @return
|
||||
*/
|
||||
function decrypt(m, d, p, q, u) {
|
||||
var xp = m.mod(p).modPow(d.mod(p.subtract(BigInteger.ONE)), p);
|
||||
var xq = m.mod(q).modPow(d.mod(q.subtract(BigInteger.ONE)), q);
|
||||
util.print_debug("rsa.js decrypt\nxpn:"+util.hexstrdump(xp.toMPI())+"\nxqn:"+util.hexstrdump(xq.toMPI()));
|
||||
|
||||
var t = xq.subtract(xp);
|
||||
if (t[0] == 0) {
|
||||
t = xp.subtract(xq);
|
||||
t = t.multiply(u).mod(q);
|
||||
t = q.subtract(t);
|
||||
} else {
|
||||
t = t.multiply(u).mod(q);
|
||||
}
|
||||
return t.multiply(p).add(xp);
|
||||
}
|
||||
|
||||
/**
|
||||
* encrypt message
|
||||
* @param m message as BigInteger
|
||||
* @param e public MPI part as BigInteger
|
||||
* @param n public MPI part as BigInteger
|
||||
* @return BigInteger
|
||||
*/
|
||||
function encrypt(m,e,n) {
|
||||
return m.modPowInt(e, n);
|
||||
}
|
||||
|
||||
/* Sign and Verify */
|
||||
function sign(m,d,n) {
|
||||
return m.modPow(d, n);
|
||||
}
|
||||
|
||||
function verify(x,e,n) {
|
||||
return x.modPowInt(e, n);
|
||||
}
|
||||
|
||||
this.encrypt = encrypt;
|
||||
this.decrypt = decrypt;
|
||||
this.verify = verify;
|
||||
this.sign = sign;
|
||||
}
|
||||
374
src/ciphers/hash/md5.js
Executable file
374
src/ciphers/hash/md5.js
Executable file
@@ -0,0 +1,374 @@
|
||||
/*
|
||||
* md5.jvs 1.0b 27/06/96
|
||||
*
|
||||
* Javascript implementation of the RSA Data Security, Inc. MD5
|
||||
* Message-Digest Algorithm.
|
||||
*
|
||||
* Copyright (c) 1996 Henri Torgemane. All Rights Reserved.
|
||||
*
|
||||
* Modified by Recurity Labs GmbH (http://www.recurity-labs.com)
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software
|
||||
* and its documentation for any purposes and without
|
||||
* fee is hereby granted provided that this copyright notice
|
||||
* appears in all copies.
|
||||
*
|
||||
* Of course, this soft is provided "as is" without express or implied
|
||||
* warranty of any kind.
|
||||
*/
|
||||
|
||||
|
||||
function MD5(entree) {
|
||||
|
||||
function array(n) {
|
||||
for(i=0;i<n;i++) this[i]=0;
|
||||
this.length=n;
|
||||
}
|
||||
|
||||
/* Some basic logical functions had to be rewritten because of a bug in
|
||||
* Javascript.. Just try to compute 0xffffffff >> 4 with it..
|
||||
* Of course, these functions are slower than the original would be, but
|
||||
* at least, they work!
|
||||
*/
|
||||
|
||||
function integer(n) { return n%(0xffffffff+1); }
|
||||
|
||||
function shr(a,b) {
|
||||
a=integer(a);
|
||||
b=integer(b);
|
||||
if (a-0x80000000>=0) {
|
||||
a=a%0x80000000;
|
||||
a>>=b;
|
||||
a+=0x40000000>>(b-1);
|
||||
} else
|
||||
a>>=b;
|
||||
return a;
|
||||
}
|
||||
|
||||
function shl1(a) {
|
||||
a=a%0x80000000;
|
||||
if (a&0x40000000==0x40000000)
|
||||
{
|
||||
a-=0x40000000;
|
||||
a*=2;
|
||||
a+=0x80000000;
|
||||
} else
|
||||
a*=2;
|
||||
return a;
|
||||
}
|
||||
|
||||
function shl(a,b) {
|
||||
a=integer(a);
|
||||
b=integer(b);
|
||||
for (var i=0;i<b;i++) a=shl1(a);
|
||||
return a;
|
||||
}
|
||||
|
||||
function and(a,b) {
|
||||
a=integer(a);
|
||||
b=integer(b);
|
||||
var t1=(a-0x80000000);
|
||||
var t2=(b-0x80000000);
|
||||
if (t1>=0)
|
||||
if (t2>=0)
|
||||
return ((t1&t2)+0x80000000);
|
||||
else
|
||||
return (t1&b);
|
||||
else
|
||||
if (t2>=0)
|
||||
return (a&t2);
|
||||
else
|
||||
return (a&b);
|
||||
}
|
||||
|
||||
function or(a,b) {
|
||||
a=integer(a);
|
||||
b=integer(b);
|
||||
var t1=(a-0x80000000);
|
||||
var t2=(b-0x80000000);
|
||||
if (t1>=0)
|
||||
if (t2>=0)
|
||||
return ((t1|t2)+0x80000000);
|
||||
else
|
||||
return ((t1|b)+0x80000000);
|
||||
else
|
||||
if (t2>=0)
|
||||
return ((a|t2)+0x80000000);
|
||||
else
|
||||
return (a|b);
|
||||
}
|
||||
|
||||
function xor(a,b) {
|
||||
a=integer(a);
|
||||
b=integer(b);
|
||||
var t1=(a-0x80000000);
|
||||
var t2=(b-0x80000000);
|
||||
if (t1>=0)
|
||||
if (t2>=0)
|
||||
return (t1^t2);
|
||||
else
|
||||
return ((t1^b)+0x80000000);
|
||||
else
|
||||
if (t2>=0)
|
||||
return ((a^t2)+0x80000000);
|
||||
else
|
||||
return (a^b);
|
||||
}
|
||||
|
||||
function not(a) {
|
||||
a=integer(a);
|
||||
return (0xffffffff-a);
|
||||
}
|
||||
|
||||
/* Here begin the real algorithm */
|
||||
|
||||
var state = new array(4);
|
||||
var count = new array(2);
|
||||
count[0] = 0;
|
||||
count[1] = 0;
|
||||
var buffer = new array(64);
|
||||
var transformBuffer = new array(16);
|
||||
var digestBits = new array(16);
|
||||
|
||||
var S11 = 7;
|
||||
var S12 = 12;
|
||||
var S13 = 17;
|
||||
var S14 = 22;
|
||||
var S21 = 5;
|
||||
var S22 = 9;
|
||||
var S23 = 14;
|
||||
var S24 = 20;
|
||||
var S31 = 4;
|
||||
var S32 = 11;
|
||||
var S33 = 16;
|
||||
var S34 = 23;
|
||||
var S41 = 6;
|
||||
var S42 = 10;
|
||||
var S43 = 15;
|
||||
var S44 = 21;
|
||||
|
||||
function F(x,y,z) {
|
||||
return or(and(x,y),and(not(x),z));
|
||||
}
|
||||
|
||||
function G(x,y,z) {
|
||||
return or(and(x,z),and(y,not(z)));
|
||||
}
|
||||
|
||||
function H(x,y,z) {
|
||||
return xor(xor(x,y),z);
|
||||
}
|
||||
|
||||
function I(x,y,z) {
|
||||
return xor(y ,or(x , not(z)));
|
||||
}
|
||||
|
||||
function rotateLeft(a,n) {
|
||||
return or(shl(a, n),(shr(a,(32 - n))));
|
||||
}
|
||||
|
||||
function FF(a,b,c,d,x,s,ac) {
|
||||
a = a+F(b, c, d) + x + ac;
|
||||
a = rotateLeft(a, s);
|
||||
a = a+b;
|
||||
return a;
|
||||
}
|
||||
|
||||
function GG(a,b,c,d,x,s,ac) {
|
||||
a = a+G(b, c, d) +x + ac;
|
||||
a = rotateLeft(a, s);
|
||||
a = a+b;
|
||||
return a;
|
||||
}
|
||||
|
||||
function HH(a,b,c,d,x,s,ac) {
|
||||
a = a+H(b, c, d) + x + ac;
|
||||
a = rotateLeft(a, s);
|
||||
a = a+b;
|
||||
return a;
|
||||
}
|
||||
|
||||
function II(a,b,c,d,x,s,ac) {
|
||||
a = a+I(b, c, d) + x + ac;
|
||||
a = rotateLeft(a, s);
|
||||
a = a+b;
|
||||
return a;
|
||||
}
|
||||
|
||||
function transform(buf,offset) {
|
||||
var a=0, b=0, c=0, d=0;
|
||||
var x = transformBuffer;
|
||||
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
x[i] = and(buf[i*4+offset],0xff);
|
||||
for (j = 1; j < 4; j++) {
|
||||
x[i]+=shl(and(buf[i*4+j+offset] ,0xff), j * 8);
|
||||
}
|
||||
}
|
||||
|
||||
/* Round 1 */
|
||||
a = FF ( a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
|
||||
d = FF ( d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
|
||||
c = FF ( c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
|
||||
b = FF ( b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
|
||||
a = FF ( a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
|
||||
d = FF ( d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
|
||||
c = FF ( c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
|
||||
b = FF ( b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
|
||||
a = FF ( a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
|
||||
d = FF ( d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
|
||||
c = FF ( c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
|
||||
b = FF ( b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
|
||||
a = FF ( a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
|
||||
d = FF ( d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
|
||||
c = FF ( c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
|
||||
b = FF ( b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
|
||||
|
||||
/* Round 2 */
|
||||
a = GG ( a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
|
||||
d = GG ( d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
|
||||
c = GG ( c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
|
||||
b = GG ( b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
|
||||
a = GG ( a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
|
||||
d = GG ( d, a, b, c, x[10], S22, 0x2441453); /* 22 */
|
||||
c = GG ( c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
|
||||
b = GG ( b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
|
||||
a = GG ( a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
|
||||
d = GG ( d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
|
||||
c = GG ( c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
|
||||
b = GG ( b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
|
||||
a = GG ( a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
|
||||
d = GG ( d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
|
||||
c = GG ( c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
|
||||
b = GG ( b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
|
||||
|
||||
/* Round 3 */
|
||||
a = HH ( a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
|
||||
d = HH ( d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
|
||||
c = HH ( c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
|
||||
b = HH ( b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
|
||||
a = HH ( a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
|
||||
d = HH ( d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
|
||||
c = HH ( c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
|
||||
b = HH ( b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
|
||||
a = HH ( a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
|
||||
d = HH ( d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
|
||||
c = HH ( c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
|
||||
b = HH ( b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
|
||||
a = HH ( a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
|
||||
d = HH ( d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
|
||||
c = HH ( c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
|
||||
b = HH ( b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
|
||||
|
||||
/* Round 4 */
|
||||
a = II ( a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
|
||||
d = II ( d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
|
||||
c = II ( c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
|
||||
b = II ( b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
|
||||
a = II ( a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
|
||||
d = II ( d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
|
||||
c = II ( c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
|
||||
b = II ( b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
|
||||
a = II ( a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
|
||||
d = II ( d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
|
||||
c = II ( c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
|
||||
b = II ( b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
|
||||
a = II ( a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
|
||||
d = II ( d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
|
||||
c = II ( c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
|
||||
b = II ( b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
|
||||
|
||||
state[0] +=a;
|
||||
state[1] +=b;
|
||||
state[2] +=c;
|
||||
state[3] +=d;
|
||||
|
||||
}
|
||||
|
||||
function init() {
|
||||
count[0]=count[1] = 0;
|
||||
state[0] = 0x67452301;
|
||||
state[1] = 0xefcdab89;
|
||||
state[2] = 0x98badcfe;
|
||||
state[3] = 0x10325476;
|
||||
for (i = 0; i < digestBits.length; i++)
|
||||
digestBits[i] = 0;
|
||||
}
|
||||
|
||||
function update(b) {
|
||||
var index,i;
|
||||
|
||||
index = and(shr(count[0],3) , 0x3f);
|
||||
if (count[0]<0xffffffff-7)
|
||||
count[0] += 8;
|
||||
else {
|
||||
count[1]++;
|
||||
count[0]-=0xffffffff+1;
|
||||
count[0]+=8;
|
||||
}
|
||||
buffer[index] = and(b,0xff);
|
||||
if (index >= 63) {
|
||||
transform(buffer, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function finish() {
|
||||
var bits = new array(8);
|
||||
var padding;
|
||||
var i=0, index=0, padLen=0;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
bits[i] = and(shr(count[0],(i * 8)), 0xff);
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
bits[i+4]=and(shr(count[1],(i * 8)), 0xff);
|
||||
}
|
||||
index = and(shr(count[0], 3) ,0x3f);
|
||||
padLen = (index < 56) ? (56 - index) : (120 - index);
|
||||
padding = new array(64);
|
||||
padding[0] = 0x80;
|
||||
for (i=0;i<padLen;i++)
|
||||
update(padding[i]);
|
||||
for (i=0;i<8;i++)
|
||||
update(bits[i]);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
digestBits[i*4+j] = and(shr(state[i], (j * 8)) , 0xff);
|
||||
}
|
||||
}
|
||||
}
|
||||
function binb2str(bin) {
|
||||
var str = "";
|
||||
var mask = (1 << 8) - 1;
|
||||
for(var i = 0; i < bin.length * 32; i += 8)
|
||||
str += String.fromCharCode((bin[i>>5] >>> (32 - 8 - i%32)) & mask);
|
||||
return str;
|
||||
}
|
||||
|
||||
// modified by Recurity Labs GmbH
|
||||
var l,s,k,ka,kb,kc,kd;
|
||||
|
||||
init();
|
||||
for (k=0;k<entree.length;k++) {
|
||||
l=entree.charCodeAt(k);
|
||||
update(l);
|
||||
}
|
||||
finish();
|
||||
ka=kb=kc=kd=0;
|
||||
for (i=0;i<4;i++) ka+=shl(digestBits[15-i], (i*8));
|
||||
for (i=4;i<8;i++) kb+=shl(digestBits[15-i], ((i-4)*8));
|
||||
for (i=8;i<12;i++) kc+=shl(digestBits[15-i], ((i-8)*8));
|
||||
for (i=12;i<16;i++) kd+=shl(digestBits[15-i], ((i-12)*8));
|
||||
s= new Array();
|
||||
s[0] = kd;
|
||||
s[1] = kc;
|
||||
s[2] = kb;
|
||||
s[3] = ka;
|
||||
return binb2str(s);
|
||||
}
|
||||
293
src/ciphers/hash/ripe-md.js
Executable file
293
src/ciphers/hash/ripe-md.js
Executable file
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* CryptoMX Tools
|
||||
* Copyright (C) 2004 - 2006 Derek Buitenhuis
|
||||
*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* Modified by Recurity Labs GmbH
|
||||
*/
|
||||
|
||||
var RMDsize = 160;
|
||||
var X = new Array();
|
||||
|
||||
function ROL(x, n)
|
||||
{
|
||||
return new Number ((x << n) | ( x >>> (32 - n)));
|
||||
}
|
||||
|
||||
function F(x, y, z)
|
||||
{
|
||||
return new Number(x ^ y ^ z);
|
||||
}
|
||||
|
||||
function G(x, y, z)
|
||||
{
|
||||
return new Number((x & y) | (~x & z));
|
||||
}
|
||||
|
||||
function H(x, y, z)
|
||||
{
|
||||
return new Number((x | ~y) ^ z);
|
||||
}
|
||||
|
||||
function I(x, y, z)
|
||||
{
|
||||
return new Number((x & z) | (y & ~z));
|
||||
}
|
||||
|
||||
function J(x, y, z)
|
||||
{
|
||||
return new Number(x ^ (y | ~z));
|
||||
}
|
||||
|
||||
function mixOneRound(a, b, c, d, e, x, s, roundNumber)
|
||||
{
|
||||
switch (roundNumber)
|
||||
{
|
||||
case 0 : a += F(b, c, d) + x + 0x00000000; break;
|
||||
case 1 : a += G(b, c, d) + x + 0x5a827999; break;
|
||||
case 2 : a += H(b, c, d) + x + 0x6ed9eba1; break;
|
||||
case 3 : a += I(b, c, d) + x + 0x8f1bbcdc; break;
|
||||
case 4 : a += J(b, c, d) + x + 0xa953fd4e; break;
|
||||
case 5 : a += J(b, c, d) + x + 0x50a28be6; break;
|
||||
case 6 : a += I(b, c, d) + x + 0x5c4dd124; break;
|
||||
case 7 : a += H(b, c, d) + x + 0x6d703ef3; break;
|
||||
case 8 : a += G(b, c, d) + x + 0x7a6d76e9; break;
|
||||
case 9 : a += F(b, c, d) + x + 0x00000000; break;
|
||||
|
||||
default : document.write("Bogus round number"); break;
|
||||
}
|
||||
|
||||
a = ROL(a, s) + e;
|
||||
c = ROL(c, 10);
|
||||
|
||||
a &= 0xffffffff;
|
||||
b &= 0xffffffff;
|
||||
c &= 0xffffffff;
|
||||
d &= 0xffffffff;
|
||||
e &= 0xffffffff;
|
||||
|
||||
var retBlock = new Array();
|
||||
retBlock[0] = a;
|
||||
retBlock[1] = b;
|
||||
retBlock[2] = c;
|
||||
retBlock[3] = d;
|
||||
retBlock[4] = e;
|
||||
retBlock[5] = x;
|
||||
retBlock[6] = s;
|
||||
|
||||
return retBlock;
|
||||
}
|
||||
|
||||
function MDinit (MDbuf)
|
||||
{
|
||||
MDbuf[0] = 0x67452301;
|
||||
MDbuf[1] = 0xefcdab89;
|
||||
MDbuf[2] = 0x98badcfe;
|
||||
MDbuf[3] = 0x10325476;
|
||||
MDbuf[4] = 0xc3d2e1f0;
|
||||
}
|
||||
|
||||
var ROLs = [
|
||||
[11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8],
|
||||
[ 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12],
|
||||
[11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5],
|
||||
[11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12],
|
||||
[ 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6],
|
||||
[ 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6],
|
||||
[ 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11],
|
||||
[ 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5],
|
||||
[15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8],
|
||||
[ 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11]
|
||||
];
|
||||
|
||||
var indexes = [
|
||||
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
|
||||
[ 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8],
|
||||
[ 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12],
|
||||
[ 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2],
|
||||
[ 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13],
|
||||
[ 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12],
|
||||
[ 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2],
|
||||
[15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13],
|
||||
[ 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14],
|
||||
[12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11]
|
||||
];
|
||||
|
||||
function compress (MDbuf, X)
|
||||
{
|
||||
blockA = new Array();
|
||||
blockB = new Array();
|
||||
|
||||
var retBlock;
|
||||
|
||||
for (var i=0; i < 5; i++)
|
||||
{
|
||||
blockA[i] = new Number(MDbuf[i]);
|
||||
blockB[i] = new Number(MDbuf[i]);
|
||||
}
|
||||
|
||||
var step = 0;
|
||||
for (var j = 0; j < 5; j++)
|
||||
{
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
retBlock = mixOneRound(
|
||||
blockA[(step+0) % 5],
|
||||
blockA[(step+1) % 5],
|
||||
blockA[(step+2) % 5],
|
||||
blockA[(step+3) % 5],
|
||||
blockA[(step+4) % 5],
|
||||
X[indexes[j][i]],
|
||||
ROLs[j][i],
|
||||
j
|
||||
);
|
||||
|
||||
blockA[(step+0) % 5] = retBlock[0];
|
||||
blockA[(step+1) % 5] = retBlock[1];
|
||||
blockA[(step+2) % 5] = retBlock[2];
|
||||
blockA[(step+3) % 5] = retBlock[3];
|
||||
blockA[(step+4) % 5] = retBlock[4];
|
||||
|
||||
step += 4;
|
||||
}
|
||||
}
|
||||
|
||||
step = 0;
|
||||
for (var j = 5; j < 10; j++)
|
||||
{
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
retBlock = mixOneRound(
|
||||
blockB[(step+0) % 5],
|
||||
blockB[(step+1) % 5],
|
||||
blockB[(step+2) % 5],
|
||||
blockB[(step+3) % 5],
|
||||
blockB[(step+4) % 5],
|
||||
X[indexes[j][i]],
|
||||
ROLs[j][i],
|
||||
j
|
||||
);
|
||||
|
||||
blockB[(step+0) % 5] = retBlock[0];
|
||||
blockB[(step+1) % 5] = retBlock[1];
|
||||
blockB[(step+2) % 5] = retBlock[2];
|
||||
blockB[(step+3) % 5] = retBlock[3];
|
||||
blockB[(step+4) % 5] = retBlock[4];
|
||||
|
||||
step += 4;
|
||||
}
|
||||
}
|
||||
|
||||
blockB[3] += blockA[2] + MDbuf[1];
|
||||
MDbuf[1] = MDbuf[2] + blockA[3] + blockB[4];
|
||||
MDbuf[2] = MDbuf[3] + blockA[4] + blockB[0];
|
||||
MDbuf[3] = MDbuf[4] + blockA[0] + blockB[1];
|
||||
MDbuf[4] = MDbuf[0] + blockA[1] + blockB[2];
|
||||
MDbuf[0] = blockB[3];
|
||||
}
|
||||
|
||||
function zeroX(X)
|
||||
{
|
||||
for (var i = 0; i < 16; i++) { X[i] = 0; }
|
||||
}
|
||||
|
||||
function MDfinish (MDbuf, strptr, lswlen, mswlen)
|
||||
{
|
||||
var X = new Array(16);
|
||||
zeroX(X);
|
||||
|
||||
var j = 0;
|
||||
for (var i=0; i < (lswlen & 63); i++)
|
||||
{
|
||||
X[i >>> 2] ^= (strptr.charCodeAt(j++) & 255) << (8 * (i & 3));
|
||||
}
|
||||
|
||||
X[(lswlen >>> 2) & 15] ^= 1 << (8 * (lswlen & 3) + 7);
|
||||
|
||||
if ((lswlen & 63) > 55)
|
||||
{
|
||||
compress(MDbuf, X);
|
||||
var X = new Array(16);
|
||||
zeroX(X);
|
||||
}
|
||||
|
||||
X[14] = lswlen << 3;
|
||||
X[15] = (lswlen >>> 29) | (mswlen << 3);
|
||||
|
||||
compress(MDbuf, X);
|
||||
}
|
||||
|
||||
function BYTES_TO_DWORD(fourChars)
|
||||
{
|
||||
var tmp = (fourChars.charCodeAt(3) & 255) << 24;
|
||||
tmp |= (fourChars.charCodeAt(2) & 255) << 16;
|
||||
tmp |= (fourChars.charCodeAt(1) & 255) << 8;
|
||||
tmp |= (fourChars.charCodeAt(0) & 255);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
function RMD(message)
|
||||
{
|
||||
var MDbuf = new Array(RMDsize / 32);
|
||||
var hashcode = new Array(RMDsize / 8);
|
||||
var length;
|
||||
var nbytes;
|
||||
|
||||
MDinit(MDbuf);
|
||||
length = message.length;
|
||||
|
||||
var X = new Array(16);
|
||||
zeroX(X);
|
||||
|
||||
var j=0;
|
||||
for (var nbytes=length; nbytes > 63; nbytes -= 64)
|
||||
{
|
||||
for (var i=0; i < 16; i++)
|
||||
{
|
||||
X[i] = BYTES_TO_DWORD(message.substr(j, 4));
|
||||
j += 4;
|
||||
}
|
||||
compress(MDbuf, X);
|
||||
}
|
||||
|
||||
MDfinish(MDbuf, message.substr(j), length, 0);
|
||||
|
||||
for (var i=0; i < RMDsize / 8; i += 4)
|
||||
{
|
||||
hashcode[i] = MDbuf[i >>> 2] & 255;
|
||||
hashcode[i+1] = (MDbuf[i >>> 2] >>> 8) & 255;
|
||||
hashcode[i+2] = (MDbuf[i >>> 2] >>> 16) & 255;
|
||||
hashcode[i+3] = (MDbuf[i >>> 2] >>> 24) & 255;
|
||||
}
|
||||
|
||||
return hashcode;
|
||||
}
|
||||
|
||||
|
||||
function RMDstring(message)
|
||||
{
|
||||
var hashcode = RMD(message);
|
||||
var retString = "";
|
||||
|
||||
for (var i=0; i < RMDsize/8; i++)
|
||||
{
|
||||
retString += String.fromCharCode(hashcode[i]);
|
||||
}
|
||||
|
||||
return retString;
|
||||
}
|
||||
1221
src/ciphers/hash/sha.js
Executable file
1221
src/ciphers/hash/sha.js
Executable file
File diff suppressed because it is too large
Load Diff
275
src/ciphers/openpgp.cfb.js
Executable file
275
src/ciphers/openpgp.cfb.js
Executable file
@@ -0,0 +1,275 @@
|
||||
// Modified by Recurity Labs GmbH
|
||||
|
||||
// modified version of http://www.hanewin.net/encrypt/PGdecode.js:
|
||||
|
||||
/* OpenPGP encryption using RSA/AES
|
||||
* Copyright 2005-2006 Herbert Hanewinkel, www.haneWIN.de
|
||||
* version 2.0, check www.haneWIN.de for the latest version
|
||||
|
||||
* This software is provided as-is, without express or implied warranty.
|
||||
* Permission to use, copy, modify, distribute or sell this software, with or
|
||||
* without fee, for any purpose and by any individual or organization, is hereby
|
||||
* granted, provided that the above copyright notice and this paragraph appear
|
||||
* in all copies. Distribution as a part of an application or binary must
|
||||
* include the above copyright notice in the documentation and/or other
|
||||
* materials provided with the application or distribution.
|
||||
*/
|
||||
|
||||
// --------------------------------------
|
||||
/**
|
||||
* This function encrypts a given with the specified prefixrandom
|
||||
* using the specified blockcipher to encrypt a message
|
||||
* @param prefixrandom random bytes of block_size length provided
|
||||
* as a string to be used in prefixing the data
|
||||
* @param blockcipherfn the algorithm encrypt function to encrypt
|
||||
* data in one block_size encryption. The function must be
|
||||
* specified as blockcipherfn([integer_array(integers 0..255)]
|
||||
* block,[integer_array(integers 0..255)] key) returning an
|
||||
* array of bytes (integers 0..255)
|
||||
* @param block_size the block size in bytes of the algorithm used
|
||||
* @param plaintext data to be encrypted provided as a string
|
||||
* @param key key to be used to encrypt the data as
|
||||
* integer_array(integers 0..255)]. This will be passed to the
|
||||
* blockcipherfn
|
||||
* @param resync a boolean value specifying if a resync of the
|
||||
* IV should be used or not. The encrypteddatapacket uses the
|
||||
* "old" style with a resync. Encryption within an
|
||||
* encryptedintegrityprotecteddata packet is not resyncing the IV.
|
||||
* @return a string with the encrypted data
|
||||
*/
|
||||
function openpgp_cfb_encrypt(prefixrandom, blockcipherencryptfn, plaintext, block_size, key, resync) {
|
||||
var FR = new Array(block_size);
|
||||
var FRE = new Array(block_size);
|
||||
|
||||
prefixrandom = prefixrandom + prefixrandom.charAt(block_size-2) +prefixrandom.charAt(block_size-1);
|
||||
util.print_debug("prefixrandom:"+util.hexstrdump(prefixrandom));
|
||||
var ciphertext = "";
|
||||
// 1. The feedback register (FR) is set to the IV, which is all zeros.
|
||||
for (var i = 0; i < block_size; i++) FR[i] = 0;
|
||||
|
||||
// 2. FR is encrypted to produce FRE (FR Encrypted). This is the
|
||||
// encryption of an all-zero value.
|
||||
FRE = blockcipherencryptfn(FR, key);
|
||||
// 3. FRE is xored with the first BS octets of random data prefixed to
|
||||
// the plaintext to produce C[1] through C[BS], the first BS octets
|
||||
// of ciphertext.
|
||||
for (var i = 0; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ prefixrandom.charCodeAt(i));
|
||||
|
||||
// 4. FR is loaded with C[1] through C[BS].
|
||||
for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i);
|
||||
|
||||
// 5. FR is encrypted to produce FRE, the encryption of the first BS
|
||||
// octets of ciphertext.
|
||||
FRE = blockcipherencryptfn(FR, key);
|
||||
|
||||
// 6. The left two octets of FRE get xored with the next two octets of
|
||||
// data that were prefixed to the plaintext. This produces C[BS+1]
|
||||
// and C[BS+2], the next two octets of ciphertext.
|
||||
ciphertext += String.fromCharCode(FRE[0] ^ prefixrandom.charCodeAt(block_size));
|
||||
ciphertext += String.fromCharCode(FRE[1] ^ prefixrandom.charCodeAt(block_size+1));
|
||||
|
||||
if (resync) {
|
||||
// 7. (The resync step) FR is loaded with C3-C10.
|
||||
for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i+2);
|
||||
} else {
|
||||
for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i);
|
||||
}
|
||||
// 8. FR is encrypted to produce FRE.
|
||||
FRE = blockcipherencryptfn(FR, key);
|
||||
|
||||
if (resync) {
|
||||
// 9. FRE is xored with the first 8 octets of the given plaintext, now
|
||||
// that we have finished encrypting the 10 octets of prefixed data.
|
||||
// This produces C11-C18, the next 8 octets of ciphertext.
|
||||
for (var i = 0; i < block_size; i++)
|
||||
ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(i));
|
||||
for(n=block_size+2; n < plaintext.length; n+=block_size) {
|
||||
// 10. FR is loaded with C11-C18
|
||||
for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(n+i);
|
||||
|
||||
// 11. FR is encrypted to produce FRE.
|
||||
FRE = blockcipherencryptfn(FR, key);
|
||||
|
||||
// 12. FRE is xored with the next 8 octets of plaintext, to produce the
|
||||
// next 8 octets of ciphertext. These are loaded into FR and the
|
||||
// process is repeated until the plaintext is used up.
|
||||
for (var i = 0; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt((n-2)+i));
|
||||
}
|
||||
}
|
||||
else {
|
||||
plaintext = " "+plaintext;
|
||||
// 9. FRE is xored with the first 8 octets of the given plaintext, now
|
||||
// that we have finished encrypting the 10 octets of prefixed data.
|
||||
// This produces C11-C18, the next 8 octets of ciphertext.
|
||||
for (var i = 2; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(i));
|
||||
|
||||
for(n=block_size; n<plaintext.length; n+=block_size) {
|
||||
// 10. FR is loaded with C11-C18
|
||||
for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(n+i);
|
||||
|
||||
// 11. FR is encrypted to produce FRE.
|
||||
FRE = blockcipherencryptfn(FR, key);
|
||||
|
||||
// 12. FRE is xored with the next 8 octets of plaintext, to produce the
|
||||
// next 8 octets of ciphertext. These are loaded into FR and the
|
||||
// process is repeated until the plaintext is used up.
|
||||
for (var i = 0; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(n+i));
|
||||
}
|
||||
|
||||
}
|
||||
return ciphertext;
|
||||
}
|
||||
|
||||
/**
|
||||
* decrypts the prefixed data for the Modification Detection Code (MDC) computation
|
||||
* @param blockcipherencryptfn cipher function to use
|
||||
* @param block_size blocksize of the algorithm
|
||||
* @param key the key for encryption
|
||||
* @param ciphertext the encrypted data
|
||||
* @return plaintext data of D(ciphertext) with blocksize length +2
|
||||
*/
|
||||
function openpgp_cfb_mdc(blockcipherencryptfn, block_size, key, ciphertext) {
|
||||
var iblock = new Array(block_size);
|
||||
var ablock = new Array(block_size);
|
||||
var i;
|
||||
|
||||
// initialisation vector
|
||||
for(i=0; i < block_size; i++) iblock[i] = 0;
|
||||
|
||||
iblock = blockcipherencryptfn(iblock, key);
|
||||
for(i = 0; i < block_size; i++)
|
||||
{
|
||||
ablock[i] = ciphertext.charCodeAt(i);
|
||||
iblock[i] ^= ablock[i];
|
||||
}
|
||||
|
||||
ablock = blockcipherencryptfn(ablock, key);
|
||||
|
||||
return util.bin2str(iblock)+
|
||||
String.fromCharCode(ablock[0]^ciphertext.charCodeAt(block_size))+
|
||||
String.fromCharCode(ablock[1]^ciphertext.charCodeAt(block_size+1));
|
||||
}
|
||||
/**
|
||||
* This function decrypts a given plaintext using the specified
|
||||
* blockcipher to decrypt a message
|
||||
* @param blockcipherfn the algorithm _encrypt_ function to encrypt
|
||||
* data in one block_size encryption. The function must be
|
||||
* specified as blockcipherfn([integer_array(integers 0..255)]
|
||||
* block,[integer_array(integers 0..255)] key) returning an
|
||||
* array of bytes (integers 0..255)
|
||||
* @param block_size the block size in bytes of the algorithm used
|
||||
* @param plaintext ciphertext to be decrypted provided as a string
|
||||
* @param key key to be used to decrypt the ciphertext as
|
||||
* integer_array(integers 0..255)]. This will be passed to the
|
||||
* blockcipherfn
|
||||
* @param resync a boolean value specifying if a resync of the
|
||||
* IV should be used or not. The encrypteddatapacket uses the
|
||||
* "old" style with a resync. Decryption within an
|
||||
* encryptedintegrityprotecteddata packet is not resyncing the IV.
|
||||
* @return a string with the plaintext data
|
||||
*/
|
||||
|
||||
function openpgp_cfb_decrypt(blockcipherencryptfn, block_size, key, ciphertext, resync)
|
||||
{
|
||||
util.print_debug("resync:"+resync);
|
||||
var iblock = new Array(block_size);
|
||||
var ablock = new Array(block_size);
|
||||
var i, n, text = '';
|
||||
|
||||
// initialisation vector
|
||||
for(i=0; i < block_size; i++) iblock[i] = 0;
|
||||
|
||||
iblock = blockcipherencryptfn(iblock, key);
|
||||
for(i = 0; i < block_size; i++)
|
||||
{
|
||||
ablock[i] = ciphertext.charCodeAt(i);
|
||||
iblock[i] ^= ablock[i];
|
||||
}
|
||||
|
||||
ablock = blockcipherencryptfn(ablock, key);
|
||||
|
||||
util.print_debug("openpgp_cfb_decrypt:\niblock:"+util.hexidump(iblock)+"\nablock:"+util.hexidump(ablock)+"\n");
|
||||
util.print_debug((ablock[0]^ciphertext.charCodeAt(block_size)).toString(16)+(ablock[1]^ciphertext.charCodeAt(block_size+1)).toString(16));
|
||||
|
||||
// test check octets
|
||||
if(iblock[block_size-2]!=(ablock[0]^ciphertext.charCodeAt(block_size))
|
||||
|| iblock[block_size-1]!=(ablock[1]^ciphertext.charCodeAt(block_size+1)))
|
||||
{
|
||||
util.print_eror("error duding decryption. Symmectric encrypted data not valid.");
|
||||
return text;
|
||||
}
|
||||
|
||||
/* RFC4880: Tag 18 and Resync:
|
||||
* [...] Unlike the Symmetrically Encrypted Data Packet, no
|
||||
* special CFB resynchronization is done after encrypting this prefix
|
||||
* data. See "OpenPGP CFB Mode" below for more details.
|
||||
|
||||
*/
|
||||
|
||||
if (resync) {
|
||||
for(i=0; i<block_size; i++) iblock[i] = ciphertext.charCodeAt(i+2);
|
||||
for(n=block_size+2; n<ciphertext.length; n+=block_size)
|
||||
{
|
||||
ablock = blockcipherencryptfn(iblock, key);
|
||||
|
||||
for(i = 0; i<block_size && i+n < ciphertext.length; i++)
|
||||
{
|
||||
iblock[i] = ciphertext.charCodeAt(n+i);
|
||||
text += String.fromCharCode(ablock[i]^iblock[i]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(i=0; i<block_size; i++) iblock[i] = ciphertext.charCodeAt(i);
|
||||
for(n=block_size; n<ciphertext.length; n+=block_size)
|
||||
{
|
||||
ablock = blockcipherencryptfn(iblock, key);
|
||||
for(i = 0; i<block_size && i+n < ciphertext.length; i++)
|
||||
{
|
||||
iblock[i] = ciphertext.charCodeAt(n+i);
|
||||
text += String.fromCharCode(ablock[i]^iblock[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
function normal_cfb_encrypt(blockcipherencryptfn, block_size, key, plaintext, iv) {
|
||||
var blocki ="";
|
||||
var blockc = "";
|
||||
var pos = 0;
|
||||
var cyphertext = "";
|
||||
blocki[i] = iv.substring(0,block_size);
|
||||
while (plaintext.length > block_size*pos) {
|
||||
blocka = plaintext.substring((pos*block_size),(pos*block_size)+block_size);
|
||||
var encblock = blockcipherencryptfn(blocki, key);
|
||||
for (var i=0; i < blocka.size; i++)
|
||||
blocki[i] = blocka ^ enblock();
|
||||
cyphertext += blocki;
|
||||
pos++;
|
||||
}
|
||||
return cyphertext;
|
||||
}
|
||||
|
||||
function normal_cfb_decrypt(blockcipherencryptfn, block_size, key, ciphertext, iv) {
|
||||
var blockp ="";
|
||||
var pos = 0;
|
||||
var plaintext = "";
|
||||
var offset = 0;
|
||||
if (iv == null)
|
||||
for (var i = 0; i < block_size; i++) blockp += String.fromCharCode(0);
|
||||
else
|
||||
blockp = iv.substring(0,block_size);
|
||||
while (ciphertext.length > (block_size*pos)) {
|
||||
var decblock = blockcipherencryptfn(blockp, key);
|
||||
blockp = ciphertext.substring((pos*(block_size))+offset,(pos*(block_size))+(block_size)+offset);
|
||||
for (var i=0; i < blockp.length; i++) {
|
||||
plaintext += String.fromCharCode(blockp.charCodeAt(i) ^ decblock[i]);
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
return plaintext;
|
||||
}
|
||||
458
src/ciphers/openpgp.crypto.js
Executable file
458
src/ciphers/openpgp.crypto.js
Executable file
@@ -0,0 +1,458 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
// The GPG4Browsers crypto interface
|
||||
|
||||
/**
|
||||
* Encrypts data using the specified public key multiprecision integers
|
||||
* and the specified algorithm.
|
||||
* @param algo [Integer] Algorithm to be used (See RFC4880 9.1)
|
||||
* @param publicMPIs [Array[openpgp_type_mpi]] algorithm dependent multiprecision integers
|
||||
* @param data [openpgp_type_mpi] data to be encrypted as MPI
|
||||
* @return [Object] if RSA an openpgp_type_mpi; if elgamal encryption an array of two
|
||||
* openpgp_type_mpi is returned; otherwise null
|
||||
*/
|
||||
function openpgp_crypto_asymetricEncrypt(algo, publicMPIs, data) {
|
||||
switch(algo) {
|
||||
case 1: // RSA (Encrypt or Sign) [HAC]
|
||||
case 2: // RSA Encrypt-Only [HAC]
|
||||
case 3: // RSA Sign-Only [HAC]
|
||||
var rsa = new RSA();
|
||||
var n = publicMPIs[0].toBigInteger();
|
||||
var e = publicMPIs[1].toBigInteger();
|
||||
var m = data.toBigInteger();
|
||||
return rsa.encrypt(m,e,n).toMPI();
|
||||
case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
|
||||
var elgamal = new Elgamal();
|
||||
var p = publicMPIs[0].toBigInteger();
|
||||
var g = publicMPIs[1].toBigInteger();
|
||||
var y = publicMPIs[2].toBigInteger();
|
||||
var m = data.toBigInteger();
|
||||
return elgamal.encrypt(m,g,p,y);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts data using the specified public key multiprecision integers of the private key,
|
||||
* the specified secretMPIs of the private key and the specified algorithm.
|
||||
* @param algo [Integer] Algorithm to be used (See RFC4880 9.1)
|
||||
* @param publicMPIs [Array[openpgp_type_mpi]] algorithm dependent multiprecision integers of the public key part of the private key
|
||||
* @param secretMPIs [Array[openpgp_type_mpi]] algorithm dependent multiprecision integers of the private key used
|
||||
* @param data [openpgp_type_mpi] data to be encrypted as MPI
|
||||
* @return [BigInteger] returns a big integer containing the decrypted data; otherwise null
|
||||
*/
|
||||
|
||||
function openpgp_crypto_asymetricDecrypt(algo, publicMPIs, secretMPIs, dataMPIs) {
|
||||
switch(algo) {
|
||||
case 1: // RSA (Encrypt or Sign) [HAC]
|
||||
case 2: // RSA Encrypt-Only [HAC]
|
||||
case 3: // RSA Sign-Only [HAC]
|
||||
var rsa = new RSA();
|
||||
var d = secretMPIs[0].toBigInteger();
|
||||
var p = secretMPIs[1].toBigInteger();
|
||||
var q = secretMPIs[2].toBigInteger();
|
||||
var u = secretMPIs[3].toBigInteger();
|
||||
var m = dataMPIs[0].toBigInteger();
|
||||
return rsa.decrypt(m, d, p, q, u);
|
||||
case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
|
||||
var elgamal = new Elgamal();
|
||||
var x = secretMPIs[0].toBigInteger();
|
||||
var c1 = dataMPIs[0].toBigInteger();
|
||||
var c2 = dataMPIs[1].toBigInteger();
|
||||
var p = publicMPIs[0].toBigInteger();
|
||||
return elgamal.decrypt(c1,c2,p,x);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Symmetrically encrypts data using prefixedrandom, a key with length
|
||||
* depending on the algorithm in openpgp_cfb mode with or without resync
|
||||
* (MDC style)
|
||||
* @param prefixrandom secure random bytes as string in length equal to the
|
||||
* block size of the algorithm used (use openpgp_crypto_getPrefixRandom(algo)
|
||||
* to retrieve that string
|
||||
* @param algo [Integer] algorithm to use (see RFC4880 9.2)
|
||||
* @param key [String] key as string. length is depending on the algorithm used
|
||||
* @param data [String] data to encrypt
|
||||
* @param openpgp_cfb [boolean]
|
||||
* @return [String] encrypted data
|
||||
*/
|
||||
function openpgp_crypto_symmetricEncrypt(prefixrandom, algo, key, data, openpgp_cfb) {
|
||||
switch(algo) {
|
||||
case 0: // Plaintext or unencrypted data
|
||||
return data; // blockcipherencryptfn, plaintext, block_size, key
|
||||
case 2: // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
|
||||
return openpgp_cfb_encrypt(prefixrandom, desede, data,8,key, openpgp_cfb).substring(0, data.length + 10);
|
||||
case 3: // CAST5 (128 bit key, as per [RFC2144])
|
||||
return openpgp_cfb_encrypt(prefixrandom, cast5_encrypt, data,8,key, openpgp_cfb).substring(0, data.length + 10);
|
||||
case 4: // Blowfish (128 bit key, 16 rounds) [BLOWFISH]
|
||||
return openpgp_cfb_encrypt(prefixrandom, BFencrypt, data,8,key, openpgp_cfb).substring(0, data.length + 10);
|
||||
case 7: // AES with 128-bit key [AES]
|
||||
case 8: // AES with 192-bit key
|
||||
case 9: // AES with 256-bit key
|
||||
return openpgp_cfb_encrypt(prefixrandom, AESencrypt, data, 16, keyExpansion(key), openpgp_cfb).substring(0, data.length + 18);
|
||||
case 10: // Twofish with 256-bit key [TWOFISH]
|
||||
return openpgp_cfb_encrypt(prefixrandom, TFencrypt, data,16, key, openpgp_cfb).substring(0, data.length + 18);
|
||||
case 1: // IDEA [IDEA]
|
||||
util.print_error("IDEA Algorithm not implemented");
|
||||
return null;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* generate random byte prefix as string for the specified algorithm
|
||||
* @param algo [Integer] algorithm to use (see RFC4880 9.2)
|
||||
* @return [String] random bytes with length equal to the block
|
||||
* size of the cipher
|
||||
*/
|
||||
function openpgp_crypto_getPrefixRandom(algo) {
|
||||
switch(algo) {
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
return openpgp_crypto_getRandomBytes(8);
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
return openpgp_crypto_getRandomBytes(16);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Symmetrically decrypts data using a key with length depending on the
|
||||
* algorithm in openpgp_cfb mode with or without resync (MDC style)
|
||||
* @param algo [Integer] algorithm to use (see RFC4880 9.2)
|
||||
* @param key [String] key as string. length is depending on the algorithm used
|
||||
* @param data [String] data to be decrypted
|
||||
* @param openpgp_cfb [boolean] if true use the resync (for encrypteddata);
|
||||
* otherwise use without the resync (for MDC encrypted data)
|
||||
* @return [String] plaintext data
|
||||
*/
|
||||
function openpgp_crypto_symmetricDecrypt(algo, key, data, openpgp_cfb) {
|
||||
util.print_debug("openpgp_crypto_symmetricDecrypt:\nalgo:"+algo+"\nencrypteddata:"+util.hexstrdump(data));
|
||||
var n = 0;
|
||||
if (!openpgp_cfb)
|
||||
n = 2;
|
||||
switch(algo) {
|
||||
case 0: // Plaintext or unencrypted data
|
||||
return data;
|
||||
case 2: // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
|
||||
return openpgp_cfb_decrypt(desede, 8, key, data, openpgp_cfb).substring(n, (data.length+n)-10);
|
||||
case 3: // CAST5 (128 bit key, as per [RFC2144])
|
||||
return openpgp_cfb_decrypt(cast5_encrypt, 8, key, data, openpgp_cfb).substring(n, (data.length+n)-10);
|
||||
case 4: // Blowfish (128 bit key, 16 rounds) [BLOWFISH]
|
||||
return openpgp_cfb_decrypt(BFencrypt, 8, key, data, openpgp_cfb).substring(n, (data.length+n)-10);
|
||||
case 7: // AES with 128-bit key [AES]
|
||||
case 8: // AES with 192-bit key
|
||||
case 9: // AES with 256-bit key
|
||||
return openpgp_cfb_decrypt(AESencrypt, 16, keyExpansion(key), data, openpgp_cfb).substring(n, (data.length+n)-18);
|
||||
case 10: // Twofish with 256-bit key [TWOFISH]
|
||||
var result = openpgp_cfb_decrypt(TFencrypt, 16, key, data, openpgp_cfb).substring(n, (data.length+n)-18);
|
||||
return result;
|
||||
case 1: // IDEA [IDEA]
|
||||
util.print_error(""+ (algo == 1 ? "IDEA Algorithm not implemented" : "Twofish Algorithm not implemented"));
|
||||
return null;
|
||||
default:
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieve the MDC prefixed bytes by decrypting them
|
||||
* @param algo [Integer] algorithm to use (see RFC4880 9.2)
|
||||
* @param key [String] key as string. length is depending on the algorithm used
|
||||
* @param data [String] encrypted data where the prefix is decrypted from
|
||||
* @return [String] plain text data of the prefixed data
|
||||
*/
|
||||
function openpgp_crypto_MDCSystemBytes(algo, key, data) {
|
||||
util.print_debug("openpgp_crypto_symmetricDecrypt:\nencrypteddata:"+util.hexstrdump(data));
|
||||
switch(algo) {
|
||||
case 0: // Plaintext or unencrypted data
|
||||
return data;
|
||||
case 2: // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
|
||||
return openpgp_cfb_mdc(desede, 8, key, data, openpgp_cfb);
|
||||
case 3: // CAST5 (128 bit key, as per [RFC2144])
|
||||
return openpgp_cfb_mdc(cast5_encrypt, 8, key, data);
|
||||
case 4: // Blowfish (128 bit key, 16 rounds) [BLOWFISH]
|
||||
return openpgp_cfb_mdc(BFencrypt, 8, key, data);
|
||||
case 7: // AES with 128-bit key [AES]
|
||||
case 8: // AES with 192-bit key
|
||||
case 9: // AES with 256-bit key
|
||||
return openpgp_cfb_mdc(AESencrypt, 16, keyExpansion(key), data);
|
||||
case 10:
|
||||
return openpgp_cfb_mdc(TFencrypt, 16, key, data);
|
||||
case 1: // IDEA [IDEA]
|
||||
util.print_error(""+ (algo == 1 ? "IDEA Algorithm not implemented" : "Twofish Algorithm not implemented"));
|
||||
return null;
|
||||
default:
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Generating a session key for the specified symmetric algorithm
|
||||
* @param algo [Integer] algorithm to use (see RFC4880 9.2)
|
||||
* @return [String] random bytes as a string to be used as a key
|
||||
*/
|
||||
function openpgp_crypto_generateSessionKey(algo) {
|
||||
switch (algo) {
|
||||
case 2: // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
|
||||
case 8: // AES with 192-bit key
|
||||
return openpgp_crypto_getRandomBytes(24);
|
||||
case 3: // CAST5 (128 bit key, as per [RFC2144])
|
||||
case 4: // Blowfish (128 bit key, 16 rounds) [BLOWFISH]
|
||||
case 7: // AES with 128-bit key [AES]
|
||||
util.print_debug("length = 16:\n"+util.hexstrdump(openpgp_crypto_getRandomBytes(16)));
|
||||
return openpgp_crypto_getRandomBytes(16);
|
||||
case 9: // AES with 256-bit key
|
||||
case 10:// Twofish with 256-bit key [TWOFISH]
|
||||
return openpgp_crypto_getRandomBytes(32);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param algo [Integer] public key algorithm
|
||||
* @param hash_algo [Integer] hash algorithm
|
||||
* @param msg_MPIs [Array[openpgp_type_mpi]] signature multiprecision integers
|
||||
* @param publickey_MPIs [Array[openpgp_type_mpi]] public key multiprecision integers
|
||||
* @param data [String] data on where the signature was computed on.
|
||||
* @return true if signature (sig_data was equal to data over hash)
|
||||
*/
|
||||
function openpgp_crypto_verifySignature(algo, hash_algo, msg_MPIs, publickey_MPIs, data) {
|
||||
var calc_hash = openpgp_crypto_hashData(hash_algo, data);
|
||||
switch(algo) {
|
||||
case 1: // RSA (Encrypt or Sign) [HAC]
|
||||
case 2: // RSA Encrypt-Only [HAC]
|
||||
case 3: // RSA Sign-Only [HAC]
|
||||
var rsa = new RSA();
|
||||
var n = publickey_MPIs[0].toBigInteger();
|
||||
var e = publickey_MPIs[1].toBigInteger();
|
||||
var x = msg_MPIs[0].toBigInteger();
|
||||
var dopublic = rsa.verify(x,e,n);
|
||||
var hash = openpgp_encoding_emsa_pkcs1_decode(hash_algo,dopublic.toMPI().substring(2));
|
||||
if (hash == -1) {
|
||||
util.print_error("PKCS1 padding in message or key incorrect. Aborting...");
|
||||
return false;
|
||||
}
|
||||
return hash == calc_hash;
|
||||
|
||||
case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
|
||||
util.print_error("signing with Elgamal is not defined in the OpenPGP standard.");
|
||||
return null;
|
||||
case 17: // DSA (Digital Signature Algorithm) [FIPS186] [HAC]
|
||||
var dsa = new DSA();
|
||||
var s1 = msg_MPIs[0].toBigInteger();
|
||||
var s2 = msg_MPIs[1].toBigInteger();
|
||||
var p = publickey_MPIs[0].toBigInteger();
|
||||
var q = publickey_MPIs[1].toBigInteger();
|
||||
var g = publickey_MPIs[2].toBigInteger();
|
||||
var y = publickey_MPIs[3].toBigInteger();
|
||||
var m = data;
|
||||
var dopublic = dsa.verify(hash_algo,s1,s2,m,p,q,g,y);
|
||||
return dopublic.compareTo(s1) == 0;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a signature on data using the specified algorithm
|
||||
* @param hash_algo [Integer] hash algorithm to use (See RFC4880 9.4)
|
||||
* @param algo [Integer] asymmetric cipher algorithm to use (See RFC4880 9.1)
|
||||
* @param publicMPIs [Array[openpgp_type_mpi]] public key multiprecision integers of the private key
|
||||
* @param secretMPIs [Array[openpgp_type_mpi]] private key multiprecision integers which is used to sign the data
|
||||
* @param data [String] data to be signed
|
||||
* @return [String or openpgp_type_mpi]
|
||||
*/
|
||||
function openpgp_crypto_signData(hash_algo, algo, publicMPIs, secretMPIs, data) {
|
||||
|
||||
switch(algo) {
|
||||
case 1: // RSA (Encrypt or Sign) [HAC]
|
||||
case 2: // RSA Encrypt-Only [HAC]
|
||||
case 3: // RSA Sign-Only [HAC]
|
||||
var rsa = new RSA();
|
||||
var d = secretMPIs[0].toBigInteger();
|
||||
var n = publicMPIs[0].toBigInteger();
|
||||
var m = openpgp_encoding_emsa_pkcs1_encode(hash_algo, data,publicMPIs[0].mpiByteLength);
|
||||
util.print_debug("signing using RSA");
|
||||
return rsa.sign(m, d, n).toMPI();
|
||||
case 17: // DSA (Digital Signature Algorithm) [FIPS186] [HAC]
|
||||
var dsa = new DSA();
|
||||
util.print_debug("DSA Sign: q size in Bytes:"+publicMPIs[1].getByteLength());
|
||||
var p = publicMPIs[0].toBigInteger();
|
||||
var q = publicMPIs[1].toBigInteger();
|
||||
var g = publicMPIs[2].toBigInteger();
|
||||
var y = publicMPIs[3].toBigInteger();
|
||||
var x = secretMPIs[0].toBigInteger();
|
||||
var m = data;
|
||||
var result = dsa.sign(hash_algo,m, g, p, q, x);
|
||||
util.print_debug("signing using DSA\n result:"+util.hexstrdump(result[0])+"|"+util.hexstrdump(result[1]));
|
||||
return result[0]+result[1];
|
||||
case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
|
||||
util.print_debug("signing with Elgamal is not defined in the OpenPGP standard.");
|
||||
return null;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* create a hash on the specified data using the specified algorithm
|
||||
* @param algo [Integer] hash algorithm type (see RFC4880 9.4)
|
||||
* @param data [String] data to be hashed
|
||||
* @return [String] hash value
|
||||
*/
|
||||
function openpgp_crypto_hashData(algo, data) {
|
||||
var hash = null;
|
||||
switch(algo) {
|
||||
case 1: // - MD5 [HAC]
|
||||
hash = MD5(data);
|
||||
break;
|
||||
case 2: // - SHA-1 [FIPS180]
|
||||
hash = str_sha1(data);
|
||||
break;
|
||||
case 3: // - RIPE-MD/160 [HAC]
|
||||
hash = RMDstring(data);
|
||||
break;
|
||||
case 8: // - SHA256 [FIPS180]
|
||||
hash = str_sha256(data);
|
||||
break;
|
||||
case 9: // - SHA384 [FIPS180]
|
||||
hash = str_sha384(data);
|
||||
break;
|
||||
case 10:// - SHA512 [FIPS180]
|
||||
hash = str_sha512(data);
|
||||
break;
|
||||
case 11:// - SHA224 [FIPS180]
|
||||
hash = str_sha224(data);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the hash size in bytes of the specified hash algorithm type
|
||||
* @param algo [Integer] hash algorithm type (See RFC4880 9.4)
|
||||
* @return [Integer] size in bytes of the resulting hash
|
||||
*/
|
||||
function openpgp_crypto_getHashByteLength(algo) {
|
||||
var hash = null;
|
||||
switch(algo) {
|
||||
case 1: // - MD5 [HAC]
|
||||
return 16;
|
||||
case 2: // - SHA-1 [FIPS180]
|
||||
case 3: // - RIPE-MD/160 [HAC]
|
||||
return 20;
|
||||
case 8: // - SHA256 [FIPS180]
|
||||
return 32;
|
||||
case 9: // - SHA384 [FIPS180]
|
||||
return 48
|
||||
case 10:// - SHA512 [FIPS180]
|
||||
return 64;
|
||||
case 11:// - SHA224 [FIPS180]
|
||||
return 28;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieve secure random byte string of the specified length
|
||||
* @param length [Integer] length in bytes to generate
|
||||
* @return [String] random byte string
|
||||
*/
|
||||
function openpgp_crypto_getRandomBytes(length) {
|
||||
var result = '';
|
||||
for (var i = 0; i < length; i++) {
|
||||
result += String.fromCharCode(openpgp_crypto_getSecureRandomOctet());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* return a pseudo-random number in the specified range
|
||||
* @param from [Integer] min of the random number
|
||||
* @param to [Integer] max of the random number (max 32bit)
|
||||
* @return [Integer] a pseudo random number
|
||||
*/
|
||||
function openpgp_crypto_getPseudoRandom(from, to) {
|
||||
return Math.round(Math.random()*(to-from))+from;
|
||||
}
|
||||
|
||||
/**
|
||||
* return a secure random number in the specified range
|
||||
* @param from [Integer] min of the random number
|
||||
* @param to [Integer] max of the random number (max 32bit)
|
||||
* @return [Integer] a secure random number
|
||||
*/
|
||||
function openpgp_crypto_getSecureRandom(from, to) {
|
||||
var buf = new Uint32Array(1);
|
||||
window.crypto.getRandomValues(buf);
|
||||
var bits = ((to-from)).toString(2).length;
|
||||
while ((buf[0] & (Math.pow(2, bits) -1)) > (to-from))
|
||||
window.crypto.getRandomValues(buf);
|
||||
return from+(Math.abs(buf[0] & (Math.pow(2, bits) -1)));
|
||||
}
|
||||
|
||||
function openpgp_crypto_getSecureRandomOctet() {
|
||||
var buf = new Uint32Array(1);
|
||||
window.crypto.getRandomValues(buf);
|
||||
return buf[0] & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* create a secure random big integer of bits length
|
||||
* @param bits [Integer] bit length of the MPI to create
|
||||
* @return [BigInteger] resulting big integer
|
||||
*/
|
||||
function openpgp_crypto_getRandomBigInteger(bits) {
|
||||
if (bits < 0)
|
||||
return null;
|
||||
var numBytes = Math.floor((bits+7)/8);
|
||||
|
||||
var randomBits = openpgp_crypto_getRandomBytes(numBytes);
|
||||
if (bits % 8 > 0) {
|
||||
|
||||
randomBits = String.fromCharCode(
|
||||
(Math.pow(2,bits % 8)-1) &
|
||||
randomBits.charCodeAt(0)) +
|
||||
randomBits.substring(1);
|
||||
}
|
||||
return new openpgp_type_mpi().create(randomBits).toBigInteger();
|
||||
}
|
||||
|
||||
function openpgp_crypto_getRandomBigIntegerInRange(min, max) {
|
||||
if (max < min)
|
||||
return;
|
||||
var range = max.subtract(min);
|
||||
var r = openpgp_crypto_getRandomBigInteger(range.bitLength());
|
||||
while (r > range) {
|
||||
r = openpgp_crypto_getRandomBigInteger(range.bitLength());
|
||||
}
|
||||
return min.add(r);
|
||||
}
|
||||
484
src/ciphers/symmetric/aes.js
Executable file
484
src/ciphers/symmetric/aes.js
Executable file
@@ -0,0 +1,484 @@
|
||||
|
||||
/* Rijndael (AES) Encryption
|
||||
* Copyright 2005 Herbert Hanewinkel, www.haneWIN.de
|
||||
* version 1.1, check www.haneWIN.de for the latest version
|
||||
|
||||
* This software is provided as-is, without express or implied warranty.
|
||||
* Permission to use, copy, modify, distribute or sell this software, with or
|
||||
* without fee, for any purpose and by any individual or organization, is hereby
|
||||
* granted, provided that the above copyright notice and this paragraph appear
|
||||
* in all copies. Distribution as a part of an application or binary must
|
||||
* include the above copyright notice in the documentation and/or other
|
||||
* materials provided with the application or distribution.
|
||||
*/
|
||||
|
||||
// The round constants used in subkey expansion
|
||||
var Rcon = [
|
||||
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
|
||||
0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4,
|
||||
0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 ];
|
||||
|
||||
// Precomputed lookup table for the SBox
|
||||
var S = [
|
||||
99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171,
|
||||
118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164,
|
||||
114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113,
|
||||
216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226,
|
||||
235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214,
|
||||
179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203,
|
||||
190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69,
|
||||
249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245,
|
||||
188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68,
|
||||
23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42,
|
||||
144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73,
|
||||
6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109,
|
||||
141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37,
|
||||
46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62,
|
||||
181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225,
|
||||
248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223,
|
||||
140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187,
|
||||
22 ];
|
||||
|
||||
var T1 = [
|
||||
0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6,
|
||||
0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591,
|
||||
0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56,
|
||||
0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec,
|
||||
0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa,
|
||||
0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb,
|
||||
0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45,
|
||||
0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b,
|
||||
0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c,
|
||||
0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83,
|
||||
0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9,
|
||||
0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a,
|
||||
0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d,
|
||||
0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f,
|
||||
0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df,
|
||||
0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea,
|
||||
0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34,
|
||||
0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b,
|
||||
0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d,
|
||||
0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413,
|
||||
0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1,
|
||||
0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6,
|
||||
0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972,
|
||||
0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85,
|
||||
0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed,
|
||||
0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511,
|
||||
0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe,
|
||||
0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b,
|
||||
0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05,
|
||||
0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1,
|
||||
0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142,
|
||||
0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf,
|
||||
0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3,
|
||||
0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e,
|
||||
0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a,
|
||||
0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6,
|
||||
0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3,
|
||||
0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b,
|
||||
0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428,
|
||||
0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad,
|
||||
0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14,
|
||||
0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8,
|
||||
0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4,
|
||||
0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2,
|
||||
0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda,
|
||||
0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949,
|
||||
0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf,
|
||||
0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810,
|
||||
0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c,
|
||||
0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697,
|
||||
0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e,
|
||||
0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f,
|
||||
0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc,
|
||||
0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c,
|
||||
0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969,
|
||||
0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27,
|
||||
0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122,
|
||||
0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433,
|
||||
0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9,
|
||||
0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5,
|
||||
0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a,
|
||||
0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0,
|
||||
0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e,
|
||||
0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c ];
|
||||
|
||||
var T2 = [
|
||||
0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d,
|
||||
0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154,
|
||||
0x30306050, 0x01010203, 0x6767cea9, 0x2b2b567d,
|
||||
0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a,
|
||||
0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87,
|
||||
0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b,
|
||||
0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea,
|
||||
0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b,
|
||||
0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a,
|
||||
0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f,
|
||||
0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908,
|
||||
0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f,
|
||||
0x0404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e,
|
||||
0x18183028, 0x969637a1, 0x05050a0f, 0x9a9a2fb5,
|
||||
0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d,
|
||||
0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f,
|
||||
0x0909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e,
|
||||
0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb,
|
||||
0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce,
|
||||
0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397,
|
||||
0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c,
|
||||
0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed,
|
||||
0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b,
|
||||
0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a,
|
||||
0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16,
|
||||
0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194,
|
||||
0x45458acf, 0xf9f9e910, 0x02020406, 0x7f7ffe81,
|
||||
0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3,
|
||||
0x5151a2f3, 0xa3a35dfe, 0x404080c0, 0x8f8f058a,
|
||||
0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104,
|
||||
0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263,
|
||||
0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d,
|
||||
0xcdcd814c, 0x0c0c1814, 0x13132635, 0xececc32f,
|
||||
0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39,
|
||||
0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47,
|
||||
0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695,
|
||||
0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f,
|
||||
0x22224466, 0x2a2a547e, 0x90903bab, 0x88880b83,
|
||||
0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c,
|
||||
0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76,
|
||||
0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e,
|
||||
0x494992db, 0x06060c0a, 0x2424486c, 0x5c5cb8e4,
|
||||
0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6,
|
||||
0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b,
|
||||
0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7,
|
||||
0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0,
|
||||
0x6c6cd8b4, 0x5656acfa, 0xf4f4f307, 0xeaeacf25,
|
||||
0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x08081018,
|
||||
0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72,
|
||||
0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751,
|
||||
0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21,
|
||||
0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85,
|
||||
0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa,
|
||||
0x484890d8, 0x03030605, 0xf6f6f701, 0x0e0e1c12,
|
||||
0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0,
|
||||
0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9,
|
||||
0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233,
|
||||
0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7,
|
||||
0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920,
|
||||
0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a,
|
||||
0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17,
|
||||
0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8,
|
||||
0x414182c3, 0x999929b0, 0x2d2d5a77, 0x0f0f1e11,
|
||||
0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a ];
|
||||
|
||||
var T3 = [
|
||||
0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b,
|
||||
0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5,
|
||||
0x30605030, 0x01020301, 0x67cea967, 0x2b567d2b,
|
||||
0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76,
|
||||
0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d,
|
||||
0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0,
|
||||
0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf,
|
||||
0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0,
|
||||
0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26,
|
||||
0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc,
|
||||
0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1,
|
||||
0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15,
|
||||
0x04080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3,
|
||||
0x18302818, 0x9637a196, 0x050a0f05, 0x9a2fb59a,
|
||||
0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2,
|
||||
0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75,
|
||||
0x09121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a,
|
||||
0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0,
|
||||
0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3,
|
||||
0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784,
|
||||
0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced,
|
||||
0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b,
|
||||
0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39,
|
||||
0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf,
|
||||
0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb,
|
||||
0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485,
|
||||
0x458acf45, 0xf9e910f9, 0x02040602, 0x7ffe817f,
|
||||
0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8,
|
||||
0x51a2f351, 0xa35dfea3, 0x4080c040, 0x8f058a8f,
|
||||
0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5,
|
||||
0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321,
|
||||
0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2,
|
||||
0xcd814ccd, 0x0c18140c, 0x13263513, 0xecc32fec,
|
||||
0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917,
|
||||
0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d,
|
||||
0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573,
|
||||
0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc,
|
||||
0x22446622, 0x2a547e2a, 0x903bab90, 0x880b8388,
|
||||
0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14,
|
||||
0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db,
|
||||
0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a,
|
||||
0x4992db49, 0x060c0a06, 0x24486c24, 0x5cb8e45c,
|
||||
0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662,
|
||||
0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79,
|
||||
0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d,
|
||||
0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9,
|
||||
0x6cd8b46c, 0x56acfa56, 0xf4f307f4, 0xeacf25ea,
|
||||
0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x08101808,
|
||||
0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e,
|
||||
0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6,
|
||||
0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f,
|
||||
0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a,
|
||||
0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66,
|
||||
0x4890d848, 0x03060503, 0xf6f701f6, 0x0e1c120e,
|
||||
0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9,
|
||||
0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e,
|
||||
0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311,
|
||||
0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794,
|
||||
0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9,
|
||||
0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf,
|
||||
0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d,
|
||||
0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868,
|
||||
0x4182c341, 0x9929b099, 0x2d5a772d, 0x0f1e110f,
|
||||
0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16 ];
|
||||
|
||||
var T4 = [
|
||||
0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b,
|
||||
0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5,
|
||||
0x60503030, 0x02030101, 0xcea96767, 0x567d2b2b,
|
||||
0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676,
|
||||
0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d,
|
||||
0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0,
|
||||
0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf,
|
||||
0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0,
|
||||
0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626,
|
||||
0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc,
|
||||
0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1,
|
||||
0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515,
|
||||
0x080c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3,
|
||||
0x30281818, 0x37a19696, 0x0a0f0505, 0x2fb59a9a,
|
||||
0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2,
|
||||
0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575,
|
||||
0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a,
|
||||
0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0,
|
||||
0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3,
|
||||
0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484,
|
||||
0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded,
|
||||
0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b,
|
||||
0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939,
|
||||
0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf,
|
||||
0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb,
|
||||
0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585,
|
||||
0x8acf4545, 0xe910f9f9, 0x04060202, 0xfe817f7f,
|
||||
0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8,
|
||||
0xa2f35151, 0x5dfea3a3, 0x80c04040, 0x058a8f8f,
|
||||
0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5,
|
||||
0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121,
|
||||
0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2,
|
||||
0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec,
|
||||
0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717,
|
||||
0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d,
|
||||
0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373,
|
||||
0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc,
|
||||
0x44662222, 0x547e2a2a, 0x3bab9090, 0x0b838888,
|
||||
0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414,
|
||||
0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb,
|
||||
0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a,
|
||||
0x92db4949, 0x0c0a0606, 0x486c2424, 0xb8e45c5c,
|
||||
0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262,
|
||||
0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979,
|
||||
0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d,
|
||||
0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9,
|
||||
0xd8b46c6c, 0xacfa5656, 0xf307f4f4, 0xcf25eaea,
|
||||
0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808,
|
||||
0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e,
|
||||
0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6,
|
||||
0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f,
|
||||
0x96dd4b4b, 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a,
|
||||
0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666,
|
||||
0x90d84848, 0x06050303, 0xf701f6f6, 0x1c120e0e,
|
||||
0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9,
|
||||
0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e,
|
||||
0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111,
|
||||
0xd2bb6969, 0xa970d9d9, 0x07898e8e, 0x33a79494,
|
||||
0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9,
|
||||
0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf,
|
||||
0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d,
|
||||
0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868,
|
||||
0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f,
|
||||
0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616 ];
|
||||
|
||||
function B0(x) { return (x&255); }
|
||||
function B1(x) { return ((x>>8)&255); }
|
||||
function B2(x) { return ((x>>16)&255); }
|
||||
function B3(x) { return ((x>>24)&255); }
|
||||
|
||||
function F1(x0, x1, x2, x3)
|
||||
{
|
||||
return B1(T1[x0&255]) | (B1(T1[(x1>>8)&255])<<8)
|
||||
| (B1(T1[(x2>>16)&255])<<16) | (B1(T1[x3>>>24])<<24);
|
||||
}
|
||||
|
||||
function packBytes(octets)
|
||||
{
|
||||
var i, j;
|
||||
var len=octets.length;
|
||||
var b=new Array(len/4);
|
||||
|
||||
if (!octets || len % 4) return;
|
||||
|
||||
for (i=0, j=0; j<len; j+= 4)
|
||||
b[i++] = octets[j] | (octets[j+1]<<8) | (octets[j+2]<<16) | (octets[j+3]<<24);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
function unpackBytes(packed)
|
||||
{
|
||||
var j;
|
||||
var i=0, l = packed.length;
|
||||
var r = new Array(l*4);
|
||||
|
||||
for (j=0; j<l; j++)
|
||||
{
|
||||
r[i++] = B0(packed[j]);
|
||||
r[i++] = B1(packed[j]);
|
||||
r[i++] = B2(packed[j]);
|
||||
r[i++] = B3(packed[j]);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
var maxkc=8;
|
||||
var maxrk=14;
|
||||
|
||||
function keyExpansion(key)
|
||||
{
|
||||
var kc, i, j, r, t;
|
||||
var rounds;
|
||||
var keySched=new Array(maxrk+1);
|
||||
var keylen=key.length;
|
||||
var k=new Array(maxkc);
|
||||
var tk=new Array(maxkc);
|
||||
var rconpointer=0;
|
||||
|
||||
if(keylen==16)
|
||||
{
|
||||
rounds=10;
|
||||
kc=4;
|
||||
}
|
||||
else if(keylen==24)
|
||||
{
|
||||
rounds=12;
|
||||
kc=6;
|
||||
}
|
||||
else if(keylen==32)
|
||||
{
|
||||
rounds=14;
|
||||
kc=8;
|
||||
}
|
||||
else
|
||||
{
|
||||
util.print_error('aes.js: Invalid key-length for AES key:'+keylen);
|
||||
return;
|
||||
}
|
||||
|
||||
for(i=0; i<maxrk+1; i++) keySched[i]=new Array(4);
|
||||
|
||||
for(i=0,j=0; j<keylen; j++,i+=4)
|
||||
k[j] = key.charCodeAt(i) | (key.charCodeAt(i+1)<<8)
|
||||
| (key.charCodeAt(i+2)<<16) | (key.charCodeAt(i+3)<<24);
|
||||
|
||||
for(j=kc-1; j>=0; j--) tk[j] = k[j];
|
||||
|
||||
r=0;
|
||||
t=0;
|
||||
for(j=0; (j<kc)&&(r<rounds+1); )
|
||||
{
|
||||
for(; (j<kc)&&(t<4); j++,t++)
|
||||
{
|
||||
keySched[r][t]=tk[j];
|
||||
}
|
||||
if(t==4)
|
||||
{
|
||||
r++;
|
||||
t=0;
|
||||
}
|
||||
}
|
||||
|
||||
while(r<rounds+1)
|
||||
{
|
||||
var temp = tk[kc-1];
|
||||
|
||||
tk[0] ^= S[B1(temp)] | (S[B2(temp)]<<8) | (S[B3(temp)]<<16) | (S[B0(temp)]<<24);
|
||||
tk[0] ^= Rcon[rconpointer++];
|
||||
|
||||
if(kc != 8)
|
||||
{
|
||||
for(j=1; j<kc; j++) tk[j] ^= tk[j-1];
|
||||
}
|
||||
else
|
||||
{
|
||||
for(j=1; j<kc/2; j++) tk[j] ^= tk[j-1];
|
||||
|
||||
temp = tk[kc/2-1];
|
||||
tk[kc/2] ^= S[B0(temp)] | (S[B1(temp)]<<8) | (S[B2(temp)]<<16) | (S[B3(temp)]<<24);
|
||||
|
||||
for(j=kc/2+1; j<kc; j++) tk[j] ^= tk[j-1];
|
||||
}
|
||||
|
||||
for(j=0; (j<kc)&&(r<rounds+1); )
|
||||
{
|
||||
for(; (j<kc)&&(t<4); j++,t++)
|
||||
{
|
||||
keySched[r][t]=tk[j];
|
||||
}
|
||||
if(t==4)
|
||||
{
|
||||
r++;
|
||||
t=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.rounds = rounds;
|
||||
this.rk = keySched;
|
||||
return this;
|
||||
}
|
||||
|
||||
function AESencrypt(block, ctx)
|
||||
{
|
||||
var r;
|
||||
var t0,t1,t2,t3;
|
||||
|
||||
var b = packBytes(block);
|
||||
var rounds = ctx.rounds;
|
||||
var b0 = b[0];
|
||||
var b1 = b[1];
|
||||
var b2 = b[2];
|
||||
var b3 = b[3];
|
||||
|
||||
for(r=0; r<rounds-1; r++)
|
||||
{
|
||||
t0 = b0 ^ ctx.rk[r][0];
|
||||
t1 = b1 ^ ctx.rk[r][1];
|
||||
t2 = b2 ^ ctx.rk[r][2];
|
||||
t3 = b3 ^ ctx.rk[r][3];
|
||||
|
||||
b0 = T1[t0&255] ^ T2[(t1>>8)&255] ^ T3[(t2>>16)&255] ^ T4[t3>>>24];
|
||||
b1 = T1[t1&255] ^ T2[(t2>>8)&255] ^ T3[(t3>>16)&255] ^ T4[t0>>>24];
|
||||
b2 = T1[t2&255] ^ T2[(t3>>8)&255] ^ T3[(t0>>16)&255] ^ T4[t1>>>24];
|
||||
b3 = T1[t3&255] ^ T2[(t0>>8)&255] ^ T3[(t1>>16)&255] ^ T4[t2>>>24];
|
||||
}
|
||||
|
||||
// last round is special
|
||||
r = rounds-1;
|
||||
|
||||
t0 = b0 ^ ctx.rk[r][0];
|
||||
t1 = b1 ^ ctx.rk[r][1];
|
||||
t2 = b2 ^ ctx.rk[r][2];
|
||||
t3 = b3 ^ ctx.rk[r][3];
|
||||
|
||||
b[0] = F1(t0, t1, t2, t3) ^ ctx.rk[rounds][0];
|
||||
b[1] = F1(t1, t2, t3, t0) ^ ctx.rk[rounds][1];
|
||||
b[2] = F1(t2, t3, t0, t1) ^ ctx.rk[rounds][2];
|
||||
b[3] = F1(t3, t0, t1, t2) ^ ctx.rk[rounds][3];
|
||||
|
||||
return unpackBytes(b);
|
||||
}
|
||||
393
src/ciphers/symmetric/blowfish.js
Executable file
393
src/ciphers/symmetric/blowfish.js
Executable file
@@ -0,0 +1,393 @@
|
||||
/* Modified by Recurity Labs GmbH
|
||||
*
|
||||
* Originally written by nklein software (nklein.com)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Javascript implementation based on Bruce Schneier's reference implementation.
|
||||
*
|
||||
*
|
||||
* The constructor doesn't do much of anything. It's just here
|
||||
* so we can start defining properties and methods and such.
|
||||
*/
|
||||
function Blowfish() {
|
||||
};
|
||||
|
||||
/*
|
||||
* Declare the block size so that protocols know what size
|
||||
* Initialization Vector (IV) they will need.
|
||||
*/
|
||||
Blowfish.prototype.BLOCKSIZE = 8;
|
||||
|
||||
/*
|
||||
* These are the default SBOXES.
|
||||
*/
|
||||
Blowfish.prototype.SBOXES = [
|
||||
[
|
||||
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
|
||||
0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
|
||||
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
|
||||
0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
|
||||
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
|
||||
0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
|
||||
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
|
||||
0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
|
||||
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
|
||||
0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
|
||||
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
|
||||
0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
|
||||
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
|
||||
0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
|
||||
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
|
||||
0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
|
||||
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
|
||||
0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
|
||||
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
|
||||
0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
|
||||
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
|
||||
0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
|
||||
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
|
||||
0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
|
||||
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
|
||||
0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
|
||||
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
|
||||
0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
|
||||
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
|
||||
0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
|
||||
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
|
||||
0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
|
||||
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
|
||||
0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
|
||||
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
|
||||
0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
|
||||
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
|
||||
0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
|
||||
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
|
||||
0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
|
||||
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
|
||||
0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
|
||||
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
|
||||
], [
|
||||
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
|
||||
0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
|
||||
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
|
||||
0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
|
||||
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
|
||||
0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
|
||||
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
|
||||
0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
|
||||
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
|
||||
0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
|
||||
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
|
||||
0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
|
||||
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
|
||||
0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
|
||||
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
|
||||
0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
|
||||
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
|
||||
0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
|
||||
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
|
||||
0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
|
||||
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
|
||||
0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
|
||||
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
|
||||
0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
|
||||
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
|
||||
0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
|
||||
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
|
||||
0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
|
||||
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
|
||||
0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
|
||||
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
|
||||
0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
|
||||
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
|
||||
0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
|
||||
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
|
||||
0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
|
||||
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
|
||||
0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
|
||||
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
|
||||
0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
|
||||
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
|
||||
0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
|
||||
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
|
||||
], [
|
||||
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
|
||||
0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
|
||||
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
|
||||
0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
|
||||
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
|
||||
0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
|
||||
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
|
||||
0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
|
||||
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
|
||||
0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
|
||||
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
|
||||
0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
|
||||
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
|
||||
0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
|
||||
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
|
||||
0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
|
||||
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
|
||||
0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
|
||||
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
|
||||
0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
|
||||
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
|
||||
0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
|
||||
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
|
||||
0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
|
||||
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
|
||||
0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
|
||||
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
|
||||
0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
|
||||
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
|
||||
0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
|
||||
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
|
||||
0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
|
||||
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
|
||||
0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
|
||||
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
|
||||
0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
|
||||
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
|
||||
0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
|
||||
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
|
||||
0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
|
||||
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
|
||||
0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
|
||||
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
|
||||
], [
|
||||
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
|
||||
0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
|
||||
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
|
||||
0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
|
||||
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
|
||||
0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
|
||||
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
|
||||
0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
|
||||
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
|
||||
0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
|
||||
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
|
||||
0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
|
||||
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
|
||||
0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
|
||||
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
|
||||
0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
|
||||
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
|
||||
0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
|
||||
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
|
||||
0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
|
||||
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
|
||||
0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
|
||||
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
|
||||
0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
|
||||
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
|
||||
0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
|
||||
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
|
||||
0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
|
||||
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
|
||||
0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
|
||||
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
|
||||
0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
|
||||
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
|
||||
0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
|
||||
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
|
||||
0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
|
||||
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
|
||||
0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
|
||||
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
|
||||
0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
|
||||
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
|
||||
0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
|
||||
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
|
||||
]
|
||||
];
|
||||
|
||||
//*
|
||||
//* This is the default PARRAY
|
||||
//*
|
||||
Blowfish.prototype.PARRAY = [
|
||||
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
|
||||
0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
|
||||
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b
|
||||
];
|
||||
|
||||
//*
|
||||
//* This is the number of rounds the cipher will go
|
||||
//*
|
||||
Blowfish.prototype.NN = 16;
|
||||
|
||||
//*
|
||||
//* This function is needed to get rid of problems
|
||||
//* with the high-bit getting set. If we don't do
|
||||
//* this, then sometimes ( aa & 0x00FFFFFFFF ) is not
|
||||
//* equal to ( bb & 0x00FFFFFFFF ) even when they
|
||||
//* agree bit-for-bit for the first 32 bits.
|
||||
//*
|
||||
Blowfish.prototype._clean = function( xx ) {
|
||||
if ( xx < 0 ) {
|
||||
var yy = xx & 0x7FFFFFFF;
|
||||
xx = yy + 0x80000000;
|
||||
}
|
||||
return xx;
|
||||
};
|
||||
|
||||
//*
|
||||
//* This is the mixing function that uses the sboxes
|
||||
//*
|
||||
Blowfish.prototype._F = function ( xx ) {
|
||||
var aa;
|
||||
var bb;
|
||||
var cc;
|
||||
var dd;
|
||||
var yy;
|
||||
|
||||
dd = xx & 0x00FF;
|
||||
xx >>>= 8;
|
||||
cc = xx & 0x00FF;
|
||||
xx >>>= 8;
|
||||
bb = xx & 0x00FF;
|
||||
xx >>>= 8;
|
||||
aa = xx & 0x00FF;
|
||||
|
||||
yy = this.sboxes[ 0 ][ aa ] + this.sboxes[ 1 ][ bb ];
|
||||
yy = yy ^ this.sboxes[ 2 ][ cc ];
|
||||
yy = yy + this.sboxes[ 3 ][ dd ];
|
||||
|
||||
return yy;
|
||||
};
|
||||
|
||||
//*
|
||||
//* This method takes an array with two values, left and right
|
||||
//* and does NN rounds of Blowfish on them.
|
||||
//*
|
||||
Blowfish.prototype._encrypt_block = function ( vals ) {
|
||||
var dataL = vals[ 0 ];
|
||||
var dataR = vals[ 1 ];
|
||||
|
||||
var ii;
|
||||
|
||||
for ( ii=0; ii < this.NN; ++ii ) {
|
||||
dataL = dataL ^ this.parray[ ii ];
|
||||
dataR = this._F( dataL ) ^ dataR;
|
||||
|
||||
var tmp = dataL;
|
||||
dataL = dataR;
|
||||
dataR = tmp;
|
||||
}
|
||||
|
||||
dataL = dataL ^ this.parray[ this.NN + 0 ];
|
||||
dataR = dataR ^ this.parray[ this.NN + 1 ];
|
||||
|
||||
vals[ 0 ] = this._clean( dataR );
|
||||
vals[ 1 ] = this._clean( dataL );
|
||||
};
|
||||
|
||||
//*
|
||||
//* This method takes a vector of numbers and turns them
|
||||
//* into long words so that they can be processed by the
|
||||
//* real algorithm.
|
||||
//*
|
||||
//* Maybe I should make the real algorithm above take a vector
|
||||
//* instead. That will involve more looping, but it won't require
|
||||
//* the F() method to deconstruct the vector.
|
||||
//*
|
||||
Blowfish.prototype.encrypt_block = function ( vector ) {
|
||||
var ii;
|
||||
var vals = [ 0, 0 ];
|
||||
var off = this.BLOCKSIZE/2;
|
||||
for ( ii = 0; ii < this.BLOCKSIZE/2; ++ii ) {
|
||||
vals[0] = ( vals[0] << 8 ) | ( vector[ ii + 0 ] & 0x00FF );
|
||||
vals[1] = ( vals[1] << 8 ) | ( vector[ ii + off ] & 0x00FF );
|
||||
}
|
||||
|
||||
this._encrypt_block( vals );
|
||||
|
||||
var ret = [ ];
|
||||
for ( ii = 0; ii < this.BLOCKSIZE/2; ++ii ) {
|
||||
ret[ ii + 0 ] = ( vals[ 0 ] >>> (24 - 8*(ii)) & 0x00FF );
|
||||
ret[ ii + off ] = ( vals[ 1 ] >>> (24 - 8*(ii)) & 0x00FF );
|
||||
// vals[ 0 ] = ( vals[ 0 ] >>> 8 );
|
||||
// vals[ 1 ] = ( vals[ 1 ] >>> 8 );
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
//*
|
||||
//* This method takes an array with two values, left and right
|
||||
//* and undoes NN rounds of Blowfish on them.
|
||||
//*
|
||||
Blowfish.prototype._decrypt_block = function ( vals ) {
|
||||
var dataL = vals[ 0 ];
|
||||
var dataR = vals[ 1 ];
|
||||
|
||||
var ii;
|
||||
|
||||
for ( ii=this.NN+1; ii > 1; --ii ) {
|
||||
dataL = dataL ^ this.parray[ ii ];
|
||||
dataR = this._F( dataL ) ^ dataR;
|
||||
|
||||
var tmp = dataL;
|
||||
dataL = dataR;
|
||||
dataR = tmp;
|
||||
}
|
||||
|
||||
dataL = dataL ^ this.parray[ 1 ];
|
||||
dataR = dataR ^ this.parray[ 0 ];
|
||||
|
||||
vals[ 0 ] = this._clean( dataR );
|
||||
vals[ 1 ] = this._clean( dataL );
|
||||
};
|
||||
|
||||
//*
|
||||
//* This method takes a key array and initializes the
|
||||
//* sboxes and parray for this encryption.
|
||||
//*
|
||||
Blowfish.prototype.init = function ( key ) {
|
||||
var ii;
|
||||
var jj = 0;
|
||||
|
||||
this.parray = [];
|
||||
for ( ii=0; ii < this.NN + 2; ++ii ) {
|
||||
var data = 0x00000000;
|
||||
var kk;
|
||||
for ( kk=0; kk < 4; ++kk ) {
|
||||
data = ( data << 8 ) | ( key[ jj ] & 0x00FF );
|
||||
if ( ++jj >= key.length ) {
|
||||
jj = 0;
|
||||
}
|
||||
}
|
||||
this.parray[ ii ] = this.PARRAY[ ii ] ^ data;
|
||||
}
|
||||
|
||||
this.sboxes = [];
|
||||
for ( ii=0; ii < 4; ++ii ) {
|
||||
this.sboxes[ ii ] = [];
|
||||
for ( jj=0; jj < 256; ++jj ) {
|
||||
this.sboxes[ ii ][ jj ] = this.SBOXES[ ii ][ jj ];
|
||||
}
|
||||
}
|
||||
|
||||
var vals = [ 0x00000000, 0x00000000 ];
|
||||
|
||||
for ( ii=0; ii < this.NN+2; ii += 2 ) {
|
||||
this._encrypt_block( vals );
|
||||
this.parray[ ii + 0 ] = vals[ 0 ];
|
||||
this.parray[ ii + 1 ] = vals[ 1 ];
|
||||
}
|
||||
|
||||
for ( ii=0; ii < 4; ++ii ) {
|
||||
for ( jj=0; jj < 256; jj += 2 ) {
|
||||
this._encrypt_block( vals );
|
||||
this.sboxes[ ii ][ jj + 0 ] = vals[ 0 ];
|
||||
this.sboxes[ ii ][ jj + 1 ] = vals[ 1 ];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// added by Recurity Labs
|
||||
function BFencrypt(block,key) {
|
||||
var bf = new Blowfish();
|
||||
bf.init(util.str2bin(key));
|
||||
return bf.encrypt_block(block);
|
||||
}
|
||||
547
src/ciphers/symmetric/cast5.js
Executable file
547
src/ciphers/symmetric/cast5.js
Executable file
@@ -0,0 +1,547 @@
|
||||
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Copyright 2010 pjacobs@xeekr.com . All rights reserved.
|
||||
|
||||
// Modified by Recurity Labs GmbH
|
||||
|
||||
// fixed/modified by Herbert Hanewinkel, www.haneWIN.de
|
||||
// check www.haneWIN.de for the latest version
|
||||
|
||||
// cast5.js is a Javascript implementation of CAST-128, as defined in RFC 2144.
|
||||
// CAST-128 is a common OpenPGP cipher.
|
||||
|
||||
|
||||
// CAST5 constructor
|
||||
|
||||
function cast5_encrypt(block, key) {
|
||||
var cast5 = new openpgp_symenc_cast5();
|
||||
cast5.setKey(util.str2bin(key));
|
||||
return cast5.encrypt(block);
|
||||
}
|
||||
|
||||
function openpgp_symenc_cast5() {
|
||||
this.BlockSize= 8;
|
||||
this.KeySize = 16;
|
||||
|
||||
this.setKey = function (key) {
|
||||
this.masking = new Array(16);
|
||||
this.rotate = new Array(16);
|
||||
|
||||
this.reset();
|
||||
|
||||
if (key.length == this.KeySize)
|
||||
{
|
||||
this.keySchedule(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
util.print_error('cast5.js: CAST-128: keys must be 16 bytes');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
this.reset = function() {
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
this.masking[i] = 0;
|
||||
this.rotate[i] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
this.getBlockSize = function() {
|
||||
return BlockSize;
|
||||
};
|
||||
|
||||
this.encrypt = function(src) {
|
||||
var dst = new Array(src.length);
|
||||
|
||||
for(i = 0; i < src.length; i+=8)
|
||||
{
|
||||
var l = src[i]<<24 | src[i+1]<<16 | src[i+2]<<8 | src[i+3];
|
||||
var r = src[i+4]<<24 | src[i+5]<<16 | src[i+6]<<8 | src[i+7];
|
||||
var t;
|
||||
|
||||
t = r; r = l^f1(r, this.masking[0], this.rotate[0]); l = t;
|
||||
t = r; r = l^f2(r, this.masking[1], this.rotate[1]); l = t;
|
||||
t = r; r = l^f3(r, this.masking[2], this.rotate[2]); l = t;
|
||||
t = r; r = l^f1(r, this.masking[3], this.rotate[3]); l = t;
|
||||
|
||||
t = r; r = l^f2(r, this.masking[4], this.rotate[4]); l = t;
|
||||
t = r; r = l^f3(r, this.masking[5], this.rotate[5]); l = t;
|
||||
t = r; r = l^f1(r, this.masking[6], this.rotate[6]); l = t;
|
||||
t = r; r = l^f2(r, this.masking[7], this.rotate[7]); l = t;
|
||||
|
||||
t = r; r = l^f3(r, this.masking[8], this.rotate[8]); l = t;
|
||||
t = r; r = l^f1(r, this.masking[9], this.rotate[9]); l = t;
|
||||
t = r; r = l^f2(r, this.masking[10], this.rotate[10]); l = t;
|
||||
t = r; r = l^f3(r, this.masking[11], this.rotate[11]); l = t;
|
||||
|
||||
t = r; r = l^f1(r, this.masking[12], this.rotate[12]); l = t;
|
||||
t = r; r = l^f2(r, this.masking[13], this.rotate[13]); l = t;
|
||||
t = r; r = l^f3(r, this.masking[14], this.rotate[14]); l = t;
|
||||
t = r; r = l^f1(r, this.masking[15], this.rotate[15]); l = t;
|
||||
|
||||
dst[i] = (r >>> 24)&255;
|
||||
dst[i+1] = (r >>> 16)&255;
|
||||
dst[i+2] = (r >>> 8)&255;
|
||||
dst[i+3] = r&255;
|
||||
dst[i+4] = (l >>> 24)&255;
|
||||
dst[i+5] = (l >>> 16)&255;
|
||||
dst[i+6] = (l >>> 8)&255;
|
||||
dst[i+7] = l&255;
|
||||
}
|
||||
|
||||
return dst;
|
||||
};
|
||||
|
||||
this.decrypt = function(src) {
|
||||
var dst = new Array(src.length);
|
||||
|
||||
for(i = 0; i < src.length; i+=8)
|
||||
{
|
||||
var l = src[i]<<24 | src[i+1]<<16 | src[i+2]<<8 | src[i+3];
|
||||
var r = src[i+4]<<24 | src[i+5]<<16 | src[i+6]<<8 | src[i+7];
|
||||
var t;
|
||||
|
||||
t = r; r = l^f1(r, this.masking[15], this.rotate[15]); l = t;
|
||||
t = r; r = l^f3(r, this.masking[14], this.rotate[14]); l = t;
|
||||
t = r; r = l^f2(r, this.masking[13], this.rotate[13]); l = t;
|
||||
t = r; r = l^f1(r, this.masking[12], this.rotate[12]); l = t;
|
||||
|
||||
t = r; r = l^f3(r, this.masking[11], this.rotate[11]); l = t;
|
||||
t = r; r = l^f2(r, this.masking[10], this.rotate[10]); l = t;
|
||||
t = r; r = l^f1(r, this.masking[9], this.rotate[9]); l = t;
|
||||
t = r; r = l^f3(r, this.masking[8], this.rotate[8]); l = t;
|
||||
|
||||
t = r; r = l^f2(r, this.masking[7], this.rotate[7]); l = t;
|
||||
t = r; r = l^f1(r, this.masking[6], this.rotate[6]); l = t;
|
||||
t = r; r = l^f3(r, this.masking[5], this.rotate[5]); l = t;
|
||||
t = r; r = l^f2(r, this.masking[4], this.rotate[4]); l = t;
|
||||
|
||||
t = r; r = l^f1(r, this.masking[3], this.rotate[3]); l = t;
|
||||
t = r; r = l^f3(r, this.masking[2], this.rotate[2]); l = t;
|
||||
t = r; r = l^f2(r, this.masking[1], this.rotate[1]); l = t;
|
||||
t = r; r = l^f1(r, this.masking[0], this.rotate[0]); l = t;
|
||||
|
||||
dst[i] = (r >>> 24)&255;
|
||||
dst[i+1] = (r >>> 16)&255;
|
||||
dst[i+2] = (r >>> 8)&255;
|
||||
dst[i+3] = r&255;
|
||||
dst[i+4] = (l >>> 24)&255;
|
||||
dst[i+5] = (l >> 16)&255;
|
||||
dst[i+6] = (l >> 8)&255;
|
||||
dst[i+7] = l&255;
|
||||
}
|
||||
|
||||
return dst;
|
||||
};
|
||||
var scheduleA = new Array(4);
|
||||
|
||||
scheduleA[0] = new Array(4);
|
||||
scheduleA[0][0] = new Array(4, 0, 0xd, 0xf, 0xc, 0xe, 0x8);
|
||||
scheduleA[0][1] = new Array(5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa);
|
||||
scheduleA[0][2] = new Array(6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9);
|
||||
scheduleA[0][3] = new Array(7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb);
|
||||
|
||||
scheduleA[1] = new Array(4);
|
||||
scheduleA[1][0] = new Array(0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0);
|
||||
scheduleA[1][1] = new Array(1, 4, 0, 2, 1, 3, 16 + 2);
|
||||
scheduleA[1][2] = new Array(2, 5, 7, 6, 5, 4, 16 + 1);
|
||||
scheduleA[1][3] = new Array(3, 7, 0xa, 9, 0xb, 8, 16 + 3);
|
||||
|
||||
scheduleA[2] = new Array(4);
|
||||
scheduleA[2][0] = new Array(4, 0, 0xd, 0xf, 0xc, 0xe, 8);
|
||||
scheduleA[2][1] = new Array(5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa);
|
||||
scheduleA[2][2] = new Array(6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9);
|
||||
scheduleA[2][3] = new Array(7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb);
|
||||
|
||||
|
||||
scheduleA[3] = new Array(4);
|
||||
scheduleA[3][0] = new Array(0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0);
|
||||
scheduleA[3][1] = new Array(1, 4, 0, 2, 1, 3, 16 + 2);
|
||||
scheduleA[3][2] = new Array(2, 5, 7, 6, 5, 4, 16 + 1);
|
||||
scheduleA[3][3] = new Array(3, 7, 0xa, 9, 0xb, 8, 16 + 3);
|
||||
|
||||
var scheduleB = new Array(4);
|
||||
|
||||
scheduleB[0] = new Array(4);
|
||||
scheduleB[0][0] = new Array(16 + 8, 16 + 9, 16 + 7, 16 + 6, 16 + 2);
|
||||
scheduleB[0][1] = new Array(16 + 0xa, 16 + 0xb, 16 + 5, 16 + 4, 16 + 6);
|
||||
scheduleB[0][2] = new Array(16 + 0xc, 16 + 0xd, 16 + 3, 16 + 2, 16 + 9);
|
||||
scheduleB[0][3] = new Array(16 + 0xe, 16 + 0xf, 16 + 1, 16 + 0, 16 + 0xc);
|
||||
|
||||
scheduleB[1] = new Array(4);
|
||||
scheduleB[1][0] = new Array(3, 2, 0xc, 0xd, 8);
|
||||
scheduleB[1][1] = new Array(1, 0, 0xe, 0xf, 0xd);
|
||||
scheduleB[1][2] = new Array(7, 6, 8, 9, 3);
|
||||
scheduleB[1][3] = new Array(5, 4, 0xa, 0xb, 7);
|
||||
|
||||
|
||||
scheduleB[2] = new Array(4);
|
||||
scheduleB[2][0] = new Array(16 + 3, 16 + 2, 16 + 0xc, 16 + 0xd, 16 + 9);
|
||||
scheduleB[2][1] = new Array(16 + 1, 16 + 0, 16 + 0xe, 16 + 0xf, 16 + 0xc);
|
||||
scheduleB[2][2] = new Array(16 + 7, 16 + 6, 16 + 8, 16 + 9, 16 + 2);
|
||||
scheduleB[2][3] = new Array(16 + 5, 16 + 4, 16 + 0xa, 16 + 0xb, 16 + 6);
|
||||
|
||||
|
||||
scheduleB[3] = new Array(4);
|
||||
scheduleB[3][0] = new Array(8, 9, 7, 6, 3);
|
||||
scheduleB[3][1] = new Array(0xa, 0xb, 5, 4, 7);
|
||||
scheduleB[3][2] = new Array(0xc, 0xd, 3, 2, 8);
|
||||
scheduleB[3][3] = new Array(0xe, 0xf, 1, 0, 0xd);
|
||||
|
||||
// changed 'in' to 'inn' (in javascript 'in' is a reserved word)
|
||||
this.keySchedule = function(inn)
|
||||
{
|
||||
var t = new Array(8);
|
||||
var k = new Array(32);
|
||||
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
var j = i * 4;
|
||||
t[i] = inn[j]<<24 | inn[j+1]<<16 | inn[j+2]<<8 | inn[j+3];
|
||||
}
|
||||
|
||||
var x = [6, 7, 4, 5];
|
||||
var ki = 0;
|
||||
|
||||
for (var half = 0; half < 2; half++)
|
||||
{
|
||||
for (var round = 0; round < 4; round++)
|
||||
{
|
||||
for (var j = 0; j < 4; j++)
|
||||
{
|
||||
var a = scheduleA[round][j];
|
||||
var w = t[a[1]];
|
||||
|
||||
w ^= sBox[4][(t[a[2]>>>2]>>>(24-8*(a[2]&3)))&0xff];
|
||||
w ^= sBox[5][(t[a[3]>>>2]>>>(24-8*(a[3]&3)))&0xff];
|
||||
w ^= sBox[6][(t[a[4]>>>2]>>>(24-8*(a[4]&3)))&0xff];
|
||||
w ^= sBox[7][(t[a[5]>>>2]>>>(24-8*(a[5]&3)))&0xff];
|
||||
w ^= sBox[x[j]][(t[a[6]>>>2]>>>(24-8*(a[6]&3)))&0xff];
|
||||
t[a[0]] = w;
|
||||
}
|
||||
|
||||
for (var j = 0; j < 4; j++)
|
||||
{
|
||||
var b = scheduleB[round][j];
|
||||
var w = sBox[4][(t[b[0]>>>2]>>>(24-8*(b[0]&3)))&0xff];
|
||||
|
||||
w ^= sBox[5][(t[b[1]>>>2]>>>(24-8*(b[1]&3)))&0xff];
|
||||
w ^= sBox[6][(t[b[2]>>>2]>>>(24-8*(b[2]&3)))&0xff];
|
||||
w ^= sBox[7][(t[b[3]>>>2]>>>(24-8*(b[3]&3)))&0xff];
|
||||
w ^= sBox[4+j][(t[b[4]>>>2]>>>(24-8*(b[4]&3)))&0xff];
|
||||
k[ki] = w;
|
||||
ki++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
this.masking[i] = k[i];
|
||||
this.rotate[i] = k[16+i] & 0x1f;
|
||||
}
|
||||
};
|
||||
|
||||
// These are the three 'f' functions. See RFC 2144, section 2.2.
|
||||
|
||||
function f1(d, m, r)
|
||||
{
|
||||
var t = m + d;
|
||||
var I = (t << r) | (t >>> (32 - r));
|
||||
return ((sBox[0][I>>>24] ^ sBox[1][(I>>>16)&255]) - sBox[2][(I>>>8)&255]) + sBox[3][I&255];
|
||||
}
|
||||
|
||||
function f2(d, m, r)
|
||||
{
|
||||
var t = m ^ d;
|
||||
var I = (t << r) | (t >>> (32 - r));
|
||||
return ((sBox[0][I>>>24] - sBox[1][(I>>>16)&255]) + sBox[2][(I>>>8)&255]) ^ sBox[3][I&255];
|
||||
}
|
||||
|
||||
function f3(d, m, r)
|
||||
{
|
||||
var t = m - d;
|
||||
var I = (t << r) | (t >>> (32 - r));
|
||||
return ((sBox[0][I>>>24] + sBox[1][(I>>>16)&255]) ^ sBox[2][(I>>>8)&255]) - sBox[3][I&255];
|
||||
}
|
||||
|
||||
var sBox = new Array(8);
|
||||
sBox[0] = new Array(
|
||||
0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949,
|
||||
0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
|
||||
0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
|
||||
0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0,
|
||||
0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7,
|
||||
0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,
|
||||
0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d,
|
||||
0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
|
||||
0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,
|
||||
0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3,
|
||||
0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167,
|
||||
0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,
|
||||
0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779,
|
||||
0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2,
|
||||
0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,
|
||||
0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d,
|
||||
0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5,
|
||||
0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324,
|
||||
0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
|
||||
0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,
|
||||
0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d,
|
||||
0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96,
|
||||
0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a,
|
||||
0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
|
||||
0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
|
||||
0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6,
|
||||
0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
|
||||
0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872,
|
||||
0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c,
|
||||
0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,
|
||||
0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9,
|
||||
0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf);
|
||||
|
||||
sBox[1] = new Array(
|
||||
0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651,
|
||||
0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
|
||||
0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,
|
||||
0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
|
||||
0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b,
|
||||
0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,
|
||||
0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b,
|
||||
0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c,
|
||||
0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,
|
||||
0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb,
|
||||
0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd,
|
||||
0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,
|
||||
0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b,
|
||||
0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
|
||||
0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,
|
||||
0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
|
||||
0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c,
|
||||
0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,
|
||||
0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f,
|
||||
0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
|
||||
0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,
|
||||
0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58,
|
||||
0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
|
||||
0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
|
||||
0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6,
|
||||
0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
|
||||
0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,
|
||||
0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f,
|
||||
0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
|
||||
0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
|
||||
0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9,
|
||||
0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1);
|
||||
|
||||
sBox[2] = new Array(
|
||||
0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90,
|
||||
0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5,
|
||||
0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,
|
||||
0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240,
|
||||
0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
|
||||
0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
|
||||
0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71,
|
||||
0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
|
||||
0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
|
||||
0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15,
|
||||
0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2,
|
||||
0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,
|
||||
0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148,
|
||||
0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc,
|
||||
0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
|
||||
0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e,
|
||||
0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
|
||||
0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,
|
||||
0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a,
|
||||
0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b,
|
||||
0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
|
||||
0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
|
||||
0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
|
||||
0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,
|
||||
0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
|
||||
0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
|
||||
0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,
|
||||
0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
|
||||
0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49,
|
||||
0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,
|
||||
0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a,
|
||||
0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783);
|
||||
|
||||
sBox[3] = new Array(
|
||||
0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1,
|
||||
0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf,
|
||||
0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,
|
||||
0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121,
|
||||
0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25,
|
||||
0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
|
||||
0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb,
|
||||
0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5,
|
||||
0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,
|
||||
0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6,
|
||||
0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23,
|
||||
0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,
|
||||
0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
|
||||
0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119,
|
||||
0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
|
||||
0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a,
|
||||
0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79,
|
||||
0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,
|
||||
0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
|
||||
0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab,
|
||||
0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,
|
||||
0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
|
||||
0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2,
|
||||
0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,
|
||||
0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
|
||||
0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919,
|
||||
0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
|
||||
0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
|
||||
0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab,
|
||||
0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,
|
||||
0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282,
|
||||
0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2);
|
||||
|
||||
sBox[4] = new Array(
|
||||
0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f,
|
||||
0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a,
|
||||
0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff,
|
||||
0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02,
|
||||
0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a,
|
||||
0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7,
|
||||
0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9,
|
||||
0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981,
|
||||
0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774,
|
||||
0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655,
|
||||
0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2,
|
||||
0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910,
|
||||
0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1,
|
||||
0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da,
|
||||
0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049,
|
||||
0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f,
|
||||
0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba,
|
||||
0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
|
||||
0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3,
|
||||
0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840,
|
||||
0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4,
|
||||
0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2,
|
||||
0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7,
|
||||
0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5,
|
||||
0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e,
|
||||
0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e,
|
||||
0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801,
|
||||
0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad,
|
||||
0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0,
|
||||
0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20,
|
||||
0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8,
|
||||
0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4);
|
||||
|
||||
sBox[5] = new Array(
|
||||
0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac,
|
||||
0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138,
|
||||
0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367,
|
||||
0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98,
|
||||
0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072,
|
||||
0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
|
||||
0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd,
|
||||
0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8,
|
||||
0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9,
|
||||
0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54,
|
||||
0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387,
|
||||
0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc,
|
||||
0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf,
|
||||
0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf,
|
||||
0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f,
|
||||
0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289,
|
||||
0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950,
|
||||
0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
|
||||
0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b,
|
||||
0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be,
|
||||
0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
|
||||
0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976,
|
||||
0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0,
|
||||
0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891,
|
||||
0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da,
|
||||
0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc,
|
||||
0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084,
|
||||
0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25,
|
||||
0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121,
|
||||
0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
|
||||
0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd,
|
||||
0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f);
|
||||
|
||||
sBox[6] = new Array(
|
||||
0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f,
|
||||
0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de,
|
||||
0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
|
||||
0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19,
|
||||
0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2,
|
||||
0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516,
|
||||
0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88,
|
||||
0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816,
|
||||
0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756,
|
||||
0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a,
|
||||
0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264,
|
||||
0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688,
|
||||
0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28,
|
||||
0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3,
|
||||
0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7,
|
||||
0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06,
|
||||
0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033,
|
||||
0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a,
|
||||
0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566,
|
||||
0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509,
|
||||
0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962,
|
||||
0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e,
|
||||
0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c,
|
||||
0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
|
||||
0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285,
|
||||
0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301,
|
||||
0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be,
|
||||
0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767,
|
||||
0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647,
|
||||
0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914,
|
||||
0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c,
|
||||
0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3);
|
||||
|
||||
sBox[7] = new Array(
|
||||
0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5,
|
||||
0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc,
|
||||
0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd,
|
||||
0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d,
|
||||
0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2,
|
||||
0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862,
|
||||
0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc,
|
||||
0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c,
|
||||
0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e,
|
||||
0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039,
|
||||
0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8,
|
||||
0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42,
|
||||
0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5,
|
||||
0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472,
|
||||
0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225,
|
||||
0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c,
|
||||
0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb,
|
||||
0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054,
|
||||
0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70,
|
||||
0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc,
|
||||
0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
|
||||
0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3,
|
||||
0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4,
|
||||
0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101,
|
||||
0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f,
|
||||
0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e,
|
||||
0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
|
||||
0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c,
|
||||
0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384,
|
||||
0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c,
|
||||
0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82,
|
||||
0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e);
|
||||
|
||||
};
|
||||
|
||||
208
src/ciphers/symmetric/dessrc.js
Executable file
208
src/ciphers/symmetric/dessrc.js
Executable file
@@ -0,0 +1,208 @@
|
||||
//Paul Tero, July 2001
|
||||
//http://www.tero.co.uk/des/
|
||||
//
|
||||
//Optimised for performance with large blocks by Michael Hayworth, November 2001
|
||||
//http://www.netdealing.com
|
||||
//
|
||||
// Modified by Recurity Labs GmbH
|
||||
|
||||
//THIS SOFTWARE IS PROVIDED "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 THE AUTHOR 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.
|
||||
|
||||
//des
|
||||
//this takes the key, the message, and whether to encrypt or decrypt
|
||||
|
||||
// added by Recurity Labs
|
||||
function desede(block,key) {
|
||||
var key1 = key.substring(0,8);
|
||||
var key2 = key.substring(8,16);
|
||||
var key3 = key.substring(16,24);
|
||||
return util.str2bin(des(des_createKeys(key3),des(des_createKeys(key2),des(des_createKeys(key1),util.bin2str(block), true, 0,null,null), false, 0,null,null), true, 0,null,null));
|
||||
}
|
||||
|
||||
|
||||
function des (keys, message, encrypt, mode, iv, padding) {
|
||||
//declaring this locally speeds things up a bit
|
||||
var spfunction1 = new Array (0x1010400,0,0x10000,0x1010404,0x1010004,0x10404,0x4,0x10000,0x400,0x1010400,0x1010404,0x400,0x1000404,0x1010004,0x1000000,0x4,0x404,0x1000400,0x1000400,0x10400,0x10400,0x1010000,0x1010000,0x1000404,0x10004,0x1000004,0x1000004,0x10004,0,0x404,0x10404,0x1000000,0x10000,0x1010404,0x4,0x1010000,0x1010400,0x1000000,0x1000000,0x400,0x1010004,0x10000,0x10400,0x1000004,0x400,0x4,0x1000404,0x10404,0x1010404,0x10004,0x1010000,0x1000404,0x1000004,0x404,0x10404,0x1010400,0x404,0x1000400,0x1000400,0,0x10004,0x10400,0,0x1010004);
|
||||
var spfunction2 = new Array (-0x7fef7fe0,-0x7fff8000,0x8000,0x108020,0x100000,0x20,-0x7fefffe0,-0x7fff7fe0,-0x7fffffe0,-0x7fef7fe0,-0x7fef8000,-0x80000000,-0x7fff8000,0x100000,0x20,-0x7fefffe0,0x108000,0x100020,-0x7fff7fe0,0,-0x80000000,0x8000,0x108020,-0x7ff00000,0x100020,-0x7fffffe0,0,0x108000,0x8020,-0x7fef8000,-0x7ff00000,0x8020,0,0x108020,-0x7fefffe0,0x100000,-0x7fff7fe0,-0x7ff00000,-0x7fef8000,0x8000,-0x7ff00000,-0x7fff8000,0x20,-0x7fef7fe0,0x108020,0x20,0x8000,-0x80000000,0x8020,-0x7fef8000,0x100000,-0x7fffffe0,0x100020,-0x7fff7fe0,-0x7fffffe0,0x100020,0x108000,0,-0x7fff8000,0x8020,-0x80000000,-0x7fefffe0,-0x7fef7fe0,0x108000);
|
||||
var spfunction3 = new Array (0x208,0x8020200,0,0x8020008,0x8000200,0,0x20208,0x8000200,0x20008,0x8000008,0x8000008,0x20000,0x8020208,0x20008,0x8020000,0x208,0x8000000,0x8,0x8020200,0x200,0x20200,0x8020000,0x8020008,0x20208,0x8000208,0x20200,0x20000,0x8000208,0x8,0x8020208,0x200,0x8000000,0x8020200,0x8000000,0x20008,0x208,0x20000,0x8020200,0x8000200,0,0x200,0x20008,0x8020208,0x8000200,0x8000008,0x200,0,0x8020008,0x8000208,0x20000,0x8000000,0x8020208,0x8,0x20208,0x20200,0x8000008,0x8020000,0x8000208,0x208,0x8020000,0x20208,0x8,0x8020008,0x20200);
|
||||
var spfunction4 = new Array (0x802001,0x2081,0x2081,0x80,0x802080,0x800081,0x800001,0x2001,0,0x802000,0x802000,0x802081,0x81,0,0x800080,0x800001,0x1,0x2000,0x800000,0x802001,0x80,0x800000,0x2001,0x2080,0x800081,0x1,0x2080,0x800080,0x2000,0x802080,0x802081,0x81,0x800080,0x800001,0x802000,0x802081,0x81,0,0,0x802000,0x2080,0x800080,0x800081,0x1,0x802001,0x2081,0x2081,0x80,0x802081,0x81,0x1,0x2000,0x800001,0x2001,0x802080,0x800081,0x2001,0x2080,0x800000,0x802001,0x80,0x800000,0x2000,0x802080);
|
||||
var spfunction5 = new Array (0x100,0x2080100,0x2080000,0x42000100,0x80000,0x100,0x40000000,0x2080000,0x40080100,0x80000,0x2000100,0x40080100,0x42000100,0x42080000,0x80100,0x40000000,0x2000000,0x40080000,0x40080000,0,0x40000100,0x42080100,0x42080100,0x2000100,0x42080000,0x40000100,0,0x42000000,0x2080100,0x2000000,0x42000000,0x80100,0x80000,0x42000100,0x100,0x2000000,0x40000000,0x2080000,0x42000100,0x40080100,0x2000100,0x40000000,0x42080000,0x2080100,0x40080100,0x100,0x2000000,0x42080000,0x42080100,0x80100,0x42000000,0x42080100,0x2080000,0,0x40080000,0x42000000,0x80100,0x2000100,0x40000100,0x80000,0,0x40080000,0x2080100,0x40000100);
|
||||
var spfunction6 = new Array (0x20000010,0x20400000,0x4000,0x20404010,0x20400000,0x10,0x20404010,0x400000,0x20004000,0x404010,0x400000,0x20000010,0x400010,0x20004000,0x20000000,0x4010,0,0x400010,0x20004010,0x4000,0x404000,0x20004010,0x10,0x20400010,0x20400010,0,0x404010,0x20404000,0x4010,0x404000,0x20404000,0x20000000,0x20004000,0x10,0x20400010,0x404000,0x20404010,0x400000,0x4010,0x20000010,0x400000,0x20004000,0x20000000,0x4010,0x20000010,0x20404010,0x404000,0x20400000,0x404010,0x20404000,0,0x20400010,0x10,0x4000,0x20400000,0x404010,0x4000,0x400010,0x20004010,0,0x20404000,0x20000000,0x400010,0x20004010);
|
||||
var spfunction7 = new Array (0x200000,0x4200002,0x4000802,0,0x800,0x4000802,0x200802,0x4200800,0x4200802,0x200000,0,0x4000002,0x2,0x4000000,0x4200002,0x802,0x4000800,0x200802,0x200002,0x4000800,0x4000002,0x4200000,0x4200800,0x200002,0x4200000,0x800,0x802,0x4200802,0x200800,0x2,0x4000000,0x200800,0x4000000,0x200800,0x200000,0x4000802,0x4000802,0x4200002,0x4200002,0x2,0x200002,0x4000000,0x4000800,0x200000,0x4200800,0x802,0x200802,0x4200800,0x802,0x4000002,0x4200802,0x4200000,0x200800,0,0x2,0x4200802,0,0x200802,0x4200000,0x800,0x4000002,0x4000800,0x800,0x200002);
|
||||
var spfunction8 = new Array (0x10001040,0x1000,0x40000,0x10041040,0x10000000,0x10001040,0x40,0x10000000,0x40040,0x10040000,0x10041040,0x41000,0x10041000,0x41040,0x1000,0x40,0x10040000,0x10000040,0x10001000,0x1040,0x41000,0x40040,0x10040040,0x10041000,0x1040,0,0,0x10040040,0x10000040,0x10001000,0x41040,0x40000,0x41040,0x40000,0x10041000,0x1000,0x40,0x10040040,0x1000,0x41040,0x10001000,0x40,0x10000040,0x10040000,0x10040040,0x10000000,0x40000,0x10001040,0,0x10041040,0x40040,0x10000040,0x10040000,0x10001000,0x10001040,0,0x10041040,0x41000,0x41000,0x1040,0x1040,0x40040,0x10000000,0x10041000);
|
||||
|
||||
//create the 16 or 48 subkeys we will need
|
||||
var m=0, i, j, temp, temp2, right1, right2, left, right, looping;
|
||||
var cbcleft, cbcleft2, cbcright, cbcright2
|
||||
var endloop, loopinc;
|
||||
var len = message.length;
|
||||
var chunk = 0;
|
||||
//set up the loops for single and triple des
|
||||
var iterations = keys.length == 32 ? 3 : 9; //single or triple des
|
||||
if (iterations == 3) {looping = encrypt ? new Array (0, 32, 2) : new Array (30, -2, -2);}
|
||||
else {looping = encrypt ? new Array (0, 32, 2, 62, 30, -2, 64, 96, 2) : new Array (94, 62, -2, 32, 64, 2, 30, -2, -2);}
|
||||
|
||||
//pad the message depending on the padding parameter
|
||||
if (padding == 2) message += " "; //pad the message with spaces
|
||||
else if (padding == 1) {temp = 8-(len%8); message += String.fromCharCode (temp,temp,temp,temp,temp,temp,temp,temp); if (temp==8) len+=8;} //PKCS7 padding
|
||||
else if (!padding) message += "\0\0\0\0\0\0\0\0"; //pad the message out with null bytes
|
||||
|
||||
//store the result here
|
||||
result = "";
|
||||
tempresult = "";
|
||||
|
||||
if (mode == 1) { //CBC mode
|
||||
cbcleft = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++);
|
||||
cbcright = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++);
|
||||
m=0;
|
||||
}
|
||||
|
||||
//loop through each 64 bit chunk of the message
|
||||
while (m < len) {
|
||||
left = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) | message.charCodeAt(m++);
|
||||
right = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) | message.charCodeAt(m++);
|
||||
|
||||
//for Cipher Block Chaining mode, xor the message with the previous result
|
||||
if (mode == 1) {if (encrypt) {left ^= cbcleft; right ^= cbcright;} else {cbcleft2 = cbcleft; cbcright2 = cbcright; cbcleft = left; cbcright = right;}}
|
||||
|
||||
//first each 64 but chunk of the message must be permuted according to IP
|
||||
temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4);
|
||||
temp = ((left >>> 16) ^ right) & 0x0000ffff; right ^= temp; left ^= (temp << 16);
|
||||
temp = ((right >>> 2) ^ left) & 0x33333333; left ^= temp; right ^= (temp << 2);
|
||||
temp = ((right >>> 8) ^ left) & 0x00ff00ff; left ^= temp; right ^= (temp << 8);
|
||||
temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1);
|
||||
|
||||
left = ((left << 1) | (left >>> 31));
|
||||
right = ((right << 1) | (right >>> 31));
|
||||
|
||||
//do this either 1 or 3 times for each chunk of the message
|
||||
for (j=0; j<iterations; j+=3) {
|
||||
endloop = looping[j+1];
|
||||
loopinc = looping[j+2];
|
||||
//now go through and perform the encryption or decryption
|
||||
for (i=looping[j]; i!=endloop; i+=loopinc) { //for efficiency
|
||||
right1 = right ^ keys[i];
|
||||
right2 = ((right >>> 4) | (right << 28)) ^ keys[i+1];
|
||||
//the result is attained by passing these bytes through the S selection functions
|
||||
temp = left;
|
||||
left = right;
|
||||
right = temp ^ (spfunction2[(right1 >>> 24) & 0x3f] | spfunction4[(right1 >>> 16) & 0x3f]
|
||||
| spfunction6[(right1 >>> 8) & 0x3f] | spfunction8[right1 & 0x3f]
|
||||
| spfunction1[(right2 >>> 24) & 0x3f] | spfunction3[(right2 >>> 16) & 0x3f]
|
||||
| spfunction5[(right2 >>> 8) & 0x3f] | spfunction7[right2 & 0x3f]);
|
||||
}
|
||||
temp = left; left = right; right = temp; //unreverse left and right
|
||||
} //for either 1 or 3 iterations
|
||||
|
||||
//move then each one bit to the right
|
||||
left = ((left >>> 1) | (left << 31));
|
||||
right = ((right >>> 1) | (right << 31));
|
||||
|
||||
//now perform IP-1, which is IP in the opposite direction
|
||||
temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1);
|
||||
temp = ((right >>> 8) ^ left) & 0x00ff00ff; left ^= temp; right ^= (temp << 8);
|
||||
temp = ((right >>> 2) ^ left) & 0x33333333; left ^= temp; right ^= (temp << 2);
|
||||
temp = ((left >>> 16) ^ right) & 0x0000ffff; right ^= temp; left ^= (temp << 16);
|
||||
temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4);
|
||||
|
||||
//for Cipher Block Chaining mode, xor the message with the previous result
|
||||
if (mode == 1) {if (encrypt) {cbcleft = left; cbcright = right;} else {left ^= cbcleft2; right ^= cbcright2;}}
|
||||
tempresult += String.fromCharCode ((left>>>24), ((left>>>16) & 0xff), ((left>>>8) & 0xff), (left & 0xff), (right>>>24), ((right>>>16) & 0xff), ((right>>>8) & 0xff), (right & 0xff));
|
||||
|
||||
chunk += 8;
|
||||
if (chunk == 512) {result += tempresult; tempresult = ""; chunk = 0;}
|
||||
} //for every 8 characters, or 64 bits in the message
|
||||
|
||||
//return the result as an array
|
||||
result += tempresult;
|
||||
result = result.replace(/\0*$/g, "");
|
||||
return result;
|
||||
} //end of des
|
||||
|
||||
|
||||
|
||||
//des_createKeys
|
||||
//this takes as input a 64 bit key (even though only 56 bits are used)
|
||||
//as an array of 2 integers, and returns 16 48 bit keys
|
||||
function des_createKeys (key) {
|
||||
//declaring this locally speeds things up a bit
|
||||
pc2bytes0 = new Array (0,0x4,0x20000000,0x20000004,0x10000,0x10004,0x20010000,0x20010004,0x200,0x204,0x20000200,0x20000204,0x10200,0x10204,0x20010200,0x20010204);
|
||||
pc2bytes1 = new Array (0,0x1,0x100000,0x100001,0x4000000,0x4000001,0x4100000,0x4100001,0x100,0x101,0x100100,0x100101,0x4000100,0x4000101,0x4100100,0x4100101);
|
||||
pc2bytes2 = new Array (0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808,0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808);
|
||||
pc2bytes3 = new Array (0,0x200000,0x8000000,0x8200000,0x2000,0x202000,0x8002000,0x8202000,0x20000,0x220000,0x8020000,0x8220000,0x22000,0x222000,0x8022000,0x8222000);
|
||||
pc2bytes4 = new Array (0,0x40000,0x10,0x40010,0,0x40000,0x10,0x40010,0x1000,0x41000,0x1010,0x41010,0x1000,0x41000,0x1010,0x41010);
|
||||
pc2bytes5 = new Array (0,0x400,0x20,0x420,0,0x400,0x20,0x420,0x2000000,0x2000400,0x2000020,0x2000420,0x2000000,0x2000400,0x2000020,0x2000420);
|
||||
pc2bytes6 = new Array (0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002,0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002);
|
||||
pc2bytes7 = new Array (0,0x10000,0x800,0x10800,0x20000000,0x20010000,0x20000800,0x20010800,0x20000,0x30000,0x20800,0x30800,0x20020000,0x20030000,0x20020800,0x20030800);
|
||||
pc2bytes8 = new Array (0,0x40000,0,0x40000,0x2,0x40002,0x2,0x40002,0x2000000,0x2040000,0x2000000,0x2040000,0x2000002,0x2040002,0x2000002,0x2040002);
|
||||
pc2bytes9 = new Array (0,0x10000000,0x8,0x10000008,0,0x10000000,0x8,0x10000008,0x400,0x10000400,0x408,0x10000408,0x400,0x10000400,0x408,0x10000408);
|
||||
pc2bytes10 = new Array (0,0x20,0,0x20,0x100000,0x100020,0x100000,0x100020,0x2000,0x2020,0x2000,0x2020,0x102000,0x102020,0x102000,0x102020);
|
||||
pc2bytes11 = new Array (0,0x1000000,0x200,0x1000200,0x200000,0x1200000,0x200200,0x1200200,0x4000000,0x5000000,0x4000200,0x5000200,0x4200000,0x5200000,0x4200200,0x5200200);
|
||||
pc2bytes12 = new Array (0,0x1000,0x8000000,0x8001000,0x80000,0x81000,0x8080000,0x8081000,0x10,0x1010,0x8000010,0x8001010,0x80010,0x81010,0x8080010,0x8081010);
|
||||
pc2bytes13 = new Array (0,0x4,0x100,0x104,0,0x4,0x100,0x104,0x1,0x5,0x101,0x105,0x1,0x5,0x101,0x105);
|
||||
|
||||
//how many iterations (1 for des, 3 for triple des)
|
||||
var iterations = key.length > 8 ? 3 : 1; //changed by Paul 16/6/2007 to use Triple DES for 9+ byte keys
|
||||
//stores the return keys
|
||||
var keys = new Array (32 * iterations);
|
||||
//now define the left shifts which need to be done
|
||||
var shifts = new Array (0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0);
|
||||
//other variables
|
||||
var lefttemp, righttemp, m=0, n=0, temp;
|
||||
|
||||
for (var j=0; j<iterations; j++) { //either 1 or 3 iterations
|
||||
left = (key.charCodeAt(m++) << 24) | (key.charCodeAt(m++) << 16) | (key.charCodeAt(m++) << 8) | key.charCodeAt(m++);
|
||||
right = (key.charCodeAt(m++) << 24) | (key.charCodeAt(m++) << 16) | (key.charCodeAt(m++) << 8) | key.charCodeAt(m++);
|
||||
|
||||
temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4);
|
||||
temp = ((right >>> -16) ^ left) & 0x0000ffff; left ^= temp; right ^= (temp << -16);
|
||||
temp = ((left >>> 2) ^ right) & 0x33333333; right ^= temp; left ^= (temp << 2);
|
||||
temp = ((right >>> -16) ^ left) & 0x0000ffff; left ^= temp; right ^= (temp << -16);
|
||||
temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1);
|
||||
temp = ((right >>> 8) ^ left) & 0x00ff00ff; left ^= temp; right ^= (temp << 8);
|
||||
temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1);
|
||||
|
||||
//the right side needs to be shifted and to get the last four bits of the left side
|
||||
temp = (left << 8) | ((right >>> 20) & 0x000000f0);
|
||||
//left needs to be put upside down
|
||||
left = (right << 24) | ((right << 8) & 0xff0000) | ((right >>> 8) & 0xff00) | ((right >>> 24) & 0xf0);
|
||||
right = temp;
|
||||
|
||||
//now go through and perform these shifts on the left and right keys
|
||||
for (i=0; i < shifts.length; i++) {
|
||||
//shift the keys either one or two bits to the left
|
||||
if (shifts[i]) {left = (left << 2) | (left >>> 26); right = (right << 2) | (right >>> 26);}
|
||||
else {left = (left << 1) | (left >>> 27); right = (right << 1) | (right >>> 27);}
|
||||
left &= -0xf; right &= -0xf;
|
||||
|
||||
//now apply PC-2, in such a way that E is easier when encrypting or decrypting
|
||||
//this conversion will look like PC-2 except only the last 6 bits of each byte are used
|
||||
//rather than 48 consecutive bits and the order of lines will be according to
|
||||
//how the S selection functions will be applied: S2, S4, S6, S8, S1, S3, S5, S7
|
||||
lefttemp = pc2bytes0[left >>> 28] | pc2bytes1[(left >>> 24) & 0xf]
|
||||
| pc2bytes2[(left >>> 20) & 0xf] | pc2bytes3[(left >>> 16) & 0xf]
|
||||
| pc2bytes4[(left >>> 12) & 0xf] | pc2bytes5[(left >>> 8) & 0xf]
|
||||
| pc2bytes6[(left >>> 4) & 0xf];
|
||||
righttemp = pc2bytes7[right >>> 28] | pc2bytes8[(right >>> 24) & 0xf]
|
||||
| pc2bytes9[(right >>> 20) & 0xf] | pc2bytes10[(right >>> 16) & 0xf]
|
||||
| pc2bytes11[(right >>> 12) & 0xf] | pc2bytes12[(right >>> 8) & 0xf]
|
||||
| pc2bytes13[(right >>> 4) & 0xf];
|
||||
temp = ((righttemp >>> 16) ^ lefttemp) & 0x0000ffff;
|
||||
keys[n++] = lefttemp ^ temp; keys[n++] = righttemp ^ (temp << 16);
|
||||
}
|
||||
} //for each iterations
|
||||
//return the keys we've created
|
||||
return keys;
|
||||
} //end of des_createKeys
|
||||
|
||||
|
||||
302
src/ciphers/symmetric/twofish.js
Executable file
302
src/ciphers/symmetric/twofish.js
Executable file
@@ -0,0 +1,302 @@
|
||||
/* Modified by Recurity Labs GmbH
|
||||
*
|
||||
* Cipher.js
|
||||
* A block-cipher algorithm implementation on JavaScript
|
||||
* See Cipher.readme.txt for further information.
|
||||
*
|
||||
* Copyright(c) 2009 Atsushi Oka [ http://oka.nu/ ]
|
||||
* This script file is distributed under the LGPL
|
||||
*
|
||||
* ACKNOWLEDGMENT
|
||||
*
|
||||
* The main subroutines are written by Michiel van Everdingen.
|
||||
*
|
||||
* Michiel van Everdingen
|
||||
* http://home.versatel.nl/MAvanEverdingen/index.html
|
||||
*
|
||||
* All rights for these routines are reserved to Michiel van Everdingen.
|
||||
*
|
||||
*/
|
||||
|
||||
// added by Recurity Labs
|
||||
function TFencrypt(block, key) {
|
||||
var block_copy = [].concat(block);
|
||||
var tf = createTwofish();
|
||||
tf.open(util.str2bin(key),0);
|
||||
var result = tf.encrypt(block_copy, 0);
|
||||
tf.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//Math
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var MAXINT = 0xFFFFFFFF;
|
||||
|
||||
function rotb(b,n){ return ( b<<n | b>>>( 8-n) ) & 0xFF; }
|
||||
function rotw(w,n){ return ( w<<n | w>>>(32-n) ) & MAXINT; }
|
||||
function getW(a,i){ return a[i]|a[i+1]<<8|a[i+2]<<16|a[i+3]<<24; }
|
||||
function setW(a,i,w){ a.splice(i,4,w&0xFF,(w>>>8)&0xFF,(w>>>16)&0xFF,(w>>>24)&0xFF); }
|
||||
function setWInv(a,i,w){ a.splice(i,4,(w>>>24)&0xFF,(w>>>16)&0xFF,(w>>>8)&0xFF,w&0xFF); }
|
||||
function getB(x,n){ return (x>>>(n*8))&0xFF; }
|
||||
|
||||
function getNrBits(i){ var n=0; while (i>0){ n++; i>>>=1; } return n; }
|
||||
function getMask(n){ return (1<<n)-1; }
|
||||
|
||||
//added 2008/11/13 XXX MUST USE ONE-WAY HASH FUNCTION FOR SECURITY REASON
|
||||
function randByte() {
|
||||
return Math.floor( Math.random() * 256 );
|
||||
}
|
||||
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Twofish
|
||||
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function createTwofish() {
|
||||
//
|
||||
var keyBytes = null;
|
||||
var dataBytes = null;
|
||||
var dataOffset = -1;
|
||||
// var dataLength = -1;
|
||||
var algorithmName = null;
|
||||
// var idx2 = -1;
|
||||
//
|
||||
|
||||
algorithmName = "twofish";
|
||||
|
||||
var tfsKey = [];
|
||||
var tfsM = [ [], [], [], [] ];
|
||||
|
||||
function tfsInit(key) {
|
||||
keyBytes = key;
|
||||
var i, a, b, c, d, meKey = [], moKey = [], inKey = [];
|
||||
var kLen;
|
||||
var sKey = [];
|
||||
var f01, f5b, fef;
|
||||
|
||||
var q0 = [ [ 8, 1, 7, 13, 6, 15, 3, 2, 0, 11, 5, 9, 14, 12, 10, 4 ],
|
||||
[ 2, 8, 11, 13, 15, 7, 6, 14, 3, 1, 9, 4, 0, 10, 12, 5 ] ];
|
||||
var q1 = [ [ 14, 12, 11, 8, 1, 2, 3, 5, 15, 4, 10, 6, 7, 0, 9, 13 ],
|
||||
[ 1, 14, 2, 11, 4, 12, 3, 7, 6, 13, 10, 5, 15, 9, 0, 8 ] ];
|
||||
var q2 = [ [ 11, 10, 5, 14, 6, 13, 9, 0, 12, 8, 15, 3, 2, 4, 7, 1 ],
|
||||
[ 4, 12, 7, 5, 1, 6, 9, 10, 0, 14, 13, 8, 2, 11, 3, 15 ] ];
|
||||
var q3 = [ [ 13, 7, 15, 4, 1, 2, 6, 14, 9, 11, 3, 0, 8, 5, 12, 10 ],
|
||||
[ 11, 9, 5, 1, 12, 3, 13, 14, 6, 4, 7, 15, 2, 0, 8, 10 ] ];
|
||||
var ror4 = [ 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15 ];
|
||||
var ashx = [ 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 5, 14, 7 ];
|
||||
var q = [ [], [] ];
|
||||
var m = [ [], [], [], [] ];
|
||||
|
||||
function ffm5b(x) {
|
||||
return x ^ (x >> 2) ^ [ 0, 90, 180, 238 ][x & 3];
|
||||
}
|
||||
function ffmEf(x) {
|
||||
return x ^ (x >> 1) ^ (x >> 2) ^ [ 0, 238, 180, 90 ][x & 3];
|
||||
}
|
||||
|
||||
function mdsRem(p, q) {
|
||||
var i, t, u;
|
||||
for (i = 0; i < 8; i++) {
|
||||
t = q >>> 24;
|
||||
q = ((q << 8) & MAXINT) | p >>> 24;
|
||||
p = (p << 8) & MAXINT;
|
||||
u = t << 1;
|
||||
if (t & 128) {
|
||||
u ^= 333;
|
||||
}
|
||||
q ^= t ^ (u << 16);
|
||||
u ^= t >>> 1;
|
||||
if (t & 1) {
|
||||
u ^= 166;
|
||||
}
|
||||
q ^= u << 24 | u << 8;
|
||||
}
|
||||
return q;
|
||||
}
|
||||
|
||||
function qp(n, x) {
|
||||
var a, b, c, d;
|
||||
a = x >> 4;
|
||||
b = x & 15;
|
||||
c = q0[n][a ^ b];
|
||||
d = q1[n][ror4[b] ^ ashx[a]];
|
||||
return q3[n][ror4[d] ^ ashx[c]] << 4 | q2[n][c ^ d];
|
||||
}
|
||||
|
||||
function hFun(x, key) {
|
||||
var a = getB(x, 0), b = getB(x, 1), c = getB(x, 2), d = getB(x, 3);
|
||||
switch (kLen) {
|
||||
case 4:
|
||||
a = q[1][a] ^ getB(key[3], 0);
|
||||
b = q[0][b] ^ getB(key[3], 1);
|
||||
c = q[0][c] ^ getB(key[3], 2);
|
||||
d = q[1][d] ^ getB(key[3], 3);
|
||||
case 3:
|
||||
a = q[1][a] ^ getB(key[2], 0);
|
||||
b = q[1][b] ^ getB(key[2], 1);
|
||||
c = q[0][c] ^ getB(key[2], 2);
|
||||
d = q[0][d] ^ getB(key[2], 3);
|
||||
case 2:
|
||||
a = q[0][q[0][a] ^ getB(key[1], 0)] ^ getB(key[0], 0);
|
||||
b = q[0][q[1][b] ^ getB(key[1], 1)] ^ getB(key[0], 1);
|
||||
c = q[1][q[0][c] ^ getB(key[1], 2)] ^ getB(key[0], 2);
|
||||
d = q[1][q[1][d] ^ getB(key[1], 3)] ^ getB(key[0], 3);
|
||||
}
|
||||
return m[0][a] ^ m[1][b] ^ m[2][c] ^ m[3][d];
|
||||
}
|
||||
|
||||
keyBytes = keyBytes.slice(0, 32);
|
||||
i = keyBytes.length;
|
||||
while (i != 16 && i != 24 && i != 32)
|
||||
keyBytes[i++] = 0;
|
||||
|
||||
for (i = 0; i < keyBytes.length; i += 4) {
|
||||
inKey[i >> 2] = getW(keyBytes, i);
|
||||
}
|
||||
for (i = 0; i < 256; i++) {
|
||||
q[0][i] = qp(0, i);
|
||||
q[1][i] = qp(1, i);
|
||||
}
|
||||
for (i = 0; i < 256; i++) {
|
||||
f01 = q[1][i];
|
||||
f5b = ffm5b(f01);
|
||||
fef = ffmEf(f01);
|
||||
m[0][i] = f01 + (f5b << 8) + (fef << 16) + (fef << 24);
|
||||
m[2][i] = f5b + (fef << 8) + (f01 << 16) + (fef << 24);
|
||||
f01 = q[0][i];
|
||||
f5b = ffm5b(f01);
|
||||
fef = ffmEf(f01);
|
||||
m[1][i] = fef + (fef << 8) + (f5b << 16) + (f01 << 24);
|
||||
m[3][i] = f5b + (f01 << 8) + (fef << 16) + (f5b << 24);
|
||||
}
|
||||
|
||||
kLen = inKey.length / 2;
|
||||
for (i = 0; i < kLen; i++) {
|
||||
a = inKey[i + i];
|
||||
meKey[i] = a;
|
||||
b = inKey[i + i + 1];
|
||||
moKey[i] = b;
|
||||
sKey[kLen - i - 1] = mdsRem(a, b);
|
||||
}
|
||||
for (i = 0; i < 40; i += 2) {
|
||||
a = 0x1010101 * i;
|
||||
b = a + 0x1010101;
|
||||
a = hFun(a, meKey);
|
||||
b = rotw(hFun(b, moKey), 8);
|
||||
tfsKey[i] = (a + b) & MAXINT;
|
||||
tfsKey[i + 1] = rotw(a + 2 * b, 9);
|
||||
}
|
||||
for (i = 0; i < 256; i++) {
|
||||
a = b = c = d = i;
|
||||
switch (kLen) {
|
||||
case 4:
|
||||
a = q[1][a] ^ getB(sKey[3], 0);
|
||||
b = q[0][b] ^ getB(sKey[3], 1);
|
||||
c = q[0][c] ^ getB(sKey[3], 2);
|
||||
d = q[1][d] ^ getB(sKey[3], 3);
|
||||
case 3:
|
||||
a = q[1][a] ^ getB(sKey[2], 0);
|
||||
b = q[1][b] ^ getB(sKey[2], 1);
|
||||
c = q[0][c] ^ getB(sKey[2], 2);
|
||||
d = q[0][d] ^ getB(sKey[2], 3);
|
||||
case 2:
|
||||
tfsM[0][i] = m[0][q[0][q[0][a] ^ getB(sKey[1], 0)]
|
||||
^ getB(sKey[0], 0)];
|
||||
tfsM[1][i] = m[1][q[0][q[1][b] ^ getB(sKey[1], 1)]
|
||||
^ getB(sKey[0], 1)];
|
||||
tfsM[2][i] = m[2][q[1][q[0][c] ^ getB(sKey[1], 2)]
|
||||
^ getB(sKey[0], 2)];
|
||||
tfsM[3][i] = m[3][q[1][q[1][d] ^ getB(sKey[1], 3)]
|
||||
^ getB(sKey[0], 3)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function tfsG0(x) {
|
||||
return tfsM[0][getB(x, 0)] ^ tfsM[1][getB(x, 1)] ^ tfsM[2][getB(x, 2)]
|
||||
^ tfsM[3][getB(x, 3)];
|
||||
}
|
||||
function tfsG1(x) {
|
||||
return tfsM[0][getB(x, 3)] ^ tfsM[1][getB(x, 0)] ^ tfsM[2][getB(x, 1)]
|
||||
^ tfsM[3][getB(x, 2)];
|
||||
}
|
||||
|
||||
function tfsFrnd(r, blk) {
|
||||
var a = tfsG0(blk[0]);
|
||||
var b = tfsG1(blk[1]);
|
||||
blk[2] = rotw(blk[2] ^ (a + b + tfsKey[4 * r + 8]) & MAXINT, 31);
|
||||
blk[3] = rotw(blk[3], 1) ^ (a + 2 * b + tfsKey[4 * r + 9]) & MAXINT;
|
||||
a = tfsG0(blk[2]);
|
||||
b = tfsG1(blk[3]);
|
||||
blk[0] = rotw(blk[0] ^ (a + b + tfsKey[4 * r + 10]) & MAXINT, 31);
|
||||
blk[1] = rotw(blk[1], 1) ^ (a + 2 * b + tfsKey[4 * r + 11]) & MAXINT;
|
||||
}
|
||||
|
||||
function tfsIrnd(i, blk) {
|
||||
var a = tfsG0(blk[0]);
|
||||
var b = tfsG1(blk[1]);
|
||||
blk[2] = rotw(blk[2], 1) ^ (a + b + tfsKey[4 * i + 10]) & MAXINT;
|
||||
blk[3] = rotw(blk[3] ^ (a + 2 * b + tfsKey[4 * i + 11]) & MAXINT, 31);
|
||||
a = tfsG0(blk[2]);
|
||||
b = tfsG1(blk[3]);
|
||||
blk[0] = rotw(blk[0], 1) ^ (a + b + tfsKey[4 * i + 8]) & MAXINT;
|
||||
blk[1] = rotw(blk[1] ^ (a + 2 * b + tfsKey[4 * i + 9]) & MAXINT, 31);
|
||||
}
|
||||
|
||||
function tfsClose() {
|
||||
tfsKey = [];
|
||||
tfsM = [ [], [], [], [] ];
|
||||
}
|
||||
|
||||
function tfsEncrypt(data, offset) {
|
||||
dataBytes = data;
|
||||
dataOffset = offset;
|
||||
var blk = [ getW(dataBytes, dataOffset) ^ tfsKey[0],
|
||||
getW(dataBytes, dataOffset + 4) ^ tfsKey[1],
|
||||
getW(dataBytes, dataOffset + 8) ^ tfsKey[2],
|
||||
getW(dataBytes, dataOffset + 12) ^ tfsKey[3] ];
|
||||
for ( var j = 0; j < 8; j++) {
|
||||
tfsFrnd(j, blk);
|
||||
}
|
||||
setW(dataBytes, dataOffset, blk[2] ^ tfsKey[4]);
|
||||
setW(dataBytes, dataOffset + 4, blk[3] ^ tfsKey[5]);
|
||||
setW(dataBytes, dataOffset + 8, blk[0] ^ tfsKey[6]);
|
||||
setW(dataBytes, dataOffset + 12, blk[1] ^ tfsKey[7]);
|
||||
dataOffset += 16;
|
||||
return dataBytes;
|
||||
}
|
||||
|
||||
function tfsDecrypt(data, offset) {
|
||||
dataBytes = data;
|
||||
dataOffset = offset;
|
||||
var blk = [ getW(dataBytes, dataOffset) ^ tfsKey[4],
|
||||
getW(dataBytes, dataOffset + 4) ^ tfsKey[5],
|
||||
getW(dataBytes, dataOffset + 8) ^ tfsKey[6],
|
||||
getW(dataBytes, dataOffset + 12) ^ tfsKey[7] ];
|
||||
for ( var j = 7; j >= 0; j--) {
|
||||
tfsIrnd(j, blk);
|
||||
}
|
||||
setW(dataBytes, dataOffset, blk[2] ^ tfsKey[0]);
|
||||
setW(dataBytes, dataOffset + 4, blk[3] ^ tfsKey[1]);
|
||||
setW(dataBytes, dataOffset + 8, blk[0] ^ tfsKey[2]);
|
||||
setW(dataBytes, dataOffset + 12, blk[1] ^ tfsKey[3]);
|
||||
dataOffset += 16;
|
||||
}
|
||||
|
||||
// added by Recurity Labs
|
||||
function tfsFinal() {
|
||||
return dataBytes;
|
||||
}
|
||||
|
||||
return {
|
||||
name : "twofish",
|
||||
blocksize : 128 / 8,
|
||||
open : tfsInit,
|
||||
close : tfsClose,
|
||||
encrypt : tfsEncrypt,
|
||||
decrypt : tfsDecrypt,
|
||||
// added by Recurity Labs
|
||||
finalize: tfsFinal
|
||||
};
|
||||
}
|
||||
|
||||
78
src/config/openpgp.config.js
Executable file
78
src/config/openpgp.config.js
Executable file
@@ -0,0 +1,78 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* Implementation of the GPG4Browsers config object
|
||||
*
|
||||
* This object contains configuration values and implements
|
||||
* storing and retrieving configuration them from HTML5 local storage.
|
||||
*
|
||||
* This object can be accessed after calling openpgp.init()
|
||||
* using openpgp.config
|
||||
* Stored config parameters can be accessed using
|
||||
* openpgp.config.config
|
||||
*/
|
||||
function openpgp_config() {
|
||||
this.config = null;
|
||||
|
||||
/**
|
||||
* the default config object which is used if no
|
||||
* configuration was in place
|
||||
*/
|
||||
this.default_config = {
|
||||
prefer_hash_algorithm: 2,
|
||||
encryption_cipher: 9,
|
||||
compression: 1,
|
||||
show_version: true,
|
||||
integrity_protect: true,
|
||||
composition_behavior: 0,
|
||||
keyserver: "keyserver.linux.it" // "pgp.mit.edu:11371"
|
||||
};
|
||||
|
||||
this.versionstring ="GPG4Browsers 0.1";
|
||||
/**
|
||||
* reads the config out of the HTML5 local storage
|
||||
* and initializes the object config.
|
||||
* if config is null the default config will be used
|
||||
* @return [void]
|
||||
*/
|
||||
function read() {
|
||||
var cf = JSON.parse(window.localStorage.getItem("config"));
|
||||
if (cf == null) {
|
||||
this.config = this.default_config;
|
||||
this.write();
|
||||
}
|
||||
else
|
||||
this.config = cf;
|
||||
}
|
||||
|
||||
/**
|
||||
* if enabled, debug messages will be printed
|
||||
*/
|
||||
this.debug = false;
|
||||
|
||||
/**
|
||||
* writes the config to HTML5 local storage
|
||||
* @return [void]
|
||||
*/
|
||||
function write() {
|
||||
window.localStorage.setItem("config",JSON.stringify(this.config));
|
||||
}
|
||||
|
||||
this.read = read;
|
||||
this.write = write;
|
||||
}
|
||||
76
src/encoding/base64.js
Executable file
76
src/encoding/base64.js
Executable file
@@ -0,0 +1,76 @@
|
||||
/* OpenPGP radix-64/base64 string encoding/decoding
|
||||
* Copyright 2005 Herbert Hanewinkel, www.haneWIN.de
|
||||
* version 1.0, check www.haneWIN.de for the latest version
|
||||
*
|
||||
* This software is provided as-is, without express or implied warranty.
|
||||
* Permission to use, copy, modify, distribute or sell this software, with or
|
||||
* without fee, for any purpose and by any individual or organization, is hereby
|
||||
* granted, provided that the above copyright notice and this paragraph appear
|
||||
* in all copies. Distribution as a part of an application or binary must
|
||||
* include the above copyright notice in the documentation and/or other materials
|
||||
* provided with the application or distribution.
|
||||
*/
|
||||
|
||||
var b64s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||
|
||||
function s2r(t) {
|
||||
var a, c, n;
|
||||
var r = '', l = 0, s = 0;
|
||||
var tl = t.length;
|
||||
|
||||
for (n = 0; n < tl; n++) {
|
||||
c = t.charCodeAt(n);
|
||||
if (s == 0) {
|
||||
r += b64s.charAt((c >> 2) & 63);
|
||||
a = (c & 3) << 4;
|
||||
} else if (s == 1) {
|
||||
r += b64s.charAt((a | (c >> 4) & 15));
|
||||
a = (c & 15) << 2;
|
||||
} else if (s == 2) {
|
||||
r += b64s.charAt(a | ((c >> 6) & 3));
|
||||
l += 1;
|
||||
if ((l % 60) == 0)
|
||||
r += "\n";
|
||||
r += b64s.charAt(c & 63);
|
||||
}
|
||||
l += 1;
|
||||
if ((l % 60) == 0)
|
||||
r += "\n";
|
||||
|
||||
s += 1;
|
||||
if (s == 3)
|
||||
s = 0;
|
||||
}
|
||||
if (s > 0) {
|
||||
r += b64s.charAt(a);
|
||||
l += 1;
|
||||
if ((l % 60) == 0)
|
||||
r += "\n";
|
||||
r += '=';
|
||||
l += 1;
|
||||
}
|
||||
if (s == 1) {
|
||||
if ((l % 60) == 0)
|
||||
r += "\n";
|
||||
r += '=';
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
function r2s(t) {
|
||||
var c, n;
|
||||
var r = '', s = 0, a = 0;
|
||||
var tl = t.length;
|
||||
|
||||
for (n = 0; n < tl; n++) {
|
||||
c = b64s.indexOf(t.charAt(n));
|
||||
if (c >= 0) {
|
||||
if (s)
|
||||
r += String.fromCharCode(a | (c >> (6 - s)) & 255);
|
||||
s = (s + 2) & 7;
|
||||
a = (c << s) & 255;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
230
src/encoding/openpgp.encoding.asciiarmor.js
Executable file
230
src/encoding/openpgp.encoding.asciiarmor.js
Executable file
@@ -0,0 +1,230 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* DeArmor an OpenPGP armored message; verify the checksum and return the encoded bytes
|
||||
* @text [String] OpenPGP armored message
|
||||
* @return either the bytes of the decoded message or an object with attribute "text" containing the message text
|
||||
* and an attribute "openpgp" containing the bytes.
|
||||
*/
|
||||
function openpgp_encoding_deArmor(text) {
|
||||
var type = getPGPMessageType(text);
|
||||
if (type != 2) {
|
||||
var splittedtext = text.split('-----');
|
||||
data = { openpgp: openpgp_encoding_base64_decode(splittedtext[2].split('\n\n')[1].split("\n=")[0].replace(/\n- /g,"\n")),
|
||||
type: type};
|
||||
if (verifyCheckSum(data.openpgp, splittedtext[2].split('\n\n')[1].split("\n=")[1].split('\n')[0]))
|
||||
return data;
|
||||
else
|
||||
util.print_error("Ascii armor integrity check on message failed: '"+splittedtext[2].split('\n\n')[1].split("\n=")[1].split('\n')[0]+"' should be '"+getCheckSum(data))+"'";
|
||||
} else {
|
||||
var splittedtext = text.split('-----');
|
||||
var result = { text: splittedtext[2].replace(/\n- /g,"\n").split("\n\n")[1],
|
||||
openpgp: openpgp_encoding_base64_decode(splittedtext[4].split("\n\n")[1].split("\n=")[0]),
|
||||
type: type};
|
||||
if (verifyCheckSum(result.openpgp, splittedtext[4].split("\n\n")[1].split("\n=")[1]))
|
||||
return result;
|
||||
else
|
||||
util.print_error("Ascii armor integrity check on message failed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds out which Ascii Armoring type is used. This is an internal function
|
||||
* @param text [String] ascii armored text
|
||||
* @return 0 = MESSAGE PART n of m
|
||||
* 1 = MESSAGE PART n
|
||||
* 2 = SIGNED MESSAGE
|
||||
* 3 = PGP MESSAGE
|
||||
* 4 = PUBLIC KEY BLOCK
|
||||
* 5 = PRIVATE KEY BLOCK
|
||||
* null = unknown
|
||||
*/
|
||||
function getPGPMessageType(text) {
|
||||
var splittedtext = text.split('-----');
|
||||
// BEGIN PGP MESSAGE, PART X/Y
|
||||
// Used for multi-part messages, where the armor is split amongst Y
|
||||
// parts, and this is the Xth part out of Y.
|
||||
if (splittedtext[1].match(/BEGIN PGP MESSAGE, PART \d+\/\d+/)) {
|
||||
return 0;
|
||||
} else
|
||||
// BEGIN PGP MESSAGE, PART X
|
||||
// Used for multi-part messages, where this is the Xth part of an
|
||||
// unspecified number of parts. Requires the MESSAGE-ID Armor
|
||||
// Header to be used.
|
||||
if (splittedtext[1].match(/BEGIN PGP MESSAGE, PART \d+/)) {
|
||||
return 1;
|
||||
|
||||
} else
|
||||
// BEGIN PGP SIGNATURE
|
||||
// Used for detached signatures, OpenPGP/MIME signatures, and
|
||||
// cleartext signatures. Note that PGP 2.x uses BEGIN PGP MESSAGE
|
||||
// for detached signatures.
|
||||
if (splittedtext[1].match(/BEGIN PGP SIGNED MESSAGE/)) {
|
||||
return 2;
|
||||
|
||||
} else
|
||||
// BEGIN PGP MESSAGE
|
||||
// Used for signed, encrypted, or compressed files.
|
||||
if (splittedtext[1].match(/BEGIN PGP MESSAGE/)) {
|
||||
return 3;
|
||||
|
||||
} else
|
||||
// BEGIN PGP PUBLIC KEY BLOCK
|
||||
// Used for armoring public keys.
|
||||
if (splittedtext[1].match(/BEGIN PGP PUBLIC KEY BLOCK/)) {
|
||||
return 4;
|
||||
|
||||
} else
|
||||
// BEGIN PGP PRIVATE KEY BLOCK
|
||||
// Used for armoring private keys.
|
||||
if (splittedtext[1].match(/BEGIN PGP PRIVATE KEY BLOCK/)) {
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Armor an OpenPGP binary packet block
|
||||
* @param messagetype type of the message
|
||||
* @param data
|
||||
* @param partindex
|
||||
* @param parttotal
|
||||
* @return
|
||||
*/
|
||||
function openpgp_encoding_armor(messagetype, data, partindex, parttotal) {
|
||||
var result = "";
|
||||
switch(messagetype) {
|
||||
case 0:
|
||||
result += "-----BEGIN PGP MESSAGE, PART "+partindex+"/"+parttotal+"-----\r\n";
|
||||
if (openpgp.config.config.show_version) {
|
||||
result += "Version: "+openpgp.config.versionstring+'\r\n\r\n';
|
||||
} else {
|
||||
result += '\r\n';
|
||||
}
|
||||
result += openpgp_encoding_base64_encode(data);
|
||||
result += "\r\n="+getCheckSum(data)+"\r\n";
|
||||
result += "-----END PGP MESSAGE, PART "+partindex+"/"+parttotal+"-----\r\n";
|
||||
break;
|
||||
case 1:
|
||||
result += "-----BEGIN PGP MESSAGE, PART "+partindex+"-----\r\n";
|
||||
if (openpgp.config.config.show_version) {
|
||||
result += "Version: "+openpgp.config.versionstring+'\r\n\r\n';
|
||||
} else {
|
||||
result += '\r\n';
|
||||
}
|
||||
|
||||
result += openpgp_encoding_base64_encode(data);
|
||||
result += "\r\n="+getCheckSum(data)+"\r\n";
|
||||
result += "-----END PGP MESSAGE, PART "+partindex+"-----\r\n";
|
||||
break;
|
||||
case 2:
|
||||
result += "\r\n-----BEGIN PGP SIGNED MESSAGE-----\r\nHash: "+data.hash+"\r\n\r\n";
|
||||
result += data.text.replace(/\n-/g,"\n- -");
|
||||
result += "\r\n-----BEGIN PGP SIGNATURE-----\r\n";
|
||||
if (openpgp.config.config.show_version) {
|
||||
result += "Version: "+openpgp.config.versionstring+'\r\n\r\n';
|
||||
} else {
|
||||
result += '\r\n';
|
||||
}
|
||||
result += openpgp_encoding_base64_encode(data.openpgp);
|
||||
result += "\r\n="+getCheckSum(data.openpgp)+"\r\n";
|
||||
result += "-----END PGP SIGNATURE-----\r\n";
|
||||
break;
|
||||
case 3:
|
||||
result += "-----BEGIN PGP MESSAGE-----\r\n";
|
||||
if (openpgp.config.config.show_version) {
|
||||
result +="Version: "+ openpgp.config.versionstring+'\r\n\r\n';
|
||||
} else {
|
||||
result += '\r\n';
|
||||
}
|
||||
|
||||
result += openpgp_encoding_base64_encode(data);
|
||||
result += "\r\n="+getCheckSum(data)+"\r\n";
|
||||
result += "-----END PGP MESSAGE-----\r\n";
|
||||
break;
|
||||
case 4:
|
||||
result += "-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n";
|
||||
if (openpgp.config.config.show_version) {
|
||||
result += "Version: "+openpgp.config.versionstring+'\r\n\r\n';
|
||||
} else {
|
||||
result += '\r\n';
|
||||
}
|
||||
|
||||
result += openpgp_encoding_base64_encode(data);
|
||||
result += "\r\n="+getCheckSum(data)+"\r\n";
|
||||
result += "-----END PGP PUBLIC KEY BLOCK-----\r\n\r\n";
|
||||
break;
|
||||
case 5:
|
||||
result += "-----BEGIN PGP PRIVATE KEY BLOCK-----\r\n";
|
||||
if (openpgp.config.config.show_version) {
|
||||
result += "Version: "+openpgp.config.versionstring+'\r\n\r\n';
|
||||
} else {
|
||||
result += '\r\n';
|
||||
}
|
||||
result += openpgp_encoding_base64_encode(data);
|
||||
result += "\r\n="+getCheckSum(data)+"\r\n";
|
||||
result += "-----END PGP PRIVATE KEY BLOCK-----\r\n";
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates a checksum over the given data and returns it base64 encoded
|
||||
* @param data [String] data to create a CRC-24 checksum for
|
||||
* @return [String] base64 encoded checksum
|
||||
*/
|
||||
function getCheckSum(data) {
|
||||
var c = createcrc24(data);
|
||||
var str = "" + String.fromCharCode(c >> 16)+
|
||||
String.fromCharCode((c >> 8) & 0xFF)+
|
||||
String.fromCharCode(c & 0xFF);
|
||||
return openpgp_encoding_base64_encode(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the checksum over the given data and compares it with the given base64 encoded checksum
|
||||
* @param data [String] data to create a CRC-24 checksum for
|
||||
* @param checksum [String] base64 encoded checksum
|
||||
* @return true if the given checksum is correct; otherwise false
|
||||
*/
|
||||
function verifyCheckSum(data, checksum) {
|
||||
var c = getCheckSum(data);
|
||||
var d = checksum;
|
||||
return c[0] == d[0] && c[1] == d[1] && c[2] == d[2];
|
||||
}
|
||||
/**
|
||||
* Internal function to calculate a CRC-24 checksum over a given string (data)
|
||||
* @param data [String] data to create a CRC-24 checksum for
|
||||
* @return [Integer] the CRC-24 checksum as number
|
||||
*/
|
||||
function createcrc24 (data) {
|
||||
var crc = 0xB704CE;
|
||||
var i;
|
||||
var mypos = 0;
|
||||
var len = data.length;
|
||||
while (len--) {
|
||||
crc ^= (data[mypos++].charCodeAt()) << 16;
|
||||
for (i = 0; i < 8; i++) {
|
||||
crc <<= 1;
|
||||
if (crc & 0x1000000)
|
||||
crc ^= 0x1864CFB;
|
||||
}
|
||||
}
|
||||
return crc & 0xFFFFFF;
|
||||
}
|
||||
125
src/encoding/openpgp.encoding.js
Executable file
125
src/encoding/openpgp.encoding.js
Executable file
@@ -0,0 +1,125 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* Wrapper function for the base64 codec.
|
||||
* This function encodes a String (message) in base64 (radix-64)
|
||||
* @param message [String] the message to encode
|
||||
* @return [String] the base64 encoded data
|
||||
*/
|
||||
function openpgp_encoding_base64_encode(message) {
|
||||
return s2r(message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper function for the base64 codec.
|
||||
* This function decodes a String(message) in base64 (radix-64)
|
||||
* @param message [String] base64 encoded data
|
||||
* @return [String] raw data after decoding
|
||||
*/
|
||||
function openpgp_encoding_base64_decode(message) {
|
||||
return r2s(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper function for jquery library.
|
||||
* This function escapes HTML characters within a string. This is used to prevent XSS.
|
||||
* @param message [String] message to escape
|
||||
* @return [String] html encoded string
|
||||
*/
|
||||
function openpgp_encoding_html_encode(message) {
|
||||
if (message == null)
|
||||
return "";
|
||||
return $('<div/>').text(message).html();
|
||||
}
|
||||
|
||||
/**
|
||||
* create a EME-PKCS1-v1_5 padding (See RFC4880 13.1.1)
|
||||
* @param message [String] message to be padded
|
||||
* @param length [Integer] length to the resulting message
|
||||
* @return [String] EME-PKCS1 padded message
|
||||
*/
|
||||
function openpgp_encoding_eme_pkcs1_encode(message, length) {
|
||||
if (message.length > length-11)
|
||||
return -1;
|
||||
var result = "";
|
||||
result += String.fromCharCode(0);
|
||||
result += String.fromCharCode(2);
|
||||
for (var i = 0; i < length - message.length - 3; i++) {
|
||||
result += String.fromCharCode(openpgp_crypto_getPseudoRandom(1,255));
|
||||
}
|
||||
result += String.fromCharCode(0);
|
||||
result += message;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* ASN1 object identifiers for hashes (See RFC4880 5.2.2)
|
||||
*/
|
||||
hash_headers = new Array();
|
||||
hash_headers[1] = [0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x04,0x10];
|
||||
hash_headers[3] = [0x30,0x21,0x30,0x09,0x06,0x05,0x2B,0x24,0x03,0x02,0x01,0x05,0x00,0x04,0x14];
|
||||
hash_headers[2] = [0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14];
|
||||
hash_headers[8] = [0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20];
|
||||
hash_headers[9] = [0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04,0x30];
|
||||
hash_headers[10] = [0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,0x40];
|
||||
hash_headers[11] = [0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x04,0x05,0x00,0x04,0x1C];
|
||||
|
||||
/**
|
||||
* create a EMSA-PKCS1-v1_5 padding (See RFC4880 13.1.3)
|
||||
* @param algo [Integer] hash algorithm type used
|
||||
* @param data [String] data to be hashed
|
||||
* @param keylength [Integer] key size of the public mpi in bytes
|
||||
* @return the [String] hashcode with pkcs1padding as string
|
||||
*/
|
||||
function openpgp_encoding_emsa_pkcs1_encode(algo, data, keylength) {
|
||||
var data2 = "";
|
||||
data2 += String.fromCharCode(0x00);
|
||||
data2 += String.fromCharCode(0x01);
|
||||
for (var i = 0; i < (keylength - hash_headers[algo].length - 3 - openpgp_crypto_getHashByteLength(algo)); i++)
|
||||
data2 += String.fromCharCode(0xff);
|
||||
data2 += String.fromCharCode(0x00);
|
||||
|
||||
for (var i = 0; i < hash_headers[algo].length; i++)
|
||||
data2 += String.fromCharCode(hash_headers[algo][i]);
|
||||
|
||||
data2 += openpgp_crypto_hashData(algo, data);
|
||||
return new BigInteger(util.hexstrdump(data2),16);
|
||||
}
|
||||
|
||||
/**
|
||||
* extract the hash out of an EMSA-PKCS1-v1.5 padding (See RFC4880 13.1.3)
|
||||
* @param data [String] hash in pkcs1 encoding
|
||||
* @return the hash as string
|
||||
*/
|
||||
function openpgp_encoding_emsa_pkcs1_decode(algo, data) {
|
||||
var i = 0;
|
||||
if (data.charCodeAt(0) == 0) i++;
|
||||
else if (data.charCodeAt(0) != 1) return -1;
|
||||
else i++;
|
||||
|
||||
while (data.charCodeAt(i) == 0xFF) i++;
|
||||
if (data.charCodeAt(i++) != 0) return -1;
|
||||
var j = 0;
|
||||
for (j = 0; j < hash_headers[algo].length && j+i < data.length; j++) {
|
||||
if (data.charCodeAt(j+i) != hash_headers[algo][j]) return -1;
|
||||
}
|
||||
i+= j;
|
||||
if (data.substring(i).length < openpgp_crypto_getHashByteLength(algo)) return -1;
|
||||
return data.substring(i);
|
||||
}
|
||||
357
src/openpgp.js
Executable file
357
src/openpgp.js
Executable file
@@ -0,0 +1,357 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* GPG4Browsers Core interface. A single instance is hold
|
||||
* from the beginning. To use this library call "openpgp.init()"
|
||||
*/
|
||||
function _openpgp () {
|
||||
this.tostring = "";
|
||||
|
||||
/**
|
||||
* initializes the library:
|
||||
* - reading the keyring from local storage
|
||||
* - reading the config from local storage
|
||||
* @return [void]
|
||||
*/
|
||||
function init() {
|
||||
this.config = new openpgp_config();
|
||||
this.config.read();
|
||||
this.keyring = new openpgp_keyring();
|
||||
this.keyring.init();
|
||||
}
|
||||
|
||||
/**
|
||||
* reads several publicKey objects from a ascii armored
|
||||
* representation an returns openpgp_msg_publickey packets
|
||||
* @param armoredText [String] OpenPGP armored text containing
|
||||
* the public key(s)
|
||||
* @return [Array[openpgp_msg_publickey]] on error the function
|
||||
* returns null
|
||||
*/
|
||||
function read_publicKey(armoredText) {
|
||||
var mypos = 0;
|
||||
var publicKeys = new Array();
|
||||
var publicKeyCount = 0;
|
||||
var input = openpgp_encoding_deArmor(armoredText.replace(/\r/g,'')).openpgp;
|
||||
var l = input.length;
|
||||
while (mypos != input.length) {
|
||||
var first_packet = openpgp_packet.read_packet(input, mypos, l);
|
||||
// public key parser
|
||||
if (input[mypos].charCodeAt() == 0x99 || first_packet.tagType == 6) {
|
||||
publicKeys[publicKeyCount] = new openpgp_msg_publickey();
|
||||
publicKeys[publicKeyCount].header = input.substring(mypos,mypos+3);
|
||||
if (input[mypos].charCodeAt() == 0x99) {
|
||||
// parse the length and read a tag6 packet
|
||||
mypos++;
|
||||
var l = (input[mypos++].charCodeAt() << 8)
|
||||
| input[mypos++].charCodeAt();
|
||||
publicKeys[publicKeyCount].publicKeyPacket = new openpgp_packet_keymaterial();
|
||||
publicKeys[publicKeyCount].publicKeyPacket.header = publicKeys[publicKeyCount].header;
|
||||
publicKeys[publicKeyCount].publicKeyPacket.read_tag6(input, mypos, l);
|
||||
mypos += publicKeys[publicKeyCount].publicKeyPacket.packetLength;
|
||||
mypos += publicKeys[publicKeyCount].read_nodes(publicKeys[publicKeyCount].publicKeyPacket, input, mypos, (input.length - mypos));
|
||||
} else {
|
||||
publicKeys[publicKeys.length] = new openpgp_msg_publickey();
|
||||
publicKeys[publicKeyCount].publicKeyPacket = first_packet;
|
||||
mypos += first_packet.headerLength+first_packet.packetLength;
|
||||
mypos += publicKeys[publicKeyCount].read_nodes(first_packet, input, mypos, input.length -mypos);
|
||||
}
|
||||
} else {
|
||||
util.print_error("no public key found!");
|
||||
return null;
|
||||
}
|
||||
publicKeys[publicKeyCount].data = input.substring(0,mypos);
|
||||
publicKeyCount++;
|
||||
}
|
||||
return publicKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* reads several privateKey objects from a ascii armored
|
||||
* representation an returns openpgp_msg_privatekey objects
|
||||
* @param armoredText [String] OpenPGP armored text containing
|
||||
* the private key(s)
|
||||
* @return [Array[openpgp_msg_privatekey]] on error the function
|
||||
* returns null
|
||||
*/
|
||||
function read_privateKey(armoredText) {
|
||||
var privateKeys = new Array();
|
||||
var privateKeyCount = 0;
|
||||
var mypos = 0;
|
||||
var input = openpgp_encoding_deArmor(armoredText.replace(/\r/g,'')).openpgp;
|
||||
var l = input.length;
|
||||
while (mypos != input.length) {
|
||||
var first_packet = openpgp_packet.read_packet(input, mypos, l);
|
||||
if (first_packet.tagType == 5) {
|
||||
privateKeys[privateKeys.length] = new openpgp_msg_privatekey();
|
||||
mypos += first_packet.headerLength+first_packet.packetLength;
|
||||
mypos += privateKeys[privateKeyCount].read_nodes(first_packet, input, mypos, l);
|
||||
// other blocks
|
||||
} else {
|
||||
util.print_error('no block packet found!');
|
||||
return null;
|
||||
}
|
||||
privateKeys[privateKeyCount].data = input.substring(0,mypos);
|
||||
privateKeyCount++;
|
||||
}
|
||||
return privateKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* reads message packets out of an OpenPGP armored text and
|
||||
* returns an array of message objects
|
||||
* @param armoredText [String] text to be parsed
|
||||
* @return [Array[openpgp_msg_message]] on error the function
|
||||
* returns null
|
||||
*/
|
||||
function read_message(armoredText) {
|
||||
var dearmored = openpgp_encoding_deArmor(armoredText.replace(/\r/g,''));
|
||||
var input = dearmored.openpgp;
|
||||
var messages = new Array();
|
||||
var messageCount = 0;
|
||||
var mypos = 0;
|
||||
var l = input.length;
|
||||
while (mypos < input.length) {
|
||||
var first_packet = openpgp_packet.read_packet(input, mypos, l);
|
||||
// public key parser (definition from the standard:)
|
||||
// OpenPGP Message :- Encrypted Message | Signed Message |
|
||||
// Compressed Message | Literal Message.
|
||||
// Compressed Message :- Compressed Data Packet.
|
||||
//
|
||||
// Literal Message :- Literal Data Packet.
|
||||
//
|
||||
// ESK :- Public-Key Encrypted Session Key Packet |
|
||||
// Symmetric-Key Encrypted Session Key Packet.
|
||||
//
|
||||
// ESK Sequence :- ESK | ESK Sequence, ESK.
|
||||
//
|
||||
// Encrypted Data :- Symmetrically Encrypted Data Packet |
|
||||
// Symmetrically Encrypted Integrity Protected Data Packet
|
||||
//
|
||||
// Encrypted Message :- Encrypted Data | ESK Sequence, Encrypted Data.
|
||||
//
|
||||
// One-Pass Signed Message :- One-Pass Signature Packet,
|
||||
// OpenPGP Message, Corresponding Signature Packet.
|
||||
|
||||
// Signed Message :- Signature Packet, OpenPGP Message |
|
||||
// One-Pass Signed Message.
|
||||
if (first_packet.tagType == 1 ||
|
||||
(first_packet.tagType == 2 && first_packet.signatureType < 16) ||
|
||||
first_packet.tagType == 3 ||
|
||||
first_packet.tagType == 8 ||
|
||||
first_packet.tagType == 9 ||
|
||||
first_packet.tagType == 10 ||
|
||||
first_packet.tagType == 11 ||
|
||||
first_packet.tagType == 18 ||
|
||||
first_packet.tagType == 19) {
|
||||
messages[messages.length] = new openpgp_msg_message();
|
||||
messages[messageCount].messagePacket = first_packet;
|
||||
messages[messageCount].type = dearmored.type;
|
||||
// Encrypted Message
|
||||
if (first_packet.tagType == 9 ||
|
||||
first_packet.tagType == 1 ||
|
||||
first_packet.tagType == 3 ||
|
||||
first_packet.tagType == 18) {
|
||||
if (first_packet.tagType == 9) {
|
||||
util.print_error("unexpected openpgp packet");
|
||||
break;
|
||||
} else if (first_packet.tagType == 1) {
|
||||
util.print_debug("session key found:\n "+first_packet.toString());
|
||||
var issessionkey = true;
|
||||
messages[messageCount].sessionKeys = new Array();
|
||||
var sessionKeyCount = 0;
|
||||
while (issessionkey) {
|
||||
messages[messageCount].sessionKeys[sessionKeyCount] = first_packet;
|
||||
mypos += first_packet.packetLength + first_packet.headerLength;
|
||||
l -= (first_packet.packetLength + first_packet.headerLength);
|
||||
first_packet = openpgp_packet.read_packet(input, mypos, l);
|
||||
|
||||
if (first_packet.tagType != 1 && first_packet.tagType != 3)
|
||||
issessionkey = false;
|
||||
sessionKeyCount++;
|
||||
}
|
||||
if (first_packet.tagType == 18 || first_packet.tagType == 9) {
|
||||
util.print_debug("encrypted data found:\n "+first_packet.toString());
|
||||
messages[messageCount].encryptedData = first_packet;
|
||||
mypos += first_packet.packetLength+first_packet.headerLength;
|
||||
l -= (first_packet.packetLength+first_packet.headerLength);
|
||||
messageCount++;
|
||||
|
||||
} else {
|
||||
util.print_debug("something is wrong: "+first_packet.tagType);
|
||||
}
|
||||
|
||||
} else if (first_packet.tagType == 18) {
|
||||
util.print_debug("symmetric encrypted data");
|
||||
break;
|
||||
}
|
||||
} else
|
||||
// Signed Message
|
||||
if (first_packet.tagType == 2 && first_packet.signatureType < 3) {
|
||||
messages[messageCount].text = dearmored.text;
|
||||
messages[messageCount].signature = first_packet;
|
||||
break;
|
||||
} else
|
||||
// Compressed Message
|
||||
// TODO: needs to be implemented. From a security perspective: this message is plaintext anyway.
|
||||
if (first_packet.tagType == 8) {
|
||||
util.print_error("A directly compressed message is currently not supported");
|
||||
break;
|
||||
} else
|
||||
// Literal Message
|
||||
// TODO: needs to be implemented. From a security perspective: this message is plaintext anyway.
|
||||
if (first_packet.tagType == 11) {
|
||||
util.print_error("A direct literal message is currently not supported.");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
util.print_error('no message found!');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a binary string representation of an encrypted and signed message.
|
||||
* The message will be encrypted with the public keys specified and signed
|
||||
* with the specified private key.
|
||||
* @param privatekey {obj: [openpgp_msg_privatekey]} private key to be used to sign the message
|
||||
* @param publickeys [Array {obj: [openpgp_msg_publickey]}] public keys to be used to encrypt the message
|
||||
* @param messagetext [String] message text to encrypt and sign
|
||||
* @return [String] a binary string representation of the message which can be OpenPGP armored
|
||||
*/
|
||||
function write_signed_and_encrypted_message(privatekey, publickeys, messagetext) {
|
||||
var result = "";
|
||||
var literal = new openpgp_packet_literaldata().write_packet(messagetext.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n"));
|
||||
util.print_debug("literal_packet: |"+literal+"|\n"+util.hexstrdump(literal));
|
||||
for (var i = 0; i < publickeys.length; i++) {
|
||||
var onepasssignature = new openpgp_packet_onepasssignature();
|
||||
var onepasssigstr = "";
|
||||
if (i == 0)
|
||||
onepasssigstr = onepasssignature.write_packet(1, openpgp.config.config.prefer_hash_algorithm, privatekey, false);
|
||||
else
|
||||
onepasssigstr = onepasssignature.write_packet(1, openpgp.config.config.prefer_hash_algorithm, privatekey, false);
|
||||
util.print_debug("onepasssigstr: |"+onepasssigstr+"|\n"+util.hexstrdump(onepasssigstr));
|
||||
var datasignature = new openpgp_packet_signature().write_message_signature(1, messagetext.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n"), privatekey);
|
||||
util.print_debug("datasignature: |"+datasignature.openpgp+"|\n"+util.hexstrdump(datasignature.openpgp));
|
||||
if (i == 0) {
|
||||
result = onepasssigstr+literal+datasignature.openpgp;
|
||||
} else {
|
||||
result = onepasssigstr+result+datasignature.openpgp;
|
||||
}
|
||||
}
|
||||
|
||||
util.print_debug("signed packet: |"+result+"|\n"+util.hexstrdump(result));
|
||||
// signatures done.. now encryption
|
||||
var sessionkey = openpgp_crypto_generateSessionKey(openpgp.config.config.encryption_cipher);
|
||||
var result2 = "";
|
||||
|
||||
// creating session keys for each recipient
|
||||
for (var i = 0; i < publickeys.length; i++) {
|
||||
var pkey = publickeys[i].getEncryptionKey();
|
||||
if (pkey == null) {
|
||||
util.print_error("no encryption key found! Key is for signing only.");
|
||||
return null;
|
||||
}
|
||||
result2 += new openpgp_packet_encryptedsessionkey().
|
||||
write_pub_key_packet(
|
||||
pkey.getKeyId(),
|
||||
pkey.MPIs,
|
||||
pkey.publicKeyAlgorithm,
|
||||
openpgp.config.config.encryption_cipher,
|
||||
sessionkey);
|
||||
}
|
||||
if (openpgp.config.config.integrity_protect) {
|
||||
result2 += new openpgp_packet_encryptedintegrityprotecteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result);
|
||||
} else {
|
||||
result2 += new openpgp_packet_encrypteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result);
|
||||
}
|
||||
return openpgp_encoding_armor(3,result2,null,null);
|
||||
}
|
||||
/**
|
||||
* creates a binary string representation of an encrypted message.
|
||||
* The message will be encrypted with the public keys specified
|
||||
* @param publickeys [Array {obj: [openpgp_msg_publickey]}] public
|
||||
* keys to be used to encrypt the message
|
||||
* @param messagetext [String] message text to encrypt
|
||||
* @return [String] a binary string representation of the message
|
||||
* which can be OpenPGP armored
|
||||
*/
|
||||
function write_encrypted_message(publickeys, messagetext) {
|
||||
var result = "";
|
||||
var literal = new openpgp_packet_literaldata().write_packet(messagetext.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n"));
|
||||
util.print_debug("literal_packet: |"+literal+"|\n"+util.hexstrdump(literal));
|
||||
result = literal;
|
||||
|
||||
// signatures done.. now encryption
|
||||
var sessionkey = openpgp_crypto_generateSessionKey(openpgp.config.config.encryption_cipher);
|
||||
var result2 = "";
|
||||
|
||||
// creating session keys for each recipient
|
||||
for (var i = 0; i < publickeys.length; i++) {
|
||||
var pkey = publickeys[i].getEncryptionKey();
|
||||
if (pkey == null) {
|
||||
util.print_error("no encryption key found! Key is for signing only.");
|
||||
return null;
|
||||
}
|
||||
result2 += new openpgp_packet_encryptedsessionkey().
|
||||
write_pub_key_packet(
|
||||
pkey.getKeyId(),
|
||||
pkey.MPIs,
|
||||
pkey.publicKeyAlgorithm,
|
||||
openpgp.config.config.encryption_cipher,
|
||||
sessionkey);
|
||||
}
|
||||
if (openpgp.config.config.integrity_protect) {
|
||||
result2 += new openpgp_packet_encryptedintegrityprotecteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result);
|
||||
} else {
|
||||
result2 += new openpgp_packet_encrypteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result);
|
||||
}
|
||||
return openpgp_encoding_armor(3,result2,null,null);
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a binary string representation a signed message.
|
||||
* The message will be signed with the specified private key.
|
||||
* @param privatekey {obj: [openpgp_msg_privatekey]} private
|
||||
* key to be used to sign the message
|
||||
* @param messagetext [String] message text to sign
|
||||
* @return [Object: text [String], openpgp: [String] a binary
|
||||
* string representation of the message which can be OpenPGP
|
||||
* armored(openpgp) and a text representation of the message (text). This can be directly used to OpenPGP armor the message
|
||||
*/
|
||||
function write_signed_message(privatekey, messagetext) {
|
||||
var sig = new openpgp_packet_signature().write_message_signature(1, messagetext.replace(/\r\n/g,"\n").replace(/\n/,"\r\n"), privatekey);
|
||||
var result = {text: messagetext.replace(/\r\n/g,"\n").replace(/\n/,"\r\n"), openpgp: sig.openpgp, hash: sig.hash};
|
||||
return openpgp_encoding_armor(2,result, null, null)
|
||||
}
|
||||
|
||||
this.write_signed_message = write_signed_message;
|
||||
this.write_signed_and_encrypted_message = write_signed_and_encrypted_message;
|
||||
this.write_encrypted_message = write_encrypted_message;
|
||||
this.read_message = read_message;
|
||||
this.read_publicKey = read_publicKey;
|
||||
this.read_privateKey = read_privateKey;
|
||||
this.init = init;
|
||||
}
|
||||
|
||||
var openpgp = new _openpgp();
|
||||
|
||||
|
||||
227
src/openpgp.keyring.js
Executable file
227
src/openpgp.keyring.js
Executable file
@@ -0,0 +1,227 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
function openpgp_keyring() {
|
||||
|
||||
/**
|
||||
* Initialization routine for the keyring. This method reads the
|
||||
* keyring from HTML5 local storage and initializes this instance.
|
||||
* This method is called by openpgp.init().
|
||||
* @return [null] undefined
|
||||
*/
|
||||
function init() {
|
||||
var sprivatekeys = JSON.parse(window.localStorage.getItem("privatekeys"));
|
||||
var spublickeys = JSON.parse(window.localStorage.getItem("publickeys"));
|
||||
if (sprivatekeys == null || sprivatekeys.length == 0) {
|
||||
sprivatekeys = new Array();
|
||||
}
|
||||
|
||||
if (spublickeys == null || spublickeys.length == 0) {
|
||||
spublickeys = new Array();
|
||||
}
|
||||
this.publicKeys = new Array();
|
||||
this.privateKeys = new Array();
|
||||
var k = 0;
|
||||
for (var i =0; i < sprivatekeys.length; i++) {
|
||||
var r = openpgp.read_privateKey(sprivatekeys[i]);
|
||||
this.privateKeys[k] = { armored: sprivatekeys[i], obj: r[0], keyId: r[0].getKeyId()};
|
||||
k++;
|
||||
}
|
||||
k = 0;
|
||||
for (var i =0; i < spublickeys.length; i++) {
|
||||
var r = openpgp.read_publicKey(spublickeys[i]);
|
||||
if (r[0] != null) {
|
||||
this.publicKeys[k] = { armored: spublickeys[i], obj: r[0], keyId: r[0].getKeyId()};
|
||||
k++;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.init = init;
|
||||
|
||||
/**
|
||||
* Checks if at least one private key is in the keyring
|
||||
* @return
|
||||
*/
|
||||
function hasPrivateKey() {
|
||||
return this.privateKeys.length > 0;
|
||||
}
|
||||
this.hasPrivateKey = hasPrivateKey;
|
||||
|
||||
/**
|
||||
* Saves the current state of the keyring to HTML5 local storage.
|
||||
* The privateKeys array and publicKeys array gets Stringified using JSON
|
||||
* @return [null] undefined
|
||||
*/
|
||||
function store() {
|
||||
var priv = new Array();
|
||||
for (var i = 0; i < this.privateKeys.length; i++) {
|
||||
priv[i] = this.privateKeys[i].armored;
|
||||
}
|
||||
var pub = new Array();
|
||||
for (var i = 0; i < this.publicKeys.length; i++) {
|
||||
pub[i] = this.publicKeys[i].armored;
|
||||
}
|
||||
window.localStorage.setItem("privatekeys",JSON.stringify(priv));
|
||||
window.localStorage.setItem("publickeys",JSON.stringify(pub));
|
||||
}
|
||||
this.store = store;
|
||||
/**
|
||||
* searches all public keys in the keyring matching the address or address part of the user ids
|
||||
* @param email_address
|
||||
* @return
|
||||
*/
|
||||
function getPublicKeyForAddress(email_address) {
|
||||
var results = new Array();
|
||||
var spl = string.split("<");
|
||||
var email = "";
|
||||
if (spl.length > 0) {
|
||||
email = spl[1].split(">")[0];
|
||||
} else {
|
||||
email = string.trim();
|
||||
}
|
||||
for (var i =0; i < this.publicKeys.length; i++) {
|
||||
|
||||
for (var j = 0; j < this.publicKeys[i].userIds; j++) {
|
||||
if (this.publicKeys[i].userIds[j].indexOf(email) >= 0)
|
||||
results[results.length] = this.publicKeys[i];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the keyring for a private key containing the specified email address
|
||||
* @param email_address [String] email address to search for
|
||||
* @return [Array[openpgp_msg_privatekey] private keys found
|
||||
*/
|
||||
function getPrivateKeyForAddress(email_address) {
|
||||
var results = new Array();
|
||||
var spl = email_address.split("<");
|
||||
var email = "";
|
||||
if (spl.length > 1) {
|
||||
email = spl[1].split(">")[0];
|
||||
} else {
|
||||
email = email_address.trim();
|
||||
}
|
||||
for (var i =0; i < this.privateKeys.length; i++) {
|
||||
|
||||
for (var j = 0; j < this.privateKeys[i].obj.userIds.length; j++) {
|
||||
if (this.privateKeys[i].obj.userIds[j].text.indexOf(email) >= 0)
|
||||
results[results.length] = this.privateKeys[i];
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
this.getPrivateKeyForAddress = getPrivateKeyForAddress;
|
||||
/**
|
||||
* Searches the keyring for public keys having the specified key id
|
||||
* @param keyId provided as string of hex number (lowercase)
|
||||
* @return Array[openpgp_msg_privatekey] public keys found
|
||||
*/
|
||||
function getPublicKeysForKeyId(keyId) {
|
||||
var result = new Array();
|
||||
for (var i=0; i < this.publicKeys.length; i++)
|
||||
if (keyId == this.publicKeys[i].obj.getKeyId())
|
||||
result[result.length] = this.publicKeys[i];
|
||||
return result;
|
||||
}
|
||||
this.getPublicKeysForKeyId = getPublicKeysForKeyId;
|
||||
|
||||
/**
|
||||
* Searches the keyring for private keys having the specified key id
|
||||
* @param keyId [String] 8 bytes as string containing the key id to look for
|
||||
* @return Array[openpgp_msg_privatekey] private keys found
|
||||
*/
|
||||
function getPrivateKeyForKeyId(keyId) {
|
||||
var result = new Array();
|
||||
for (var i=0; i < this.privateKeys.length; i++) {
|
||||
if (keyId == util.hexstrdump(this.privateKeys[i].obj.getKeyId())) {
|
||||
result[result.length] = { key: this.privateKeys[i], keymaterial: this.privateKeys[i].obj.privateKeyPacket};
|
||||
}
|
||||
if (this.privateKeys[i].obj.subKeys != null) {
|
||||
var subkeyids = this.privateKeys[i].obj.getSubKeyIds();
|
||||
for (var j=0; j < subkeyids.length; j++)
|
||||
if (keyId == util.hexstrdump(subkeyids[j])) {
|
||||
result[result.length] = { key: this.privateKeys[i], keymaterial: this.privateKeys[i].obj.subKeys[j]};
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
this.getPrivateKeyForKeyId = getPrivateKeyForKeyId;
|
||||
|
||||
/**
|
||||
* Imports a public key from an exported ascii armored message
|
||||
* @param armored_text [String] PUBLIC KEY BLOCK message to read the public key from
|
||||
* @return [null] nothing
|
||||
*/
|
||||
function importPublicKey (armored_text) {
|
||||
var result = openpgp.read_publicKey(armored_text);
|
||||
for (var i = 0; i < result.length; i++) {
|
||||
this.publicKeys[this.publicKeys.length] = {armored: armored_text, obj: result[i]};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports a private key from an exported ascii armored message
|
||||
* @param armored_text [String] PRIVATE KEY BLOCK message to read the private key from
|
||||
* @return [null] nothing
|
||||
*/
|
||||
function importPrivateKey (armored_text) {
|
||||
var result = openpgp.read_privateKey(armored_text);
|
||||
for (var i = 0; i < result.length; i++) {
|
||||
this.privateKeys[this.privateKeys.length] = {armored: armored_text, obj: result[i]};
|
||||
}
|
||||
}
|
||||
|
||||
this.importPublicKey = importPublicKey;
|
||||
this.importPrivateKey = importPrivateKey;
|
||||
|
||||
/**
|
||||
* returns the PUBLIC KEY BLOCK message representation of the public key at public key ring index
|
||||
* @param index [Integer] the index of the public key within the publicKeys array
|
||||
* @return [String] the PUBLIC KEY BLOCK message
|
||||
*/
|
||||
function exportPublicKey(index) {
|
||||
return this.publicKey[index];
|
||||
}
|
||||
this.exportPublicKey = exportPublicKey;
|
||||
|
||||
|
||||
/**
|
||||
* Removes a public key from the public key keyring at the specified index
|
||||
* @param index [Integer] the index of the public key within the publicKeys array
|
||||
* @return [String The public key object which has been removed
|
||||
*/
|
||||
function removePublicKey(index) {
|
||||
var removed = this.publicKeys.splice(index,1);
|
||||
this.store();
|
||||
return removed;
|
||||
}
|
||||
this.removePublicKey = removePublicKey;
|
||||
|
||||
/**
|
||||
* returns the PRIVATE KEY BLOCK message representation of the private key at private key ring index
|
||||
* @param index [Integer] the index of the private key within the privateKeys array
|
||||
* @return [String] the PRIVATE KEY BLOCK message
|
||||
*/
|
||||
function exportPrivateKey(index) {
|
||||
return this.privateKeys[index];
|
||||
}
|
||||
this.exportPrivateKey = exportPrivateKey;
|
||||
}
|
||||
135
src/openpgp.msg.message.js
Executable file
135
src/openpgp.msg.message.js
Executable file
@@ -0,0 +1,135 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
function openpgp_msg_message() {
|
||||
|
||||
// -1 = no valid passphrase submitted
|
||||
// -2 = no private key found
|
||||
// -3 = decryption error
|
||||
// text = valid decryption
|
||||
this.text = "";
|
||||
|
||||
/**
|
||||
* Decrypts a message and generates user interface message out of the found.
|
||||
* MDC will be verified as well as message signatures
|
||||
* @param private_key [openpgp_msg_privatekey] the private the message is encrypted with (corresponding to the session key)
|
||||
* @param sessionkey [openpgp_packet_encryptedsessionkey] the session key to be used to decrypt the message
|
||||
* @return [String] plaintext of the message or null on error
|
||||
*/
|
||||
function decrypt(private_key, sessionkey) {
|
||||
if (private_key == null || sessionkey == null || sessionkey == "")
|
||||
return null;
|
||||
var decrypted = sessionkey.decrypt(this, private_key.keymaterial);
|
||||
if (decrypted == null)
|
||||
return null;
|
||||
var packet;
|
||||
var position = 0;
|
||||
var len = decrypted.length;
|
||||
util.print_debug("openpgp.msg.messge decrypt:\n"+util.hexstrdump(decrypted));
|
||||
|
||||
while (position != decrypted.length && (packet = openpgp_packet.read_packet(decrypted, position, len)) != null) {
|
||||
if (packet.tagType == 8) {
|
||||
this.text = packet.decompress();
|
||||
decrypted = packet.decompress();
|
||||
}
|
||||
util.print_debug(packet.toString());
|
||||
position += packet.headerLength+packet.packetLength;
|
||||
if (position > 38)
|
||||
util.print_debug("openpgp.msg.messge decrypt:\n"+util.hexstrdump(decrypted.substring(position)));
|
||||
len = decrypted.length - position;
|
||||
if (packet.tagType == 11) {
|
||||
this.text = packet.data;
|
||||
util.print_info("message successfully decrypted");
|
||||
}
|
||||
if (packet.tagType == 19)
|
||||
// ignore.. we checked that already in a more strict way.
|
||||
continue;
|
||||
if (packet.tagType == 2 && packet.signatureType < 3) {
|
||||
var pubkey = openpgp.keyring.getPublicKeysForKeyId(packet.issuerKeyId);
|
||||
if (pubkey.length == 0) {
|
||||
util.print_warning("Unable to verify signature of issuer: "+util.hexstrdump(packet.issuerKeyId)+". Public key not found in keyring.");
|
||||
} else {
|
||||
if(packet.verify(this.text.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n"),pubkey[0]) && pubkey[0].obj.validate())
|
||||
util.print_info("Found Good Signature from "+pubkey[0].obj.userIds[0].text+" (0x"+util.hexstrdump(pubkey[0].obj.getKeyId()).substring(8)+")");
|
||||
else
|
||||
util.print_error("Signature verification failed: Bad Signature from "+pubkey[0].obj.userIds[0].text+" (0x"+util.hexstrdump(pubkey[0].obj.getKeyId()).substring(8)+")");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.text == "") {
|
||||
this.text = decrypted;
|
||||
}
|
||||
return this.text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies a message signature. This function can be called after read_message if the message was signed only.
|
||||
* @return [boolean] true if the signature was correct; otherwise false
|
||||
*/
|
||||
function verifySignature() {
|
||||
var result = false;
|
||||
if (this.type == 2) {
|
||||
var pubkey;
|
||||
if (this.signature.version == 4) {
|
||||
pubkey = openpgp.keyring.getPublicKeysForKeyId(this.signature.issuerKeyId);
|
||||
} else if (this.signature.version == 3) {
|
||||
pubkey = openpgp.keyring.getPublicKeysForKeyId(this.signature.keyId);
|
||||
} else {
|
||||
util.print_error("unknown signature type on message!");
|
||||
return false;
|
||||
}
|
||||
if (pubkey.length == 0)
|
||||
util.print_warning("Unable to verify signature of issuer: "+util.hexstrdump(this.signature.issuerKeyId)+". Public key not found in keyring.");
|
||||
else {
|
||||
for (var i = 0 ; i < pubkey.length; i++) {
|
||||
var tohash = this.text.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n");
|
||||
if (this.signature.verify(tohash.substring(0, tohash.length -2), pubkey[i])) {
|
||||
util.print_info("Found Good Signature from "+pubkey[i].obj.userIds[i].text+" (0x"+util.hexstrdump(pubkey[i].obj.getKeyId()).substring(8)+")");
|
||||
result = true;
|
||||
} else {
|
||||
util.print_error("Signature verification failed: Bad Signature from "+pubkey[i].obj.userIds[0].text+" (0x"+util.hexstrdump(pubkey[0].obj.getKeyId()).substring(8)+")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function toString() {
|
||||
var result = "Session Keys:\n";
|
||||
if (this.sessionKeys !=null)
|
||||
for (var i = 0; i < this.sessionKeys.length; i++) {
|
||||
result += this.sessionKeys[i].toString();
|
||||
}
|
||||
result += "\n\n EncryptedData:\n";
|
||||
if(this.encryptedData != null)
|
||||
result += this.encryptedData.toString();
|
||||
|
||||
result += "\n\n Signature:\n";
|
||||
if(this.signature != null)
|
||||
result += this.signature.toString();
|
||||
|
||||
result += "\n\n Text:\n"
|
||||
if(this.signature != null)
|
||||
result += this.text;
|
||||
return result;
|
||||
}
|
||||
this.decrypt = decrypt;
|
||||
this.verifySignature = verifySignature;
|
||||
this.toString = toString;
|
||||
}
|
||||
144
src/openpgp.msg.privatekey.js
Executable file
144
src/openpgp.msg.privatekey.js
Executable file
@@ -0,0 +1,144 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
function openpgp_msg_privatekey() {
|
||||
this.subKeys = new Array();
|
||||
this.privateKeyPacket = null;
|
||||
this.userIds = new Array();
|
||||
this.userAttributes = new Array();
|
||||
this.revocationSignatures = new Array();
|
||||
this.subKeys = new Array();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return last position
|
||||
*/
|
||||
function read_nodes(parent_node, input, position, len) {
|
||||
this.privateKeyPacket = parent_node;
|
||||
|
||||
var pos = position;
|
||||
while (input.length > pos) {
|
||||
var result = openpgp_packet.read_packet(input, pos, input.length - pos);
|
||||
if (result == null) {
|
||||
util.print_error("openpgp.msg.messge decrypt:\n"+'[pub/priv_key]parsing ends here @:' + pos + " l:" + len);
|
||||
break;
|
||||
} else {
|
||||
switch (result.tagType) {
|
||||
case 2: // public key revocation signature
|
||||
if (result.signatureType == 32)
|
||||
this.revocationSignatures[this.revocationSignatures.length] = result;
|
||||
else if (result.signatureType > 15 && result.signatureType < 20) {
|
||||
if (this.certificationsignatures == null)
|
||||
this.certificationSignatures = new Array();
|
||||
this.certificationSignatures[this.certificationSignatures.length] = result;
|
||||
} else
|
||||
util.print_error("openpgp.msg.messge decrypt:\n"+"unknown signature type directly on key "+result.signatureType+" @"+pos);
|
||||
pos += result.packetLength + result.headerLength;
|
||||
break;
|
||||
case 7: // PrivateSubkey Packet
|
||||
this.subKeys[this.subKeys.length] = result;
|
||||
pos += result.packetLength + result.headerLength;
|
||||
pos += result.read_nodes(this.privateKeyPacket,input, pos, input.length - pos);
|
||||
break;
|
||||
case 17: // User Attribute Packet
|
||||
this.userAttributes[this.userAttributes.length] = result;
|
||||
pos += result.packetLength + result.headerLength;
|
||||
pos += result.read_nodes(this.privateKeyPacket,input, pos, input.length - pos);
|
||||
break;
|
||||
case 13: // User ID Packet
|
||||
this.userIds[this.userIds.length] = result;
|
||||
pos += result.packetLength + result.headerLength;
|
||||
pos += result.read_nodes(this.privateKeyPacket, input, pos, input.length - pos);
|
||||
break;
|
||||
default:
|
||||
this.position = position - this.privateKeyPacket.packetLength - this.privateKeyPacket.headerLength;
|
||||
this.len = pos - position;
|
||||
return this.len;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.position = position - this.privateKeyPacket.packetLength - this.privateKeyPacket.headerLength;
|
||||
this.len = pos - position;
|
||||
|
||||
return this.len;
|
||||
}
|
||||
|
||||
function getKeyId() {
|
||||
return this.privateKeyPacket.publicKey.getKeyId();
|
||||
}
|
||||
|
||||
|
||||
function getSubKeyIds() {
|
||||
if (this.privateKeyPacket.publicKey.version == 4) // V3 keys MUST NOT have subkeys.
|
||||
var result = new Array();
|
||||
for (var i = 0; i < this.subKeys.length; i++) {
|
||||
result[i] = str_sha1(this.subKeys[i].publicKey.header+this.subKeys[i].publicKey.data).substring(12,20);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
function getSigningKey() {
|
||||
if ((this.privateKeyPacket.publicKey.publicKeyAlgorithm == 17 ||
|
||||
this.privateKeyPacket.publicKey.publicKeyAlgorithm != 2)
|
||||
&& this.privateKeyPacket.publicKey.verifyKey() == 3)
|
||||
return this.privateKeyPacket;
|
||||
else if (this.privateKeyPacket.publicKey.version == 4) // V3 keys MUST NOT have subkeys.
|
||||
for (var j = 0; j < this.privateKeyPacket.subKeys.length; j++) {
|
||||
if ((this.privateKeyPacket.subKeys[j].publicKey.publicKeyAlgorithm == 17 ||
|
||||
this.privateKeyPacket.subKeys[j].publicKey.publicKeyAlgorithm != 2) &&
|
||||
this.privateKeyPacket.subKeys[j].publicKey.verifyKey() == 3)
|
||||
return this.privateKeyPacket.subKeys[j];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getPreferredSignatureHashAlgorithm() {
|
||||
var pkey = this.getSigningKey();
|
||||
if (pkey == null) {
|
||||
util.print_error("private key is for encryption only! Cannot create a signature.")
|
||||
return null;
|
||||
}
|
||||
if (pkey.publicKey.publicKeyAlgorithm == 17) {
|
||||
var dsa = new DSA();
|
||||
return dsa.select_hash_algorithm(pkey.publicKey.MPIs[1].toBigInteger()); // q
|
||||
}
|
||||
return openpgp.config.config.prefer_hash_algorithm;
|
||||
|
||||
}
|
||||
|
||||
function decryptSecretMPIs(str_passphrase) {
|
||||
return this.privateKeyPacket.decryptSecretMPIs(str_passphrase);
|
||||
}
|
||||
|
||||
function getFingerprint() {
|
||||
return this.privateKeyPacket.publicKey.getFingerprint();
|
||||
}
|
||||
|
||||
// TODO need to implement this
|
||||
function revoke() {
|
||||
|
||||
}
|
||||
this.getSigningKey = getSigningKey;
|
||||
this.getFingerprint = getFingerprint;
|
||||
this.getPreferredSignatureHashAlgorithm = getPreferredSignatureHashAlgorithm;
|
||||
this.read_nodes = read_nodes;
|
||||
this.decryptSecretMPIs = decryptSecretMPIs;
|
||||
this.getSubKeyIds = getSubKeyIds;
|
||||
this.getKeyId = getKeyId;
|
||||
|
||||
}
|
||||
252
src/openpgp.msg.publickey.js
Executable file
252
src/openpgp.msg.publickey.js
Executable file
@@ -0,0 +1,252 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
function openpgp_msg_publickey() {
|
||||
this.data;
|
||||
this.position;
|
||||
this.len;
|
||||
this.tostring = "OPENPGP PUBLIC KEY\n";
|
||||
this.bindingSignature = null;
|
||||
this.publicKeyPacket = null;
|
||||
this.userIds = new Array();
|
||||
this.userAttributes = new Array();
|
||||
this.revocationSignatures = new Array();
|
||||
this.subKeys = new Array();
|
||||
this.arbitraryPacket = new Array();
|
||||
this.directSignatures = new Array();
|
||||
/**
|
||||
*
|
||||
* @return last position
|
||||
*/
|
||||
function read_nodes(parent_node, input, position, len) {
|
||||
this.publicKeyPacket = parent_node;
|
||||
var exit = false;
|
||||
var pos = position;
|
||||
var l = len;
|
||||
while (input.length != pos) {
|
||||
var result = openpgp_packet.read_packet(input, pos, input.length - pos);
|
||||
if (result == null) {
|
||||
util.print_error("openpgp.msg.publickey read_nodes:\n"+'[pub_key]parsing ends here @:' + pos + " l:" + l);
|
||||
break;
|
||||
} else {
|
||||
switch (result.tagType) {
|
||||
case 2: // public key revocation signature
|
||||
if (result.signatureType == 32)
|
||||
this.revocationSignatures[this.revocationSignatures.length] = result;
|
||||
else if (result.signatureType == 19)
|
||||
this.certificationSignature = result;
|
||||
else if (result.signatureType == 25) {
|
||||
this.bindingSignature = result;
|
||||
} else if (result.signatureType == 31) {
|
||||
this.directSignatures[this.directSignatures.length] = result;
|
||||
} else
|
||||
util.print_error("openpgp.msg.publickey read_nodes:\n"+"unknown signature type directly on key "+result.signatureType);
|
||||
pos += result.packetLength + result.headerLength;
|
||||
break;
|
||||
case 14: // Public-Subkey Packet
|
||||
this.subKeys[this.subKeys.length] = result;
|
||||
pos += result.packetLength + result.headerLength;
|
||||
pos += result.read_nodes(this.publicKeyPacket,input, pos, input.length - pos);
|
||||
break;
|
||||
case 17: // User Attribute Packet
|
||||
this.userAttributes[this.userAttributes.length] = result;
|
||||
pos += result.packetLength + result.headerLength;
|
||||
pos += result.read_nodes(this.publicKeyPacket,input, pos, input.length - pos);
|
||||
break;
|
||||
case 13: // User ID Packet
|
||||
this.userIds[this.userIds.length] = result;
|
||||
pos += result.packetLength + result.headerLength;
|
||||
pos += result.read_nodes(this.publicKeyPacket, input, pos, input.length - pos);
|
||||
break;
|
||||
default:
|
||||
this.data = input;
|
||||
this.position = position - this.publicKeyPacket.packetLength - this.publicKeyPacket.headerLength;
|
||||
this.len = pos - position;
|
||||
return this.len;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.data = input;
|
||||
this.position = position - (this.publicKeyPacket.packetLength - this.publicKeyPacket.headerLength);
|
||||
this.len = pos - position;
|
||||
return this.len;
|
||||
}
|
||||
|
||||
function write() {
|
||||
|
||||
}
|
||||
|
||||
function getKeyId() {
|
||||
return this.publicKeyPacket.getKeyId();
|
||||
}
|
||||
|
||||
function getFingerprint() {
|
||||
return this.publicKeyPacket.getFingerprint();
|
||||
}
|
||||
|
||||
|
||||
|
||||
function validate() {
|
||||
// check revocation keys
|
||||
for (var i = 0; i < this.revocationSignatures.length; i++) {
|
||||
var tohash = this.publicKeyPacket.header+this.publicKeyPacket.data;
|
||||
if (this.revocationSignatures[i].verify(tohash, this.publicKeyPacket))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.subKeys.length != 0) {
|
||||
// search for a valid subkey
|
||||
var found = false;
|
||||
for (var i = 0; i < this.subKeys.length; i++)
|
||||
if (this.subKeys[i].verifyKey() == 3) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (!found)
|
||||
return false;
|
||||
}
|
||||
// search for one valid userid
|
||||
found = false;
|
||||
for (var i = 0; i < this.userIds.length; i++)
|
||||
if (this.userIds[i].verify(this.publicKeyPacket) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (!found)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* verifies all signatures
|
||||
* @return a 2 dimensional array. the first dimension corresponds to the userids available
|
||||
*/
|
||||
function verifyCertificationSignatures() {
|
||||
var result = new Array();
|
||||
for (var i = 0; i < this.userIds.length; i++) {
|
||||
result[i] = this.userIds[i].verifyCertificationSignatures(this.publicKeyPacket);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
this.verifyCertificationSignatures = verifyCertificationSignatures;
|
||||
|
||||
/**
|
||||
* verifies:
|
||||
* - revocation certificates directly on key
|
||||
* - self signatures
|
||||
* - subkey binding and revocation certificates
|
||||
*
|
||||
* This is useful for validating the key
|
||||
* @returns true if the basic signatures are all valid
|
||||
*/
|
||||
function verifyBasicSignatures() {
|
||||
for (var i = 0; i < this.revocationSignatures.length; i++) {
|
||||
var tohash = this.publicKeyPacket.header+this.publicKeyPacket.data;
|
||||
if (this.revocationSignatures[i].verify(tohash, this.publicKeyPacket))
|
||||
return false;
|
||||
else return false;
|
||||
}
|
||||
|
||||
if (this.subKeys.length != 0) {
|
||||
// search for a valid subkey
|
||||
var found = false;
|
||||
for (var i = 0; i < this.subKeys.length; i++) {
|
||||
if (this.subKeys[i] == null)
|
||||
continue;
|
||||
var result = this.subKeys[i].verifyKey();
|
||||
if (result == 3) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
return false;
|
||||
}
|
||||
var keyId = this.getKeyId();
|
||||
for (var i = 0; i < this.userIds.length; i++) {
|
||||
for (var j = 0; j < this.userIds[i].certificationRevocationSignatures.length; j++) {
|
||||
if (this.userIds[i].certificationSignatures[j].getIssuer == keyId &&
|
||||
this.userIds[i].certificationSignatures[j].verifyBasic(this.publicKeyPacket) != 4)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function toString() {
|
||||
var result = " OPENPGP Public Key\n length: "+this.len+"\n";
|
||||
result += " Revocation Signatures:\n"
|
||||
for (var i=0; i < this.revocationSignatures.length; i++) {
|
||||
result += " "+this.revocationSignatures[i].toString();
|
||||
}
|
||||
result += " User Ids:\n";
|
||||
for (var i=0; i < this.userIds.length; i++) {
|
||||
result += " "+this.userIds[i].toString();
|
||||
}
|
||||
result += " User Attributes:\n";
|
||||
for (var i=0; i < this.userAttributes.length; i++) {
|
||||
result += " "+this.userAttributes[i].toString();
|
||||
}
|
||||
result += " Public Key SubKeys:\n";
|
||||
for (var i=0; i < this.subKeys.length; i++) {
|
||||
result += " "+this.subKeys[i].toString();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* finds an encryption key for this public key
|
||||
* @returns null if no encryption key has been found
|
||||
*/
|
||||
function getEncryptionKey() {
|
||||
if (this.publicKeyPacket.publicKeyAlgorithm != 17 && this.publicKeyPacket.publicKeyAlgorithm != 3
|
||||
&& this.publicKeyPacket.verifyKey())
|
||||
return this.publicKeyPacket;
|
||||
else if (this.publicKeyPacket.version == 4) // V3 keys MUST NOT have subkeys.
|
||||
for (var j = 0; j < this.subKeys.length; j++)
|
||||
if (this.subKeys[j].publicKeyAlgorithm != 17 &&
|
||||
this.subKeys[j].publicKeyAlgorithm != 3 &&
|
||||
this.subKeys[j].verifyKey()) {
|
||||
return this.subKeys[j];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getSigningKey() {
|
||||
if ((this.publicKeyPacket.publicKeyAlgorithm == 17 ||
|
||||
this.publicKeyPacket.publicKeyAlgorithm != 2))
|
||||
return this.publicKeyPacket;
|
||||
else if (this.publicKeyPacket.version == 4) // V3 keys MUST NOT have subkeys.
|
||||
for (var j = 0; j < this.subKeys.length; j++) {
|
||||
if ((this.subKeys[j].publicKeyAlgorithm == 17 ||
|
||||
this.subKeys[j].publicKeyAlgorithm != 2) &&
|
||||
this.subKeys[j].verifyKey())
|
||||
return this.subKeys[j];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
this.getEncryptionKey = getEncryptionKey;
|
||||
this.getSigningKey = getSigningKey;
|
||||
this.read_nodes = read_nodes;
|
||||
this.write = write;
|
||||
this.toString = toString;
|
||||
this.validate = validate;
|
||||
this.getFingerprint = getFingerprint;
|
||||
this.getKeyId = getKeyId;
|
||||
this.verifyBasicSignatures = verifyBasicSignatures;
|
||||
}
|
||||
145
src/packet/openpgp.packet.compressed.js
Executable file
145
src/packet/openpgp.packet.compressed.js
Executable file
@@ -0,0 +1,145 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* Implementation of the Compressed Data Packet (Tag 8)
|
||||
*
|
||||
* RFC4880 5.6:
|
||||
* The Compressed Data packet contains compressed data. Typically, this
|
||||
* packet is found as the contents of an encrypted packet, or following
|
||||
* a Signature or One-Pass Signature packet, and contains a literal data
|
||||
* packet.
|
||||
*/
|
||||
function openpgp_packet_compressed() {
|
||||
this.tagType = 8;
|
||||
|
||||
/**
|
||||
* parsing function for the packet.
|
||||
* @param input [string] payload of a tag 8 packet
|
||||
* @param position [integer] position to start reading from the input string
|
||||
* @param len [integer] length of the packet or the remaining length of input at position
|
||||
* @return [openpgp_packet_compressed] object representation
|
||||
*/
|
||||
function read_packet (input, position, len) {
|
||||
this.packetLength = len;
|
||||
var mypos = position;
|
||||
// One octet that gives the algorithm used to compress the packet.
|
||||
this.type = input.charCodeAt(mypos++);
|
||||
// Compressed data, which makes up the remainder of the packet.
|
||||
this.compressedData = input.substring(position+1, position+len);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* decompression method for decompressing the compressed data
|
||||
* read by read_packet
|
||||
* @return [String] the decompressed data
|
||||
*/
|
||||
function decompress() {
|
||||
if (this.decompressedData != null)
|
||||
return this.decompressedData;
|
||||
|
||||
if (this.type == null)
|
||||
return null;
|
||||
|
||||
switch (this.type) {
|
||||
case 0: // - Uncompressed
|
||||
this.decompressedData = this.compressedData;
|
||||
break;
|
||||
case 1: // - ZIP [RFC1951]
|
||||
util.print_error("Compression algorithm ZIP [RFC1951] is not implemented.");
|
||||
break;
|
||||
case 2: // - ZLIB [RFC1950]
|
||||
// TODO: need to implement this
|
||||
this.decompressedData = JXG.decompress(s2r(this.compressedData).replace(/\n/g,""));
|
||||
util.print_error("Compression algorithm ZLIB [RFC1950] is not implemented.");
|
||||
break;
|
||||
case 3: // - BZip2 [BZ2]
|
||||
// TODO: need to implement this
|
||||
util.print_error("Compression algorithm BZip2 [BZ2] is not implemented.");
|
||||
break;
|
||||
default:
|
||||
util.print_error("Compression algorithm unknown :"+this.type);
|
||||
break;
|
||||
}
|
||||
util.print_debug("decompressed:"+util.hexstrdump(this.decompressedData));
|
||||
return this.decompressedData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compress the packet data (member decompressedData)
|
||||
* @param type [integer] algorithm to be used // See RFC 4880 9.3
|
||||
* @param data [String] data to be compressed
|
||||
* @return [String] The compressed data stored in attribute compressedData
|
||||
*/
|
||||
function compress(type, data) {
|
||||
this.type = type;
|
||||
this.decompressedData = data;
|
||||
switch (this.type) {
|
||||
case 0: // - Uncompressed
|
||||
this.compressedData = this.decompressedData;
|
||||
break;
|
||||
case 1: // - ZIP [RFC1951]
|
||||
util.print_error("Compression algorithm ZIP [RFC1951] is not implemented.");
|
||||
break;
|
||||
case 2: // - ZLIB [RFC1950]
|
||||
// TODO: need to implement this
|
||||
util.print_error("Compression algorithm ZLIB [RFC1950] is not implemented.");
|
||||
break;
|
||||
case 3: // - BZip2 [BZ2]
|
||||
// TODO: need to implement this
|
||||
util.print_error("Compression algorithm BZip2 [BZ2] is not implemented.");
|
||||
break;
|
||||
default:
|
||||
util.print_error("Compression algorithm unknown :"+this.type);
|
||||
break;
|
||||
}
|
||||
this.packetLength = this.compressedData.length +1;
|
||||
return this.compressedData;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a string representation of the packet
|
||||
* @param algorithm [integer] algorithm to be used // See RFC 4880 9.3
|
||||
* @param data [String] data to be compressed
|
||||
* @return [String] string-representation of the packet
|
||||
*/
|
||||
function write_packet(algorithm, data) {
|
||||
this.decompressedData = data;
|
||||
if (algorithm == null) {
|
||||
this.type = 1;
|
||||
}
|
||||
var result = String.fromCharCode(this.type)+this.compress(this.type);
|
||||
return openpgp_packet.write_packet_header(8, result.length)+result;
|
||||
}
|
||||
|
||||
/**
|
||||
* pretty printing the packet (useful for debug purposes)
|
||||
* @return [String]
|
||||
*/
|
||||
function toString() {
|
||||
return '5.6. Compressed Data Packet (Tag 8)\n'+
|
||||
' length: '+this.packetLength+'\n'+
|
||||
' Compression Algorithm = '+this.type+'\n'+
|
||||
' Compressed Data: Byte ['+util.hexstrdump(this.compressedData)+']\n';
|
||||
}
|
||||
|
||||
this.read_packet = read_packet;
|
||||
this.toString = toString;
|
||||
this.compress = compress;
|
||||
this.decompress = decompress;
|
||||
this.write_packet = write_packet;
|
||||
};
|
||||
104
src/packet/openpgp.packet.encrypteddata.js
Executable file
104
src/packet/openpgp.packet.encrypteddata.js
Executable file
@@ -0,0 +1,104 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* Implementation of the Symmetrically Encrypted Data Packet (Tag 9)
|
||||
*
|
||||
* RFC4880 5.7: The Symmetrically Encrypted Data packet contains data encrypted
|
||||
* with a symmetric-key algorithm. When it has been decrypted, it contains other
|
||||
* packets (usually a literal data packet or compressed data packet, but in
|
||||
* theory other Symmetrically Encrypted Data packets or sequences of packets
|
||||
* that form whole OpenPGP messages).
|
||||
*/
|
||||
|
||||
function openpgp_packet_encrypteddata() {
|
||||
this.tagType = 9;
|
||||
this.packetLength = null;
|
||||
this.encryptedData = null;
|
||||
this.decryptedData = null;
|
||||
|
||||
/**
|
||||
* parsing function for the packet.
|
||||
*
|
||||
* @param input
|
||||
* [string] payload of a tag 9 packet
|
||||
* @param position
|
||||
* [integer] position to start reading from the input string
|
||||
* @param len
|
||||
* [integer] length of the packet or the remaining length of
|
||||
* input at position
|
||||
* @return [openpgp_packet_encrypteddata] object representation
|
||||
*/
|
||||
function read_packet(input, position, len) {
|
||||
var mypos = position;
|
||||
this.packetLength = len;
|
||||
// - Encrypted data, the output of the selected symmetric-key cipher
|
||||
// operating in OpenPGP's variant of Cipher Feedback (CFB) mode.
|
||||
this.encryptedData = input.substring(position, position + len);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* symmetrically decrypt the packet data
|
||||
*
|
||||
* @param symmetric_algorithm_type
|
||||
* [integer] symmetric key algorithm to use // See RFC4880 9.2
|
||||
* @param key
|
||||
* [String] key as string with the corresponding length to the
|
||||
* algorithm
|
||||
* @return the decrypted data;
|
||||
*/
|
||||
function decrypt_sym(symmetric_algorithm_type, key) {
|
||||
this.decryptedData = openpgp_crypto_symmetricDecrypt(
|
||||
symmetric_algorithm_type, key, this.encryptedData, true);
|
||||
util.print_debug("openpgp.packet.encryptedintegrityprotecteddata.js\n"+
|
||||
"data: "+util.hexstrdump(this.decryptedData));
|
||||
return this.decryptedData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string representation of the packet
|
||||
*
|
||||
* @param algo
|
||||
* [Integer] symmetric key algorithm to use // See RFC4880 9.2
|
||||
* @param key
|
||||
* [String] key as string with the corresponding length to the
|
||||
* algorithm
|
||||
* @param data
|
||||
* [String] data to be
|
||||
* @return [String] string-representation of the packet
|
||||
*/
|
||||
function write_packet(algo, key, data) {
|
||||
var result = "";
|
||||
result += openpgp_crypto_symmetricEncrypt(
|
||||
openpgp_crypto_getPrefixRandom(algo), algo, key, data, true);
|
||||
result = openpgp_packet.write_packet_header(9, result.length) + result;
|
||||
return result;
|
||||
}
|
||||
|
||||
function toString() {
|
||||
return '5.7. Symmetrically Encrypted Data Packet (Tag 9)\n'
|
||||
+ ' length: ' + this.packetLength + '\n'
|
||||
+ ' Used symmetric algorithm: ' + this.algorithmType + '\n'
|
||||
+ ' encrypted data: Bytes ['
|
||||
+ util.hexstrdump(this.encryptedData) + ']\n';
|
||||
}
|
||||
this.decrypt_sym = decrypt_sym;
|
||||
this.toString = toString;
|
||||
this.read_packet = read_packet;
|
||||
this.write_packet = write_packet;
|
||||
};
|
||||
155
src/packet/openpgp.packet.encryptedintegrityprotecteddata.js
Executable file
155
src/packet/openpgp.packet.encryptedintegrityprotecteddata.js
Executable file
@@ -0,0 +1,155 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* Implementation of the Sym. Encrypted Integrity Protected Data Packet (Tag 18)
|
||||
*
|
||||
* RFC4880 5.13: The Symmetrically Encrypted Integrity Protected Data packet is
|
||||
* a variant of the Symmetrically Encrypted Data packet. It is a new feature
|
||||
* created for OpenPGP that addresses the problem of detecting a modification to
|
||||
* encrypted data. It is used in combination with a Modification Detection Code
|
||||
* packet.
|
||||
*/
|
||||
|
||||
function openpgp_packet_encryptedintegrityprotecteddata() {
|
||||
this.tagType = 18;
|
||||
this.version = null; // integer == 1
|
||||
this.packetLength = null; // integer
|
||||
this.encryptedData = null; // string
|
||||
this.decrytpedData = null; // string
|
||||
this.hash = null; // string
|
||||
/**
|
||||
* parsing function for the packet.
|
||||
*
|
||||
* @param input
|
||||
* [string] payload of a tag 18 packet
|
||||
* @param position
|
||||
* [integer] position to start reading from the input string
|
||||
* @param len
|
||||
* [integer] length of the packet or the remaining length of
|
||||
* input at position
|
||||
* @return [openpgp_packet_encryptedintegrityprotecteddata] object
|
||||
* representation
|
||||
*/
|
||||
function read_packet(input, position, len) {
|
||||
this.packetLength = len;
|
||||
// - A one-octet version number. The only currently defined value is
|
||||
// 1.
|
||||
this.version = input[position].charCodeAt();
|
||||
if (this.version != 1) {
|
||||
util
|
||||
.print_error('openpgp.packet.encryptedintegrityprotecteddata.js\nunknown encrypted integrity protected data packet version: '
|
||||
+ this.version
|
||||
+ " , @ "
|
||||
+ position
|
||||
+ "hex:"
|
||||
+ util.hexstrdump(input));
|
||||
return null;
|
||||
}
|
||||
// - Encrypted data, the output of the selected symmetric-key cipher
|
||||
// operating in Cipher Feedback mode with shift amount equal to the
|
||||
// block size of the cipher (CFB-n where n is the block size).
|
||||
this.encryptedData = input.substring(position + 1, position + 1 + len);
|
||||
util.print_debug("openpgp.packet.encryptedintegrityprotecteddata.js\n"
|
||||
+ this.toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string representation of a Sym. Encrypted Integrity Protected
|
||||
* Data Packet (tag 18) (see RFC4880 5.13)
|
||||
*
|
||||
* @param symmetric_algorithm
|
||||
* [integer] the selected symmetric encryption algorithm to be
|
||||
* used
|
||||
* @param key
|
||||
* [String] the key of cipher blocksize length to be used
|
||||
* @param data
|
||||
* plaintext data to be encrypted within the packet
|
||||
* @return a string representation of the packet
|
||||
*/
|
||||
function write_packet(symmetric_algorithm, key, data) {
|
||||
|
||||
var prefixrandom = openpgp_crypto_getPrefixRandom(symmetric_algorithm);
|
||||
var prefix = prefixrandom
|
||||
+ prefixrandom.charAt(prefixrandom.length - 2)
|
||||
+ prefixrandom.charAt(prefixrandom.length - 1);
|
||||
var tohash = data;
|
||||
tohash += String.fromCharCode(0xD3);
|
||||
tohash += String.fromCharCode(0x14);
|
||||
util.print_debug("data to be hashed:"
|
||||
+ util.hexstrdump(prefix + tohash));
|
||||
tohash += str_sha1(prefix + tohash);
|
||||
util.print_debug("hash:"
|
||||
+ util.hexstrdump(tohash.substring(tohash.length - 20,
|
||||
tohash.length)));
|
||||
var result = openpgp_crypto_symmetricEncrypt(prefixrandom,
|
||||
symmetric_algorithm, key, tohash, false).substring(0,
|
||||
prefix.length + tohash.length);
|
||||
var header = openpgp_packet.write_packet_header(18, result.length + 1)
|
||||
+ String.fromCharCode(1);
|
||||
this.encryptedData = result;
|
||||
return header + result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts the encrypted data contained in this object read_packet must
|
||||
* have been called before
|
||||
*
|
||||
* @param symmetric_algorithm_type
|
||||
* [integer] the selected symmetric encryption algorithm to be
|
||||
* used
|
||||
* @param key
|
||||
* [String] the key of cipher blocksize length to be used
|
||||
* @return the decrypted data of this packet
|
||||
*/
|
||||
function decrypt(symmetric_algorithm_type, key) {
|
||||
this.decryptedData = openpgp_crypto_symmetricDecrypt(
|
||||
symmetric_algorithm_type, key, this.encryptedData, false);
|
||||
// there must be a modification detection code packet as the
|
||||
// last packet and everything gets hashed except the hash itself
|
||||
this.hash = str_sha1(openpgp_crypto_MDCSystemBytes(
|
||||
symmetric_algorithm_type, key, this.encryptedData)
|
||||
+ this.decryptedData.substring(0,
|
||||
this.decryptedData.length - 20));
|
||||
util.print_debug("calc hash = " + util.hexstrdump(this.hash));
|
||||
if (this.hash == this.decryptedData.substring(
|
||||
this.decryptedData.length - 20, this.decryptedData.length))
|
||||
return this.decryptedData;
|
||||
else
|
||||
util
|
||||
.print_error("Decryption stopped: discovered a modification of encrypted data.");
|
||||
return null;
|
||||
}
|
||||
|
||||
function toString() {
|
||||
return '5.13. Sym. Encrypted Integrity Protected Data Packet (Tag 18)\n'
|
||||
+ ' length: '
|
||||
+ this.packetLength
|
||||
+ '\n'
|
||||
+ ' version: '
|
||||
+ this.version
|
||||
+ '\n'
|
||||
+ ' data: Bytes ['
|
||||
+ util.hexstrdump(this.encryptedData) + ']';
|
||||
}
|
||||
|
||||
this.write_packet = write_packet;
|
||||
this.read_packet = read_packet;
|
||||
this.toString = toString;
|
||||
this.decrypt = decrypt;
|
||||
};
|
||||
242
src/packet/openpgp.packet.encryptedsessionkey.js
Executable file
242
src/packet/openpgp.packet.encryptedsessionkey.js
Executable file
@@ -0,0 +1,242 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* Public-Key Encrypted Session Key Packets (Tag 1)
|
||||
*
|
||||
* RFC4880 5.1: A Public-Key Encrypted Session Key packet holds the session key
|
||||
* used to encrypt a message. Zero or more Public-Key Encrypted Session Key
|
||||
* packets and/or Symmetric-Key Encrypted Session Key packets may precede a
|
||||
* Symmetrically Encrypted Data Packet, which holds an encrypted message. The
|
||||
* message is encrypted with the session key, and the session key is itself
|
||||
* encrypted and stored in the Encrypted Session Key packet(s). The
|
||||
* Symmetrically Encrypted Data Packet is preceded by one Public-Key Encrypted
|
||||
* Session Key packet for each OpenPGP key to which the message is encrypted.
|
||||
* The recipient of the message finds a session key that is encrypted to their
|
||||
* public key, decrypts the session key, and then uses the session key to
|
||||
* decrypt the message.
|
||||
*/
|
||||
function openpgp_packet_encryptedsessionkey() {
|
||||
|
||||
/**
|
||||
* parsing function for a publickey encrypted session key packet (tag 1).
|
||||
*
|
||||
* @param input
|
||||
* [string] payload of a tag 1 packet
|
||||
* @param position
|
||||
* [integer] position to start reading from the input string
|
||||
* @param len
|
||||
* [integer] length of the packet or the remaining length of
|
||||
* input at position
|
||||
* @return [openpgp_packet_encrypteddata] object representation
|
||||
*/
|
||||
function read_pub_key_packet(input, position, len) {
|
||||
this.tagType = 1;
|
||||
this.packetLength = len;
|
||||
var mypos = position;
|
||||
if (len < 10) {
|
||||
util
|
||||
.print_error("openpgp.packet.encryptedsessionkey.js\n" + 'invalid length');
|
||||
return null;
|
||||
}
|
||||
|
||||
this.version = input[mypos++].charCodeAt();
|
||||
this.keyId = new openpgp_type_keyid();
|
||||
this.keyId.read_packet(input, mypos);
|
||||
mypos += 8;
|
||||
this.publicKeyAlgorithmUsed = input[mypos++].charCodeAt();
|
||||
|
||||
switch (this.publicKeyAlgorithmUsed) {
|
||||
case 1:
|
||||
case 2: // RSA
|
||||
this.MPIs = new Array();
|
||||
this.MPIs[0] = new openpgp_type_mpi();
|
||||
this.MPIs[0].read(input, mypos, mypos - position);
|
||||
break;
|
||||
case 16: // Elgamal
|
||||
this.MPIs = new Array();
|
||||
this.MPIs[0] = new openpgp_type_mpi();
|
||||
this.MPIs[0].read(input, mypos, mypos - position);
|
||||
mypos += this.MPIs[0].packetLength;
|
||||
this.MPIs[1] = new openpgp_type_mpi();
|
||||
this.MPIs[1].read(input, mypos, mypos - position);
|
||||
break;
|
||||
default:
|
||||
util.print_error("openpgp.packet.encryptedsessionkey.js\n"
|
||||
+ "unknown public key packet algorithm type "
|
||||
+ this.publicKeyAlgorithmType);
|
||||
break;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* create a string representation of a tag 1 packet
|
||||
*
|
||||
* @param publicKeyId
|
||||
* [String] the public key id corresponding to publicMPIs key as
|
||||
* string
|
||||
* @param publicMPIs
|
||||
* [Array[openpgp_type_mpi]] multiprecision integer objects
|
||||
* describing the public key
|
||||
* @param pubalgo
|
||||
* [integer] the corresponding public key algorithm // See
|
||||
* RFC4880 9.1
|
||||
* @param symmalgo
|
||||
* [integer] the symmetric cipher algorithm used to encrypt the
|
||||
* data within an encrypteddatapacket or
|
||||
* encryptedintegrityprotecteddatapacket following this packet //
|
||||
* See RFC4880 9.2
|
||||
* @param sessionkey
|
||||
* [String] a string of randombytes representing the session key
|
||||
* @return [String] the string representation
|
||||
*/
|
||||
function write_pub_key_packet(publicKeyId, publicMPIs, pubalgo, symmalgo,
|
||||
sessionkey) {
|
||||
var result = String.fromCharCode(3);
|
||||
var data = String.fromCharCode(symmalgo);
|
||||
data += sessionkey;
|
||||
var checksum = util.calc_checksum(sessionkey);
|
||||
data += String.fromCharCode((checksum >> 8) & 0xFF);
|
||||
data += String.fromCharCode((checksum) & 0xFF);
|
||||
result += publicKeyId;
|
||||
result += String.fromCharCode(pubalgo);
|
||||
var mpi = new openpgp_type_mpi();
|
||||
var mpiresult = openpgp_crypto_asymetricEncrypt(pubalgo, publicMPIs,
|
||||
mpi.create(openpgp_encoding_eme_pkcs1_encode(data,
|
||||
publicMPIs[0].mpiByteLength)));
|
||||
for ( var i = 0; i < mpiresult.length; i++) {
|
||||
result += mpiresult[i];
|
||||
}
|
||||
result = openpgp_packet.write_packet_header(1, result.length) + result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* parsing function for a symmetric encrypted session key packet (tag 3).
|
||||
*
|
||||
* @param input
|
||||
* [string] payload of a tag 1 packet
|
||||
* @param position
|
||||
* [integer] position to start reading from the input string
|
||||
* @param len
|
||||
* [integer] length of the packet or the remaining length of
|
||||
* input at position
|
||||
* @return [openpgp_packet_encrypteddata] object representation
|
||||
*/
|
||||
function read_symmetric_key_packet(input, position, len) {
|
||||
this.tagType = 3;
|
||||
var mypos = position;
|
||||
// A one-octet version number. The only currently defined version is 4.
|
||||
this.version = input[mypos++];
|
||||
|
||||
// A one-octet number describing the symmetric algorithm used.
|
||||
this.symmetricKeyAlgorithmUsed = input[mypos++];
|
||||
// A string-to-key (S2K) specifier, length as defined above.
|
||||
this.s2k = new openpgp_type_s2k();
|
||||
this.s2k.read(input, mypos);
|
||||
|
||||
// Optionally, the encrypted session key itself, which is decrypted
|
||||
// with the string-to-key object.
|
||||
if ((s2k.s2kLength + mypos) < len) {
|
||||
this.encryptedSessionKey = new Array();
|
||||
for ( var i = (mypos - position); i < len; i++) {
|
||||
this.encryptedSessionKey[i] = input[mypos++];
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Decrypts the session key (only for public key encrypted session key
|
||||
* packets (tag 1)
|
||||
*
|
||||
* @param msg
|
||||
* [openpgp_msg_message] the message object (with member
|
||||
* encryptedData
|
||||
* @param key
|
||||
* [openpgp_msg_privatekey] private key with secMPIs unlocked
|
||||
* @return [String] the unencrypted session key
|
||||
*/
|
||||
function decrypt(msg, key) {
|
||||
if (this.tagType == 1) {
|
||||
var result = openpgp_crypto_asymetricDecrypt(
|
||||
this.publicKeyAlgorithmUsed, key.publicKey.MPIs,
|
||||
key.secMPIs, this.MPIs).toMPI();
|
||||
var checksum = ((result.charCodeAt(result.length - 2) << 8) + result
|
||||
.charCodeAt(result.length - 1));
|
||||
// search for zero
|
||||
// FIXME: this is a poor way to decode a padding
|
||||
var i = 0;
|
||||
while (result.charCodeAt(i) != 0 && i < result.length)
|
||||
i++;
|
||||
i++;
|
||||
if (i > result.length) {
|
||||
return null;
|
||||
}
|
||||
var algo = result.charCodeAt(i++);
|
||||
var sesskey = result.substring(i, result.length - 2);
|
||||
if (msg.encryptedData.tagType == 18)
|
||||
return msg.encryptedData.decrypt(algo, sesskey);
|
||||
else
|
||||
return msg.encryptedData.decrypt_sym(algo, sesskey);
|
||||
} else if (this.tagType == 3) {
|
||||
util
|
||||
.print_error("Symmetric encrypted sessionkey is not supported!");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string representation of this object (useful for debug
|
||||
* purposes)
|
||||
*
|
||||
* @return the string containing a openpgp description
|
||||
*/
|
||||
function toString() {
|
||||
if (this.tagType == 1) {
|
||||
var result = '5.1. Public-Key Encrypted Session Key Packets (Tag 1)\n'
|
||||
+ ' KeyId: '
|
||||
+ this.keyId.toString()
|
||||
+ '\n'
|
||||
+ ' length: '
|
||||
+ this.packetLength
|
||||
+ '\n'
|
||||
+ ' version:'
|
||||
+ this.version
|
||||
+ '\n'
|
||||
+ ' pubAlgUs:'
|
||||
+ this.publicKeyAlgorithmUsed + '\n';
|
||||
for ( var i = 0; i < this.MPIs.length; i++) {
|
||||
result += this.MPIs[i].toString();
|
||||
}
|
||||
return result;
|
||||
} else
|
||||
return '5.3 Symmetric-Key Encrypted Session Key Packets (Tag 3)\n'
|
||||
+ ' KeyId: ' + this.keyId.toString() + '\n'
|
||||
+ ' length: ' + this.packetLength + '\n'
|
||||
+ ' version:' + this.version + '\n' + ' symKeyA:'
|
||||
+ this.symmetricKeyAlgorithmUsed + '\n' + ' s2k: '
|
||||
+ this.s2k + '\n';
|
||||
}
|
||||
|
||||
this.read_pub_key_packet = read_pub_key_packet;
|
||||
this.read_symmetric_key_packet = read_symmetric_key_packet;
|
||||
this.write_pub_key_packet = write_pub_key_packet;
|
||||
this.toString = toString;
|
||||
this.decrypt = decrypt;
|
||||
};
|
||||
|
||||
409
src/packet/openpgp.packet.js
Executable file
409
src/packet/openpgp.packet.js
Executable file
@@ -0,0 +1,409 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
function _openpgp_packet() {
|
||||
/**
|
||||
* Encodes a given integer of length to the openpgp length specifier to a
|
||||
* string
|
||||
*
|
||||
* @param length
|
||||
* [Integer] of the length to encode
|
||||
* @return string with openpgp length representation
|
||||
*/
|
||||
function encode_length(length) {
|
||||
result = "";
|
||||
if (length < 192) {
|
||||
result += String.fromCharCode(length);
|
||||
} else if (length > 191 && length < 8384) {
|
||||
/*
|
||||
* let a = (total data packet length) - 192 let bc = two octet
|
||||
* representation of a let d = b + 192
|
||||
*/
|
||||
result += String.fromCharCode(((length - 192) >> 8) + 192);
|
||||
result += String.fromCharCode((length - 192) & 0xFF);
|
||||
} else {
|
||||
result += String.fromCharCode(255);
|
||||
result += String.fromCharCode((length >> 24) & 0xFF);
|
||||
result += String.fromCharCode((length >> 16) & 0xFF);
|
||||
result += String.fromCharCode((length >> 8) & 0xFF);
|
||||
result += String.fromCharCode(length & 0xFF);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
this.encode_length = encode_length;
|
||||
|
||||
/**
|
||||
* Writes a packet header version 4 with the given tag_type and length to a
|
||||
* string
|
||||
*
|
||||
* @param tag_type
|
||||
* integer of tag type
|
||||
* @param length
|
||||
* integer length of the payload
|
||||
* @return string of the header
|
||||
*/
|
||||
function write_packet_header(tag_type, length) {
|
||||
/* we're only generating v4 packet headers here */
|
||||
var result = "";
|
||||
result += String.fromCharCode(0xC0 | tag_type);
|
||||
result += encode_length(length);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a packet header Version 3 with the given tag_type and length to a
|
||||
* string
|
||||
*
|
||||
* @param tag_type
|
||||
* integer of tag type
|
||||
* @param length
|
||||
* integer length of the payload
|
||||
* @return string of the header
|
||||
*/
|
||||
function write_old_packet_header(tag_type, length) {
|
||||
var result = "";
|
||||
if (length < 256) {
|
||||
result += String.fromCharCode(0x80 | (tag_type << 2));
|
||||
result += String.fromCharCode(length);
|
||||
} else if (length < 65536) {
|
||||
result += String.fromCharCode(0x80 | (tag_type << 2) | 1);
|
||||
result += String.fromCharCode(length >> 8);
|
||||
result += String.fromCharCode(length & 0xFF);
|
||||
} else {
|
||||
result += String.fromCharCode(0x80 | (tag_type << 2) | 2);
|
||||
result += String.fromCharCode((length >> 24) & 0xFF);
|
||||
result += String.fromCharCode((length >> 16) & 0xFF);
|
||||
result += String.fromCharCode((length >> 8) & 0xFF);
|
||||
result += String.fromCharCode(length & 0xFF);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
this.write_old_packet_header = write_old_packet_header;
|
||||
this.write_packet_header = write_packet_header;
|
||||
/**
|
||||
* Generic static Packet Parser function
|
||||
*
|
||||
* @param input
|
||||
* [String] input stream as string
|
||||
* @param position
|
||||
* [integer] position to start parsing
|
||||
* @param len
|
||||
* [integer] length of the input from position on
|
||||
* @return [openpgp_packet_*] returns a parsed openpgp_packet
|
||||
*/
|
||||
function read_packet(input, position, len) {
|
||||
// some sanity checks
|
||||
if (input == null || input.length <= position
|
||||
|| input.substring(position).length < 2
|
||||
|| (input[position].charCodeAt() & 0x80) == 0) {
|
||||
util
|
||||
.print_error("Error during parsing. This message / key is propably not containing a valid OpenPGP format.");
|
||||
return null;
|
||||
}
|
||||
var mypos = position;
|
||||
var tag = -1;
|
||||
var format = -1;
|
||||
|
||||
format = 0; // 0 = old format; 1 = new format
|
||||
if ((input[mypos].charCodeAt() & 0x40) != 0) {
|
||||
format = 1;
|
||||
}
|
||||
|
||||
var packet_length_type;
|
||||
if (format) {
|
||||
// new format header
|
||||
tag = input[mypos].charCodeAt() & 0x3F; // bit 5-0
|
||||
} else {
|
||||
// old format header
|
||||
tag = (input[mypos].charCodeAt() & 0x3F) >> 2; // bit 5-2
|
||||
packet_length_type = input[mypos].charCodeAt() & 0x03; // bit 1-0
|
||||
}
|
||||
|
||||
// header octet parsing done
|
||||
mypos++;
|
||||
|
||||
// parsed length from length field
|
||||
var len = 0;
|
||||
var bodydata = null;
|
||||
|
||||
// used for partial body lengths
|
||||
var real_packet_length = -1;
|
||||
if (!format) {
|
||||
// 4.2.1. Old Format Packet Lengths
|
||||
switch (packet_length_type) {
|
||||
case 0: // The packet has a one-octet length. The header is 2 octets
|
||||
// long.
|
||||
packet_length = input[mypos++].charCodeAt();
|
||||
break;
|
||||
case 1: // The packet has a two-octet length. The header is 3 octets
|
||||
// long.
|
||||
packet_length = (input[mypos++].charCodeAt() << 8)
|
||||
| input[mypos++].charCodeAt();
|
||||
break;
|
||||
case 2: // The packet has a four-octet length. The header is 5
|
||||
// octets long.
|
||||
packet_length = (input[mypos++].charCodeAt() << 24)
|
||||
| (input[mypos++].charCodeAt() << 16)
|
||||
| (input[mypos++].charCodeAt() << 8)
|
||||
| input[mypos++].charCodeAt();
|
||||
break;
|
||||
default:
|
||||
// 3 - The packet is of indeterminate length. The header is 1
|
||||
// octet long, and the implementation must determine how long
|
||||
// the packet is. If the packet is in a file, this means that
|
||||
// the packet extends until the end of the file. In general,
|
||||
// an implementation SHOULD NOT use indeterminate-length
|
||||
// packets except where the end of the data will be clear
|
||||
// from the context, and even then it is better to use a
|
||||
// definite length, or a new format header. The new format
|
||||
// headers described below have a mechanism for precisely
|
||||
// encoding data of indeterminate length.
|
||||
}
|
||||
|
||||
} else // 4.2.2. New Format Packet Lengths
|
||||
{
|
||||
|
||||
// 4.2.2.1. One-Octet Lengths
|
||||
if (input[mypos].charCodeAt() < 192) {
|
||||
packet_length = input[mypos++].charCodeAt();
|
||||
util.print_debug("1 byte length:" + packet_length);
|
||||
// 4.2.2.2. Two-Octet Lengths
|
||||
} else if (input[mypos].charCodeAt() >= 192
|
||||
&& input[mypos].charCodeAt() < 224) {
|
||||
packet_length = ((input[mypos++].charCodeAt() - 192) << 8)
|
||||
+ (input[mypos++].charCodeAt()) + 192;
|
||||
util.print_debug("2 byte length:" + packet_length);
|
||||
// 4.2.2.4. Partial Body Lengths
|
||||
} else if (input[mypos].charCodeAt() > 223
|
||||
&& input[mypos].charCodeAt() < 255) {
|
||||
packet_length = 1 << (input[mypos++].charCodeAt() & 0x1F);
|
||||
util.print_debug("4 byte length:" + packet_length);
|
||||
// EEEK, we're reading the full data here...
|
||||
var mypos2 = mypos + packet_length;
|
||||
bodydata = input.substring(mypos, mypos + packet_length);
|
||||
while (true) {
|
||||
if (input[mypos2].charCodeAt() < 192) {
|
||||
var tmplen = input[mypos2++].charCodeAt();
|
||||
packet_length += tmplen;
|
||||
bodydata += input.substring(mypos2, mypos2 + tmplen);
|
||||
mypos2 += tmplen;
|
||||
break;
|
||||
} else if (input[mypos2].charCodeAt() >= 192
|
||||
&& input[mypos2].charCodeAt() < 224) {
|
||||
var tmplen = ((input[mypos2++].charCodeAt() - 192) << 8)
|
||||
+ (input[mypos2++].charCodeAt()) + 192;
|
||||
packet_length += tmplen;
|
||||
bodydata += input.substring(mypos2, mypos2 + tmplen);
|
||||
mypos2 += tmplen;
|
||||
break;
|
||||
} else if (input[mypos2].charCodeAt() > 223
|
||||
&& input[mypos2].charCodeAt() < 255) {
|
||||
var tmplen = 1 << (input[mypos2++].charCodeAt() & 0x1F);
|
||||
packet_length += tmplen;
|
||||
bodydata += input.substring(mypos2, mypos2 + tmplen);
|
||||
mypos2 += tmplen;
|
||||
} else {
|
||||
mypos2++;
|
||||
var tmplen = (input[mypos2++].charCodeAt() << 24)
|
||||
| (input[mypos2++].charCodeAt() << 16)
|
||||
| (input[mypos2++].charCodeAt() << 8)
|
||||
| input[mypos2++].charCodeAt();
|
||||
bodydata += input.substring(mypos2, mypos2 + tmplen);
|
||||
packet_length += tmplen;
|
||||
mypos2 += tmplen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
real_packet_length = mypos2;
|
||||
// 4.2.2.3. Five-Octet Lengths
|
||||
} else {
|
||||
mypos++;
|
||||
packet_length = (input[mypos++].charCodeAt() << 24)
|
||||
| (input[mypos++].charCodeAt() << 16)
|
||||
| (input[mypos++].charCodeAt() << 8)
|
||||
| input[mypos++].charCodeAt();
|
||||
}
|
||||
}
|
||||
|
||||
// if there was'nt a partial body length: use the specified
|
||||
// packet_length
|
||||
if (real_packet_length == -1) {
|
||||
real_packet_length = packet_length;
|
||||
}
|
||||
|
||||
if (bodydata == null) {
|
||||
bodydata = input.substring(mypos, mypos + real_packet_length);
|
||||
}
|
||||
|
||||
// alert('tag type: '+this.tag+' length: '+packet_length);
|
||||
var version = 1; // (old format; 2= new format)
|
||||
// if (input[mypos++].charCodeAt() > 15)
|
||||
// version = 2;
|
||||
|
||||
switch (tag) {
|
||||
case 0: // Reserved - a packet tag MUST NOT have this value
|
||||
break;
|
||||
case 1: // Public-Key Encrypted Session Key Packet
|
||||
var result = new openpgp_packet_encryptedsessionkey();
|
||||
if (result.read_pub_key_packet(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 2: // Signature Packet
|
||||
var result = new openpgp_packet_signature();
|
||||
if (result.read_packet(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 3: // Symmetric-Key Encrypted Session Key Packet
|
||||
var result = new openpgp_packet_encryptedsessionkey();
|
||||
if (result.read_symmetric_key_packet(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 4: // One-Pass Signature Packet
|
||||
var result = new openpgp_packet_onepasssignature();
|
||||
if (result.read_packet(bodydata, 0, packet_length)) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 5: // Secret-Key Packet
|
||||
var result = new openpgp_packet_keymaterial();
|
||||
result.header = input.substring(position, mypos);
|
||||
if (result.read_tag5(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 6: // Public-Key Packet
|
||||
var result = new openpgp_packet_keymaterial();
|
||||
result.header = input.substring(position, mypos);
|
||||
if (result.read_tag6(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 7: // Secret-Subkey Packet
|
||||
var result = new openpgp_packet_keymaterial();
|
||||
if (result.read_tag7(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 8: // Compressed Data Packet
|
||||
var result = new openpgp_packet_compressed();
|
||||
if (result.read_packet(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 9: // Symmetrically Encrypted Data Packet
|
||||
var result = new openpgp_packet_encrypteddata();
|
||||
if (result.read_packet(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 10: // Marker Packet = PGP (0x50, 0x47, 0x50)
|
||||
var result = new openpgp_packet_marker();
|
||||
if (result.read_packet(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 11: // Literal Data Packet
|
||||
var result = new openpgp_packet_literaldata();
|
||||
if (result.read_packet(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.header = input.substring(position, mypos);
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 12: // Trust Packet
|
||||
// TODO: to be implemented
|
||||
break;
|
||||
case 13: // User ID Packet
|
||||
var result = new openpgp_packet_userid();
|
||||
if (result.read_packet(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 14: // Public-Subkey Packet
|
||||
var result = new openpgp_packet_keymaterial();
|
||||
result.header = input.substring(position, mypos);
|
||||
if (result.read_tag14(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 17: // User Attribute Packet
|
||||
var result = new openpgp_packet_userattribute();
|
||||
if (result.read_packet(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 18: // Sym. Encrypted and Integrity Protected Data Packet
|
||||
var result = new openpgp_packet_encryptedintegrityprotecteddata();
|
||||
if (result.read_packet(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case 19: // Modification Detection Code Packet
|
||||
var result = new openpgp_packet_modificationdetectioncode();
|
||||
if (result.read_packet(bodydata, 0, packet_length) != null) {
|
||||
result.headerLength = mypos - position;
|
||||
result.packetLength = real_packet_length;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
util.print_error("openpgp.packet.js\n"
|
||||
+ "[ERROR] openpgp_packet: failed to parse packet @:"
|
||||
+ mypos + "\nchar:'"
|
||||
+ util.hexstrdump(input.substring(mypos)) + "'\ninput:"
|
||||
+ util.hexstrdump(input));
|
||||
return null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.read_packet = read_packet;
|
||||
}
|
||||
|
||||
var openpgp_packet = new _openpgp_packet();
|
||||
689
src/packet/openpgp.packet.keymaterial.js
Executable file
689
src/packet/openpgp.packet.keymaterial.js
Executable file
@@ -0,0 +1,689 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* Implementation of the Key Material Packet (Tag 5,6,7,14)
|
||||
*
|
||||
* RFC4480 5.5:
|
||||
* A key material packet contains all the information about a public or
|
||||
* private key. There are four variants of this packet type, and two
|
||||
* major versions. Consequently, this section is complex.
|
||||
*/
|
||||
function openpgp_packet_keymaterial() {
|
||||
// members:
|
||||
this.publicKeyAlgorithm = null;
|
||||
this.tagType = null;
|
||||
this.creationTime = null;
|
||||
this.version = null;
|
||||
this.expiration = null;// V3
|
||||
this.MPIs = null;
|
||||
this.secMPIs = null;
|
||||
this.publicKey = null;
|
||||
this.symmetricEncryptionAlgorithm = null;
|
||||
this.s2kUsageConventions = null;
|
||||
this.IVLength = null;
|
||||
this.encryptedMPIData = null;
|
||||
this.hasUnencryptedSecretKeyData = null;
|
||||
this.checksum = null;
|
||||
this.parentNode = null;
|
||||
this.subKeySignature = null;
|
||||
this.subKeyRevocationSignature = null;
|
||||
|
||||
// 5.5.1. Key Packet Variants
|
||||
|
||||
// 5.5.1.3. Secret-Key Packet (Tag 5)
|
||||
/**
|
||||
* This function reads the payload of a secret key packet (Tag 5)
|
||||
* and initializes the openpgp_packet_keymaterial
|
||||
* @param input input string to read the packet from
|
||||
* @param position start position for the parser
|
||||
* @param len length of the packet or remaining length of input
|
||||
* @return openpgp_packet_keymaterial object
|
||||
*/
|
||||
function read_tag5(input, position, len) {
|
||||
this.tagType = 5;
|
||||
this.read_priv_key(input, position, len);
|
||||
return this;
|
||||
}
|
||||
|
||||
// 5.5.1.1. Public-Key Packet (Tag 6)
|
||||
/**
|
||||
* This function reads the payload of a public key packet (Tag 6)
|
||||
* and initializes the openpgp_packet_keymaterial
|
||||
* @param input input string to read the packet from
|
||||
* @param position start position for the parser
|
||||
* @param len length of the packet or remaining length of input
|
||||
* @return openpgp_packet_keymaterial object
|
||||
*/
|
||||
function read_tag6(input, position, len) {
|
||||
// A Public-Key packet starts a series of packets that forms an OpenPGP
|
||||
// key (sometimes called an OpenPGP certificate).
|
||||
this.tagType = 6;
|
||||
this.packetLength = len;
|
||||
this.read_pub_key(input, position,len);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// 5.5.1.4. Secret-Subkey Packet (Tag 7)
|
||||
/**
|
||||
* This function reads the payload of a secret key sub packet (Tag 7)
|
||||
* and initializes the openpgp_packet_keymaterial
|
||||
* @param input input string to read the packet from
|
||||
* @param position start position for the parser
|
||||
* @param len length of the packet or remaining length of input
|
||||
* @return openpgp_packet_keymaterial object
|
||||
*/
|
||||
function read_tag7(input, position, len) {
|
||||
this.tagType = 7;
|
||||
this.packetLength = len;
|
||||
return this.read_priv_key(input, position, len);
|
||||
}
|
||||
|
||||
// 5.5.1.2. Public-Subkey Packet (Tag 14)
|
||||
/**
|
||||
* This function reads the payload of a public key sub packet (Tag 14)
|
||||
* and initializes the openpgp_packet_keymaterial
|
||||
* @param input input string to read the packet from
|
||||
* @param position start position for the parser
|
||||
* @param len length of the packet or remaining length of input
|
||||
* @return openpgp_packet_keymaterial object
|
||||
*/
|
||||
function read_tag14(input, position, len) {
|
||||
this.subKeySignature = null;
|
||||
this.subKeyRevocationSignature = new Array();
|
||||
this.tagType = 14;
|
||||
this.packetLength = len;
|
||||
this.read_pub_key(input, position,len);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal Parser for public keys as specified in RFC 4880 section 5.5.2 Public-Key Packet Formats
|
||||
* called by read_tag<num>
|
||||
* @param input input string to read the packet from
|
||||
* @param position start position for the parser
|
||||
* @param len length of the packet or remaining length of input
|
||||
* @return this object with attributes set by the parser
|
||||
*/
|
||||
function read_pub_key(input, position, len) {
|
||||
var mypos = position;
|
||||
// A one-octet version number (3 or 4).
|
||||
this.version = input[mypos++].charCodeAt();
|
||||
if (this.version == 3) {
|
||||
// A four-octet number denoting the time that the key was created.
|
||||
this.creationTime = new Date(((input[mypos++].charCodeAt() << 24) |
|
||||
(input[mypos++].charCodeAt() << 16) |
|
||||
(input[mypos++].charCodeAt() << 8) |
|
||||
(input[mypos++].charCodeAt()))*1000);
|
||||
|
||||
// - A two-octet number denoting the time in days that this key is
|
||||
// valid. If this number is zero, then it does not expire.
|
||||
this.expiration = (input[mypos++].charCodeAt() << 8) & input[mypos++].charCodeAt();
|
||||
|
||||
// - A one-octet number denoting the public-key algorithm of this key.
|
||||
this.publicKeyAlgorithm = input[mypos++].charCodeAt();
|
||||
var mpicount = 0;
|
||||
// - A series of multiprecision integers comprising the key material:
|
||||
// Algorithm-Specific Fields for RSA public keys:
|
||||
// - a multiprecision integer (MPI) of RSA public modulus n;
|
||||
// - an MPI of RSA public encryption exponent e.
|
||||
if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4)
|
||||
mpicount = 2;
|
||||
// Algorithm-Specific Fields for Elgamal public keys:
|
||||
// - MPI of Elgamal prime p;
|
||||
// - MPI of Elgamal group generator g;
|
||||
// - MPI of Elgamal public key value y (= g**x mod p where x is secret).
|
||||
|
||||
else if (this.publicKeyAlgorithm == 16)
|
||||
mpicount = 3;
|
||||
// Algorithm-Specific Fields for DSA public keys:
|
||||
// - MPI of DSA prime p;
|
||||
// - MPI of DSA group order q (q is a prime divisor of p-1);
|
||||
// - MPI of DSA group generator g;
|
||||
// - MPI of DSA public-key value y (= g**x mod p where x is secret).
|
||||
else if (this.publicKeyAlgorithm == 17)
|
||||
mpicount = 4;
|
||||
|
||||
this.MPIs = new Array();
|
||||
for (var i = 0; i < mpicount; i++) {
|
||||
this.MPIs[i] = new openpgp_type_mpi();
|
||||
if (this.MPIs[i].read(input, mypos, (mypos-position)) != null &&
|
||||
!this.packetLength < (mypos-position)) {
|
||||
mypos += this.MPIs[i].packetLength;
|
||||
} else {
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+'error reading MPI @:'+mypos);
|
||||
}
|
||||
}
|
||||
this.packetLength = mypos-position;
|
||||
} else if (this.version == 4) {
|
||||
// - A four-octet number denoting the time that the key was created.
|
||||
this.creationTime = new Date(((input[mypos++].charCodeAt() << 24) |
|
||||
(input[mypos++].charCodeAt() << 16) |
|
||||
(input[mypos++].charCodeAt() << 8) |
|
||||
(input[mypos++].charCodeAt()))*1000);
|
||||
|
||||
// - A one-octet number denoting the public-key algorithm of this key.
|
||||
this.publicKeyAlgorithm = input[mypos++].charCodeAt();
|
||||
var mpicount = 0;
|
||||
// - A series of multiprecision integers comprising the key material:
|
||||
// Algorithm-Specific Fields for RSA public keys:
|
||||
// - a multiprecision integer (MPI) of RSA public modulus n;
|
||||
// - an MPI of RSA public encryption exponent e.
|
||||
if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4)
|
||||
mpicount = 2;
|
||||
// Algorithm-Specific Fields for Elgamal public keys:
|
||||
// - MPI of Elgamal prime p;
|
||||
// - MPI of Elgamal group generator g;
|
||||
// - MPI of Elgamal public key value y (= g**x mod p where x is secret).
|
||||
else if (this.publicKeyAlgorithm == 16)
|
||||
mpicount = 3;
|
||||
|
||||
// Algorithm-Specific Fields for DSA public keys:
|
||||
// - MPI of DSA prime p;
|
||||
// - MPI of DSA group order q (q is a prime divisor of p-1);
|
||||
// - MPI of DSA group generator g;
|
||||
// - MPI of DSA public-key value y (= g**x mod p where x is secret).
|
||||
else if (this.publicKeyAlgorithm == 17)
|
||||
mpicount = 4;
|
||||
|
||||
this.MPIs = new Array();
|
||||
var i = 0;
|
||||
for (var i = 0; i < mpicount; i++) {
|
||||
this.MPIs[i] = new openpgp_type_mpi();
|
||||
if (this.MPIs[i].read(input, mypos, (mypos-position)) != null &&
|
||||
!this.packetLength < (mypos-position)) {
|
||||
mypos += this.MPIs[i].packetLength;
|
||||
} else {
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+'error reading MPI @:'+mypos);
|
||||
}
|
||||
}
|
||||
this.packetLength = mypos-position;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
this.data = input.substring(position, mypos);
|
||||
this.packetdata = input.substring(position, mypos);
|
||||
return this;
|
||||
}
|
||||
|
||||
// 5.5.3. Secret-Key Packet Formats
|
||||
|
||||
/**
|
||||
* Internal parser for private keys as specified in RFC 4880 section 5.5.3
|
||||
* @param input input string to read the packet from
|
||||
* @param position start position for the parser
|
||||
* @param len length of the packet or remaining length of input
|
||||
* @return this object with attributes set by the parser
|
||||
*/
|
||||
function read_priv_key(input,position, len) {
|
||||
// - A Public-Key or Public-Subkey packet, as described above.
|
||||
this.publicKey = new openpgp_packet_keymaterial();
|
||||
if (this.publicKey.read_pub_key(input,position, len) == null) {
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+"Failed reading public key portion of a private key: "+input[position].charCodeAt()+" "+position+" "+len+"\n Aborting here...");
|
||||
return null;
|
||||
}
|
||||
this.publicKey.header = openpgp_packet.write_old_packet_header(6,this.publicKey.packetLength);
|
||||
// this.publicKey.header = String.fromCharCode(0x99) + String.fromCharCode(this.publicKey.packetLength >> 8 & 0xFF)+String.fromCharCode(this.publicKey.packetLength & 0xFF);
|
||||
var mypos = position + this.publicKey.data.length;
|
||||
this.packetLength = len;
|
||||
|
||||
// - One octet indicating string-to-key usage conventions. Zero
|
||||
// indicates that the secret-key data is not encrypted. 255 or 254
|
||||
// indicates that a string-to-key specifier is being given. Any
|
||||
// other value is a symmetric-key encryption algorithm identifier.
|
||||
this.s2kUsageConventions = input[mypos++].charCodeAt();
|
||||
|
||||
if (this.s2kUsageConventions == 0)
|
||||
this.hasUnencryptedSecretKeyData = true;
|
||||
|
||||
// - [Optional] If string-to-key usage octet was 255 or 254, a one-
|
||||
// octet symmetric encryption algorithm.
|
||||
if (this.s2kUsageConventions == 255 || this.s2kUsageConventions == 254) {
|
||||
this.symmetricEncryptionAlgorithm = input[mypos++].charCodeAt();
|
||||
}
|
||||
|
||||
// - [Optional] If string-to-key usage octet was 255 or 254, a
|
||||
// string-to-key specifier. The length of the string-to-key
|
||||
// specifier is implied by its type, as described above.
|
||||
if (this.s2kUsageConventions == 255 || this.s2kUsageConventions == 254) {
|
||||
this.s2k = new openpgp_type_s2k();
|
||||
this.s2k.read(input, mypos);
|
||||
mypos +=this.s2k.s2kLength;
|
||||
}
|
||||
|
||||
// - [Optional] If secret data is encrypted (string-to-key usage octet
|
||||
// not zero), an Initial Vector (IV) of the same length as the
|
||||
// cipher's block size.
|
||||
this.symkeylength = 0;
|
||||
if (this.s2kUsageConventions != 0 && this.s2kUsageConventions != 255 &&
|
||||
this.s2kUsageConventions != 254) {
|
||||
this.symmetricEncryptionAlgorithm = this.s2kUsageConventions;
|
||||
}
|
||||
if (this.s2kUsageConventions != 0) {
|
||||
this.hasIV = true;
|
||||
switch (this.symmetricEncryptionAlgorithm) {
|
||||
case 1: // - IDEA [IDEA]
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+"symmetric encrytryption algorithim: IDEA is not implemented");
|
||||
return null;
|
||||
case 2: // - TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
|
||||
case 3: // - CAST5 (128 bit key, as per [RFC2144])
|
||||
this.IVLength = 8;
|
||||
break;
|
||||
case 4: // - Blowfish (128 bit key, 16 rounds) [BLOWFISH]
|
||||
case 7: // - AES with 128-bit key [AES]
|
||||
case 8: // - AES with 192-bit key
|
||||
case 9: // - AES with 256-bit key
|
||||
this.IVLength = 16;
|
||||
break;
|
||||
case 10: // - Twofish with 256-bit key [TWOFISH]
|
||||
this.IVLength = 32;
|
||||
break;
|
||||
case 5: // - Reserved
|
||||
case 6: // - Reserved
|
||||
default:
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+"unknown encryption algorithm for secret key :"+this.symmetricEncryptionAlgorithm);
|
||||
return null;
|
||||
}
|
||||
mypos++;
|
||||
this.IV = input.substring(mypos, mypos+this.IVLength);
|
||||
mypos += this.IVLength;
|
||||
}
|
||||
// - Plain or encrypted multiprecision integers comprising the secret
|
||||
// key data. These algorithm-specific fields are as described
|
||||
// below.
|
||||
|
||||
//
|
||||
//
|
||||
if (!this.hasUnencryptedSecretKeyData) {
|
||||
this.encryptedMPIData = input.substring(mypos, len);
|
||||
mypos += this.encryptedMPIData.length;
|
||||
} else {
|
||||
if (this.publicKey.publicKeyAlgorithm > 0 && this.publicKey.publicKeyAlgorithm < 4) {
|
||||
// Algorithm-Specific Fields for RSA secret keys:
|
||||
// - multiprecision integer (MPI) of RSA secret exponent d.
|
||||
// - MPI of RSA secret prime value p.
|
||||
// - MPI of RSA secret prime value q (p < q).
|
||||
// - MPI of u, the multiplicative inverse of p, mod q.
|
||||
this.secMPIs = new Array();
|
||||
this.secMPIs[0] = new openpgp_type_mpi();
|
||||
this.secMPIs[0].read(input, mypos, len-2- (mypos - position));
|
||||
mypos += this.secMPIs[0].packetLength;
|
||||
this.secMPIs[1] = new openpgp_type_mpi();
|
||||
this.secMPIs[1].read(input, mypos, len-2- (mypos - position));
|
||||
mypos += this.secMPIs[1].packetLength;
|
||||
this.secMPIs[2] = new openpgp_type_mpi();
|
||||
this.secMPIs[2].read(input, mypos, len-2- (mypos - position));
|
||||
mypos += this.secMPIs[2].packetLength;
|
||||
this.secMPIs[3] = new openpgp_type_mpi();
|
||||
this.secMPIs[3].read(input, mypos, len-2- (mypos - position));
|
||||
mypos += this.secMPIs[3].packetLength;
|
||||
} else if (this.publicKey.publicKeyAlgorithm == 16) {
|
||||
// Algorithm-Specific Fields for Elgamal secret keys:
|
||||
// - MPI of Elgamal secret exponent x.
|
||||
this.secMPIs = new Array();
|
||||
this.secMPIs[0] = new openpgp_type_mpi();
|
||||
this.secMPIs[0].read(input, mypos, len-2- (mypos - position));
|
||||
mypos += this.secMPIs[0].packetLength;
|
||||
} else if (this.publicKey.publicKeyAlgorithm == 17) {
|
||||
// Algorithm-Specific Fields for DSA secret keys:
|
||||
// - MPI of DSA secret exponent x.
|
||||
this.secMPIs = new Array();
|
||||
this.secMPIs[0] = new openpgp_type_mpi();
|
||||
this.secMPIs[0].read(input, mypos, len-2- (mypos - position));
|
||||
mypos += this.secMPIs[0].packetLength;
|
||||
}
|
||||
// checksum because s2k usage convention is 0
|
||||
this.checksum = new Array();
|
||||
this.checksum[0] = input[mypos++].charCodeAt();
|
||||
this.checksum[1] = input[mypos++].charCodeAt();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decrypts the private key MPIs which are needed to use the key.
|
||||
* openpgp_packet_keymaterial.hasUnencryptedSecretKeyData should be false otherwise
|
||||
* a call to this function is not needed
|
||||
*
|
||||
* @param str_passphrase the passphrase for this private key as string
|
||||
* @return true if the passphrase was correct; false if not
|
||||
*/
|
||||
function decryptSecretMPIs(str_passphrase) {
|
||||
if (this.hasUnencryptedSecretKeyData)
|
||||
return this.secMPIs;
|
||||
// creating a key out of the passphrase
|
||||
var key = this.s2k.produce_key(str_passphrase);
|
||||
var cleartextMPIs = "";
|
||||
switch (this.symmetricEncryptionAlgorithm) {
|
||||
case 1: // - IDEA [IDEA]
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+"symmetric encryption algorithim: IDEA is not implemented");
|
||||
return false;
|
||||
case 2: // - TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
|
||||
cleartextMPIs = normal_cfb_decrypt(function(block, key) {
|
||||
return des(key, block,1,null,0);
|
||||
}, this.IVLength, key, this.encryptedMPIData, this.IV);
|
||||
break;
|
||||
case 3: // - CAST5 (128 bit key, as per [RFC2144])
|
||||
cleartextMPIs = normal_cfb_decrypt(function(block, key) {
|
||||
var cast5 = new openpgp_symenc_cast5();
|
||||
cast5.setKey(key);
|
||||
return cast5.encrypt(util.str2bin(block));
|
||||
}, this.IVLength, util.str2bin(key.substring(0,16)), this.encryptedMPIData, this.IV);
|
||||
break;
|
||||
case 4: // - Blowfish (128 bit key, 16 rounds) [BLOWFISH]
|
||||
cleartextMPIs = normal_cfb_decrypt(function(block, key) {
|
||||
var blowfish = new Blowfish(key);
|
||||
return blowfish.encrypt(block);
|
||||
}, this.IVLength, key, this.encryptedMPIData, this.IV);
|
||||
break;
|
||||
case 7: // - AES with 128-bit key [AES]
|
||||
case 8: // - AES with 192-bit key
|
||||
case 9: // - AES with 256-bit key
|
||||
cleartextMPIs = normal_cfb_decrypt(AESencrypt,
|
||||
this.IVLength, keyExpansion(key), this.encryptedMPIData, this.IV);
|
||||
break;
|
||||
case 10: // - Twofish with 256-bit key [TWOFISH]
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+"Key material is encrypted with twofish: not implemented");
|
||||
return false;;
|
||||
case 5: // - Reserved
|
||||
case 6: // - Reserved
|
||||
default:
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+"unknown encryption algorithm for secret key :"+this.symmetricEncryptionAlgorithm);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cleartextMPIs == null) {
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+"cleartextMPIs was null");
|
||||
return false;
|
||||
}
|
||||
|
||||
var cleartextMPIslength = cleartextMPIs.length;
|
||||
if (this.s2kUsageConventions == 254 &&
|
||||
str_sha1(cleartextMPIs.substring(0,cleartextMPIs.length - 20)) ==
|
||||
cleartextMPIs.substring(cleartextMPIs.length - 20)) {
|
||||
cleartextMPIslength -= 20;
|
||||
} else if (this.s2kUsageConcentions != 254 && util.calc_checksum(cleartextMPIs.substring(0,cleartextMPIs.length - 2)) ==
|
||||
(cleartextMPIs.charCodeAt(cleartextMPIs.length -2) << 8 | cleartextMPIs.charCodeAt(cleartextMPIs.length -1))) {
|
||||
cleartextMPIslength -= 2;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.publicKey.publicKeyAlgorithm > 0 && this.publicKey.publicKeyAlgorithm < 4) {
|
||||
// Algorithm-Specific Fields for RSA secret keys:
|
||||
// - multiprecision integer (MPI) of RSA secret exponent d.
|
||||
// - MPI of RSA secret prime value p.
|
||||
// - MPI of RSA secret prime value q (p < q).
|
||||
// - MPI of u, the multiplicative inverse of p, mod q.
|
||||
var mypos = 0;
|
||||
this.secMPIs = new Array();
|
||||
this.secMPIs[0] = new openpgp_type_mpi();
|
||||
this.secMPIs[0].read(cleartextMPIs, 0, cleartextMPIslength);
|
||||
mypos += this.secMPIs[0].packetLength;
|
||||
this.secMPIs[1] = new openpgp_type_mpi();
|
||||
this.secMPIs[1].read(cleartextMPIs, mypos, cleartextMPIslength-mypos);
|
||||
mypos += this.secMPIs[1].packetLength;
|
||||
this.secMPIs[2] = new openpgp_type_mpi();
|
||||
this.secMPIs[2].read(cleartextMPIs, mypos, cleartextMPIslength-mypos);
|
||||
mypos += this.secMPIs[2].packetLength;
|
||||
this.secMPIs[3] = new openpgp_type_mpi();
|
||||
this.secMPIs[3].read(cleartextMPIs, mypos, cleartextMPIslength-mypos);
|
||||
mypos += this.secMPIs[3].packetLength;
|
||||
} else if (this.publicKey.publicKeyAlgorithm == 16) {
|
||||
// Algorithm-Specific Fields for Elgamal secret keys:
|
||||
// - MPI of Elgamal secret exponent x.
|
||||
this.secMPIs = new Array();
|
||||
this.secMPIs[0] = new openpgp_type_mpi();
|
||||
this.secMPIs[0].read(cleartextMPIs, 0, cleartextMPIs);
|
||||
} else if (this.publicKey.publicKeyAlgorithm == 17) {
|
||||
// Algorithm-Specific Fields for DSA secret keys:
|
||||
// - MPI of DSA secret exponent x.
|
||||
this.secMPIs = new Array();
|
||||
this.secMPIs[0] = new openpgp_type_mpi();
|
||||
this.secMPIs[0].read(cleartextMPIs, 0, cleartextMPIslength);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates Debug output
|
||||
* @return String which gives some information about the keymaterial
|
||||
*/
|
||||
function toString() {
|
||||
var result = "";
|
||||
switch (this.tagType) {
|
||||
case 6:
|
||||
result += '5.5.1.1. Public-Key Packet (Tag 6)\n'+
|
||||
' length: '+this.packetLength+'\n'+
|
||||
' version: '+this.version+'\n'+
|
||||
' creation time: '+this.creationTime+'\n'+
|
||||
' expiration time: '+this.expiration+'\n'+
|
||||
' publicKeyAlgorithm: '+this.publicKeyAlgorithm+'\n';
|
||||
break;
|
||||
case 14:
|
||||
result += '5.5.1.2. Public-Subkey Packet (Tag 14)\n'+
|
||||
' length: '+this.packetLength+'\n'+
|
||||
' version: '+this.version+'\n'+
|
||||
' creation time: '+this.creationTime+'\n'+
|
||||
' expiration time: '+this.expiration+'\n'+
|
||||
' publicKeyAlgorithm: '+this.publicKeyAlgorithm+'\n';
|
||||
break;
|
||||
case 5:
|
||||
result +='5.5.1.3. Secret-Key Packet (Tag 5)\n'+
|
||||
' length: '+this.packetLength+'\n'+
|
||||
' version: '+this.publicKey.version+'\n'+
|
||||
' creation time: '+this.publicKey.creationTime+'\n'+
|
||||
' expiration time: '+this.publicKey.expiration+'\n'+
|
||||
' publicKeyAlgorithm: '+this.publicKey.publicKeyAlgorithm+'\n';
|
||||
break;
|
||||
case 7:
|
||||
result += '5.5.1.4. Secret-Subkey Packet (Tag 7)\n'+
|
||||
' length: '+this.packetLength+'\n'+
|
||||
' version[1]: '+(this.version == 4)+'\n'+
|
||||
' creationtime[4]: '+this.creationTime+'\n'+
|
||||
' expiration[2]: '+this.expiration+'\n'+
|
||||
' publicKeyAlgorithm: '+this.publicKeyAlgorithm+'\n';
|
||||
break;
|
||||
default:
|
||||
result += 'unknown key material packet\n';
|
||||
}
|
||||
if (this.MPIs != null) {
|
||||
result += "Public Key MPIs:\n";
|
||||
for (var i = 0; i < this.MPIs.length; i++) {
|
||||
result += this.MPIs[i].toString();
|
||||
}
|
||||
}
|
||||
if (this.publicKey != null && this.publicKey.MPIs != null) {
|
||||
result += "Public Key MPIs:\n";
|
||||
for (var i = 0; i < this.publicKey.MPIs.length; i++) {
|
||||
result += this.publicKey.MPIs[i].toString();
|
||||
}
|
||||
}
|
||||
if (this.secMPIs != null) {
|
||||
result += "Secret Key MPIs:\n";
|
||||
for (var i = 0; i < this.secMPIs.length; i++) {
|
||||
result += this.secMPIs[i].toString();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.subKeySignature != null)
|
||||
result += "subKey Signature:\n"+this.subKeySignature.toString();
|
||||
|
||||
if (this.subKeyRevocationSignature != null )
|
||||
result += "subKey Revocation Signature:\n"+this.subKeyRevocationSignature.toString();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Continue parsing packets belonging to the key material such as signatures
|
||||
* @param parent_node [openpgp_*] the parent object
|
||||
* @param input [String] input string to read the packet(s) from
|
||||
* @param position [integer] start position for the parser
|
||||
* @param len [integer] length of the packet(s) or remaining length of input
|
||||
* @return [integer] length of nodes read
|
||||
*/
|
||||
function read_nodes(parent_node, input, position, len) {
|
||||
this.parentNode = parent_node;
|
||||
if (this.tagType == 14) { // public sub-key packet
|
||||
var pos = position;
|
||||
var result = null;
|
||||
while (input.length != pos) {
|
||||
var l = input.length - pos;
|
||||
result = openpgp_packet.read_packet(input, pos, l);
|
||||
if (result == null) {
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+'[user_keymat_pub]parsing ends here @:' + pos + " l:" + l);
|
||||
break;
|
||||
} else {
|
||||
|
||||
switch (result.tagType) {
|
||||
case 2: // Signature Packet certification signature
|
||||
if (result.signatureType == 24) { // subkey binding signature
|
||||
this.subKeySignature = result;
|
||||
pos += result.packetLength + result.headerLength;
|
||||
break;
|
||||
} else if (result.signatureType == 40) { // subkey revocation signature
|
||||
this.subKeyRevocationSignature = result;
|
||||
pos += result.packetLength + result.headerLength;
|
||||
break;
|
||||
} else {
|
||||
util.print_error("openpgp.packet.keymaterial.js\nunknown signature:"+result.toString());
|
||||
}
|
||||
|
||||
default:
|
||||
this.data = input;
|
||||
this.position = position - this.parentNode.packetLength;
|
||||
this.len = pos - position;
|
||||
return this.len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.data = input;
|
||||
this.position = position - this.parentNode.packetLength;
|
||||
this.len = pos - position;
|
||||
return this.len;
|
||||
} else if (this.tagType == 7) { // private sub-key packet
|
||||
var pos = position;
|
||||
while (input.length != pos) {
|
||||
var result = openpgp_packet.read_packet(input, pos, len - (pos - position));
|
||||
if (result == null) {
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+'[user_keymat_priv] parsing ends here @:' + pos);
|
||||
break;
|
||||
} else {
|
||||
switch (result.tagType) {
|
||||
case 2: // Signature Packet certification signature
|
||||
if (result.signatureType == 24) // subkey embedded signature
|
||||
this.subKeySignature = result;
|
||||
else if (result.signatureType == 40) // subkey revocation signature
|
||||
this.subKeyRevocationSignature[this.subKeyRevocationSignature] = result;
|
||||
pos += result.packetLength + result.headerLength;
|
||||
break;
|
||||
default:
|
||||
this.data = input;
|
||||
this.position = position - this.parentNode.packetLength;
|
||||
this.len = pos - position;
|
||||
return this.len;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.data = input;
|
||||
this.position = position - this.parentNode.packetLength;
|
||||
this.len = pos - position;
|
||||
return this.len;
|
||||
} else {
|
||||
util.print_error("openpgp.packet.keymaterial.js\n"+"unknown parent node for a key material packet "+parent_node.tagType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the validity for usage of this (sub)key
|
||||
* @return 0 = bad key, 1 = expired, 2 = revoked, 3 = valid
|
||||
*/
|
||||
function verifyKey() {
|
||||
if (this.tagType == 14) {
|
||||
if (this.subKeySignature == null)
|
||||
return 0;
|
||||
if (this.subKeySignature.version == 4 &&
|
||||
this.subKeySignature.keyNeverExpires != null &&
|
||||
!this.subKeySignature.keyNeverExpires &&
|
||||
new Date((this.subKeySignature.keyExpirationTime*1000)+ this.creationTime.getTime()) < new Date())
|
||||
return 1;
|
||||
var hashdata = String.fromCharCode(0x99)+this.parentNode.header.substring(1)+this.parentNode.data+
|
||||
String.fromCharCode(0x99)+this.header.substring(1)+this.packetdata;
|
||||
if (!this.subKeySignature.verify(hashdata,this.parentNode)) {
|
||||
return 0;
|
||||
}
|
||||
for (var i = 0; i < this.subKeyRevocationSignature.length; i++) {
|
||||
if (this.subKeyRevocationSignature[i])
|
||||
var hashdata = String.fromCharCode(0x99)+this.parentNode.header.substring(1)+this.parentNode.data+
|
||||
String.fromCharCode(0x99)+this.header.substring(1)+this.packetdata;
|
||||
if (this.subKeyRevocationSignature[i].verify(hashdata, this.parentNode))
|
||||
return 2;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* calculates the key id of they key
|
||||
* @return [String] a 8 byte key id
|
||||
*/
|
||||
function getKeyId() {
|
||||
if (this.version == 4) {
|
||||
var f = this.getFingerprint();
|
||||
return f.substring(12,20);
|
||||
} else if (this.version == 3 && this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4) {
|
||||
var key_id = this.MPIs[0].substring((this.MPIs[0].mpiByteLength-8));
|
||||
util.print_debug("openpgp.msg.publickey read_nodes:\n"+"V3 key ID: "+key_id);
|
||||
return key_id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* calculates the fingerprint of the key
|
||||
* @return [String] a string containing the fingerprint
|
||||
*/
|
||||
function getFingerprint() {
|
||||
if (this.version == 4) {
|
||||
var tohash= this.header+this.data;
|
||||
//if (this.tagType == 14) {
|
||||
tohash = String.fromCharCode(0x99)+this.header.substring(1)+this.packetdata;
|
||||
util.print_debug("openpgp.msg.publickey creating subkey fingerprint by hashing:"+util.hexstrdump(tohash)+"\npublickeyalgorithm: "+this.publicKeyAlgorithm);
|
||||
//}
|
||||
return str_sha1(tohash, tohash.length);
|
||||
} else if (this.version == 3 && this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4) {
|
||||
return MD5(this.MPIs[0].MPI);
|
||||
}
|
||||
}
|
||||
|
||||
this.read_tag5 = read_tag5;
|
||||
this.read_tag6 = read_tag6;
|
||||
this.read_tag7 = read_tag7;
|
||||
this.read_tag14 = read_tag14;
|
||||
this.toString = toString;
|
||||
this.read_pub_key = read_pub_key;
|
||||
this.read_priv_key = read_priv_key;
|
||||
this.decryptSecretMPIs = decryptSecretMPIs;
|
||||
this.read_nodes = read_nodes;
|
||||
this.verifyKey = verifyKey;
|
||||
this.getKeyId = getKeyId;
|
||||
this.getFingerprint = getFingerprint;
|
||||
}
|
||||
99
src/packet/openpgp.packet.literaldata.js
Executable file
99
src/packet/openpgp.packet.literaldata.js
Executable file
@@ -0,0 +1,99 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* Implementation of the Literal Data Packet (Tag 11)
|
||||
*
|
||||
* RFC4880 5.9: A Literal Data packet contains the body of a message; data that
|
||||
* is not to be further interpreted.
|
||||
*/
|
||||
function openpgp_packet_literaldata() {
|
||||
this.tagType = 11;
|
||||
|
||||
/**
|
||||
* parsing function for a literal data packet (tag 11).
|
||||
*
|
||||
* @param input
|
||||
* [string] payload of a tag 11 packet
|
||||
* @param position
|
||||
* [integer] position to start reading from the input string
|
||||
* @param len
|
||||
* [integer] length of the packet or the remaining length of
|
||||
* input at position
|
||||
* @return [openpgp_packet_encrypteddata] object representation
|
||||
*/
|
||||
function read_packet(input, position, len) {
|
||||
this.packetLength = len;
|
||||
// - A one-octet field that describes how the data is formatted.
|
||||
|
||||
this.format = input[position];
|
||||
this.filename = input.substr(position + 2, input
|
||||
.charCodeAt(position + 1));
|
||||
this.date = new Date(parseInt(input.substr(position + 2
|
||||
+ input.charCodeAt(position + 1), 4)) * 1000);
|
||||
this.data = input.substring(position + 6
|
||||
+ input.charCodeAt(position + 1));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string representation of the packet
|
||||
*
|
||||
* @param data
|
||||
* [String] the data to be inserted as body
|
||||
* @return [String] string-representation of the packet
|
||||
*/
|
||||
function write_packet(data) {
|
||||
data = data.replace(/\r\n/g, "\n").replace(/\n/g, "\r\n");
|
||||
this.filename = "msg.txt";
|
||||
this.date = new Date();
|
||||
this.format = 't';
|
||||
var result = openpgp_packet.write_packet_header(11, data.length + 6
|
||||
+ this.filename.length);
|
||||
result += this.format;
|
||||
result += String.fromCharCode(this.filename.length);
|
||||
result += this.filename;
|
||||
result += String
|
||||
.fromCharCode((Math.round(this.date.getTime() / 1000) >> 24) & 0xFF);
|
||||
result += String
|
||||
.fromCharCode((Math.round(this.date.getTime() / 1000) >> 16) & 0xFF);
|
||||
result += String
|
||||
.fromCharCode((Math.round(this.date.getTime() / 1000) >> 8) & 0xFF);
|
||||
result += String
|
||||
.fromCharCode(Math.round(this.date.getTime() / 1000) & 0xFF);
|
||||
result += data;
|
||||
this.data = data;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* generates debug output (pretty print)
|
||||
*
|
||||
* @return String which gives some information about the keymaterial
|
||||
*/
|
||||
function toString() {
|
||||
return '5.9. Literal Data Packet (Tag 11)\n' + ' length: '
|
||||
+ this.packetLength + '\n' + ' format: ' + this.format
|
||||
+ '\n' + ' filename:' + this.filename + '\n'
|
||||
+ ' date: ' + this.date + '\n' + ' data: |'
|
||||
+ this.data + '|\n' + ' rdata: |' + this.real_data + '|\n';
|
||||
}
|
||||
|
||||
this.read_packet = read_packet;
|
||||
this.toString = toString;
|
||||
this.write_packet = write_packet;
|
||||
}
|
||||
64
src/packet/openpgp.packet.marker.js
Executable file
64
src/packet/openpgp.packet.marker.js
Executable file
@@ -0,0 +1,64 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* Implementation of the strange "Marker packet" (Tag 10)
|
||||
*
|
||||
* RFC4880 5.8: An experimental version of PGP used this packet as the Literal
|
||||
* packet, but no released version of PGP generated Literal packets with this
|
||||
* tag. With PGP 5.x, this packet has been reassigned and is reserved for use as
|
||||
* the Marker packet.
|
||||
*
|
||||
* Such a packet MUST be ignored when received.
|
||||
*/
|
||||
function openpgp_packet_marker() {
|
||||
this.tagType = 10;
|
||||
/**
|
||||
* parsing function for a literal data packet (tag 10).
|
||||
*
|
||||
* @param input
|
||||
* [string] payload of a tag 10 packet
|
||||
* @param position
|
||||
* [integer] position to start reading from the input string
|
||||
* @param len
|
||||
* [integer] length of the packet or the remaining length of
|
||||
* input at position
|
||||
* @return [openpgp_packet_encrypteddata] object representation
|
||||
*/
|
||||
function read_packet(input, position, len) {
|
||||
this.packetLength = 3;
|
||||
if (input[position].charCodeAt() == 0x50 && // P
|
||||
input[position + 1].charCodeAt() == 0x47 && // G
|
||||
input[position + 2].charCodeAt() == 0x50) // P
|
||||
return this;
|
||||
// marker packet does not contain "PGP"
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates Debug output
|
||||
*
|
||||
* @return String which gives some information about the keymaterial
|
||||
*/
|
||||
function toString() {
|
||||
return "5.8. Marker Packet (Obsolete Literal Packet) (Tag 10)\n"
|
||||
+ " packet reads: \"PGP\"\n";
|
||||
}
|
||||
|
||||
this.read_packet = read_packet;
|
||||
this.toString = toString;
|
||||
}
|
||||
79
src/packet/openpgp.packet.modificationdetectioncode.js
Executable file
79
src/packet/openpgp.packet.modificationdetectioncode.js
Executable file
@@ -0,0 +1,79 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* Implementation of the Modification Detection Code Packet (Tag 19)
|
||||
*
|
||||
* RFC4880 5.14: The Modification Detection Code packet contains a SHA-1 hash of
|
||||
* plaintext data, which is used to detect message modification. It is only used
|
||||
* with a Symmetrically Encrypted Integrity Protected Data packet. The
|
||||
* Modification Detection Code packet MUST be the last packet in the plaintext
|
||||
* data that is encrypted in the Symmetrically Encrypted Integrity Protected
|
||||
* Data packet, and MUST appear in no other place.
|
||||
*/
|
||||
|
||||
function openpgp_packet_modificationdetectioncode() {
|
||||
this.tagType = 19;
|
||||
this.hash = null;
|
||||
/**
|
||||
* parsing function for a modification detection code packet (tag 19).
|
||||
*
|
||||
* @param input
|
||||
* [String] payload of a tag 19 packet
|
||||
* @param position
|
||||
* [Integer] position to start reading from the input string
|
||||
* @param len
|
||||
* [Integer] length of the packet or the remaining length of
|
||||
* input at position
|
||||
* @return [openpgp_packet_encrypteddata] object representation
|
||||
*/
|
||||
function read_packet(input, position, len) {
|
||||
this.packetLength = len;
|
||||
|
||||
if (len != 20) {
|
||||
util
|
||||
.print_error("openpgp.packet.modificationdetectioncode.js\n"
|
||||
+ 'invalid length for a modification detection code packet!'
|
||||
+ len);
|
||||
return null;
|
||||
}
|
||||
// - A 20-octet SHA-1 hash of the preceding plaintext data of the
|
||||
// Symmetrically Encrypted Integrity Protected Data packet,
|
||||
// including prefix data, the tag octet, and length octet of the
|
||||
// Modification Detection Code packet.
|
||||
this.hash = input.substring(position, position + 20);
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* this packet is created within the encryptedintegrityprotected packet
|
||||
* function write_packet(data) { }
|
||||
*/
|
||||
|
||||
/**
|
||||
* generates debug output (pretty print)
|
||||
*
|
||||
* @return String which gives some information about the modification
|
||||
* detection code
|
||||
*/
|
||||
function toString() {
|
||||
return '5.14 Modification detection code packet\n' + ' bytes ('
|
||||
+ this.hash.length + '): [' + util.hexstrdump(this.hash) + ']';
|
||||
}
|
||||
this.read_packet = read_packet;
|
||||
this.toString = toString;
|
||||
};
|
||||
118
src/packet/openpgp.packet.onepasssignature.js
Executable file
118
src/packet/openpgp.packet.onepasssignature.js
Executable file
@@ -0,0 +1,118 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* Implementation of the One-Pass Signature Packets (Tag 4)
|
||||
*
|
||||
* RFC4880 5.4:
|
||||
* The One-Pass Signature packet precedes the signed data and contains
|
||||
* enough information to allow the receiver to begin calculating any
|
||||
* hashes needed to verify the signature. It allows the Signature
|
||||
* packet to be placed at the end of the message, so that the signer
|
||||
* can compute the entire signed message in one pass.
|
||||
*/
|
||||
function openpgp_packet_onepasssignature() {
|
||||
this.tagType = 4;
|
||||
this.version = null; // A one-octet version number. The current version is 3.
|
||||
this.type == null; // A one-octet signature type. Signature types are described in RFC4880 Section 5.2.1.
|
||||
this.hashAlgorithm = null; // A one-octet number describing the hash algorithm used. (See RFC4880 9.4)
|
||||
this.publicKeyAlgorithm = null; // A one-octet number describing the public-key algorithm used. (See RFC4880 9.1)
|
||||
this.signingKeyId = null; // An eight-octet number holding the Key ID of the signing key.
|
||||
this.flags = null; // A one-octet number holding a flag showing whether the signature is nested. A zero value indicates that the next packet is another One-Pass Signature packet that describes another signature to be applied to the same message data.
|
||||
|
||||
/**
|
||||
* parsing function for a one-pass signature packet (tag 4).
|
||||
* @param input [string] payload of a tag 4 packet
|
||||
* @param position [integer] position to start reading from the input string
|
||||
* @param len [integer] length of the packet or the remaining length of input at position
|
||||
* @return [openpgp_packet_encrypteddata] object representation
|
||||
*/
|
||||
function read_packet(input, position, len) {
|
||||
this.packetLength = len;
|
||||
var mypos = position;
|
||||
// A one-octet version number. The current version is 3.
|
||||
this.version = input.charCodeAt(mypos++);
|
||||
|
||||
// A one-octet signature type. Signature types are described in
|
||||
// Section 5.2.1.
|
||||
this.type = input.charCodeAt(mypos++);
|
||||
|
||||
// A one-octet number describing the hash algorithm used.
|
||||
this.hashAlgorithm = input.charCodeAt(mypos++);
|
||||
|
||||
// A one-octet number describing the public-key algorithm used.
|
||||
this.publicKeyAlgorithm = input.charCodeAt(mypos++);
|
||||
// An eight-octet number holding the Key ID of the signing key.
|
||||
this.signingKeyId = new openpgp_type_keyid();
|
||||
this.signingKeyId.read_packet(input,mypos);
|
||||
mypos += 8;
|
||||
|
||||
// A one-octet number holding a flag showing whether the signature
|
||||
// is nested. A zero value indicates that the next packet is
|
||||
// another One-Pass Signature packet that describes another
|
||||
// signature to be applied to the same message data.
|
||||
this.flags = input.charCodeAt(mypos++);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a string representation of a one-pass signature packet
|
||||
* @param type [integer] Signature types as described in RFC4880 Section 5.2.1.
|
||||
* @param hashalgorithm [integer] the hash algorithm used within the signature
|
||||
* @param privatekey [openpgp_msg_privatekey] the private key used to generate the signature
|
||||
* @param length [integer] length of data to be signed
|
||||
* @param nested [boolean] boolean showing whether the signature is nested.
|
||||
* "true" indicates that the next packet is another One-Pass Signature packet
|
||||
* that describes another signature to be applied to the same message data.
|
||||
* @return [String] a string representation of a one-pass signature packet
|
||||
*/
|
||||
function write_packet(type, hashalgorithm, privatekey,length, nested) {
|
||||
var result ="";
|
||||
|
||||
result += openpgp_packet.write_packet_header(4,13);
|
||||
result += String.fromCharCode(3);
|
||||
result += String.fromCharCode(type);
|
||||
result += String.fromCharCode(hashalgorithm);
|
||||
result += String.fromCharCode(privatekey.privateKeyPacket.publicKey.publicKeyAlgorithm);
|
||||
result += privatekey.getKeyId();
|
||||
if (nested)
|
||||
result += String.fromCharCode(0);
|
||||
else
|
||||
result += String.fromCharCode(1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* generates debug output (pretty print)
|
||||
* @return String which gives some information about the one-pass signature packet
|
||||
*/
|
||||
function toString() {
|
||||
return '5.4. One-Pass Signature Packets (Tag 4)\n'+
|
||||
' length: '+this.packetLength+'\n'+
|
||||
' type: '+this.type+'\n'+
|
||||
' keyID: '+this.signingKeyId.toString()+'\n'+
|
||||
' hashA: '+this.hashAlgorithm+'\n'+
|
||||
' pubKeyA:'+this.publicKeyAlgorithm+'\n'+
|
||||
' flags: '+this.flags+'\n'+
|
||||
' version:'+this.version+'\n';
|
||||
}
|
||||
|
||||
this.read_packet = read_packet;
|
||||
this.toString = toString;
|
||||
this.write_packet = write_packet;
|
||||
};
|
||||
755
src/packet/openpgp.packet.signature.js
Executable file
755
src/packet/openpgp.packet.signature.js
Executable file
@@ -0,0 +1,755 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* Implementation of the Signature Packet (Tag 2)
|
||||
*
|
||||
* RFC4480 5.2:
|
||||
* A Signature packet describes a binding between some public key and
|
||||
* some data. The most common signatures are a signature of a file or a
|
||||
* block of text, and a signature that is a certification of a User ID.
|
||||
*/
|
||||
function openpgp_packet_signature() {
|
||||
this.tagType = 2;
|
||||
this.signatureType = null;
|
||||
this.creationTime = null;
|
||||
this.keyId = null;
|
||||
this.signatureData = null;
|
||||
this.signatureExpirationTime = null;
|
||||
this.signatureNeverExpires = null;
|
||||
this.signedHashValue = null;
|
||||
this.MPIs = null;
|
||||
this.publicKeyAlgorithm = null;
|
||||
this.hashAlgorithm = null;
|
||||
this.exportable = null;
|
||||
this.trustLevel = null;
|
||||
this.trustAmount = null;
|
||||
this.regular_expression = null;
|
||||
this.revocable = null;
|
||||
this.keyExpirationTime = null;
|
||||
this.keyNeverExpires = null;
|
||||
this.preferredSymmetricAlgorithms = null;
|
||||
this.revocationKeyClass = null;
|
||||
this.revocationKeyAlgorithm = null;
|
||||
this.revocationKeyFingerprint = null;
|
||||
this.issuerKeyId = null;
|
||||
this.notationFlags = null;
|
||||
this.notationName = null;
|
||||
this.notationValue = null;
|
||||
this.preferredHashAlgorithms = null;
|
||||
this.preferredCompressionAlgorithms = null;
|
||||
this.keyServerPreferences = null;
|
||||
this.preferredKeyServer = null;
|
||||
this.isPrimaryUserID = null;
|
||||
this.policyURI = null;
|
||||
this.keyFlags = null;
|
||||
this.signersUserId = null;
|
||||
this.reasonForRevocationFlag = null;
|
||||
this.reasonForRevocationString = null;
|
||||
this.signatureTargetPublicKeyAlgorithm = null;
|
||||
this.signatureTargetHashAlgorithm = null;
|
||||
this.signatureTargetHash = null;
|
||||
this.embeddedSignature = null;
|
||||
|
||||
|
||||
/**
|
||||
* parsing function for a signature packet (tag 2).
|
||||
* @param input [string] payload of a tag 2 packet
|
||||
* @param position [integer] position to start reading from the input string
|
||||
* @param len [integer] length of the packet or the remaining length of input at position
|
||||
* @return [openpgp_packet_encrypteddata] object representation
|
||||
*/
|
||||
function read_packet(input, position, len) {
|
||||
this.data = input.substring (position, position+len);
|
||||
if (len < 0) {
|
||||
util.print_debug("openpgp.packet.signature.js\n"+"openpgp_packet_signature read_packet length < 0 @:"+position);
|
||||
return null;
|
||||
}
|
||||
var mypos = position;
|
||||
this.packetLength = len;
|
||||
// alert('starting parsing signature: '+position+' '+this.packetLength);
|
||||
this.version = input[mypos++].charCodeAt();
|
||||
// switch on version (3 and 4)
|
||||
switch (this.version) {
|
||||
case 3:
|
||||
// One-octet length of following hashed material. MUST be 5.
|
||||
if (input[mypos++].charCodeAt() != 5)
|
||||
util.print_debug("openpgp.packet.signature.js\n"+'invalid One-octet length of following hashed material. MUST be 5. @:'+(mypos-1));
|
||||
var sigpos = mypos;
|
||||
// One-octet signature type.
|
||||
this.signatureType = input[mypos++].charCodeAt();
|
||||
|
||||
// Four-octet creation time.
|
||||
this.creationTime = new Date(((input[mypos++].charCodeAt()) << 24 |
|
||||
(input[mypos++].charCodeAt() << 16) | (input[mypos++].charCodeAt() << 8) |
|
||||
input[mypos++].charCodeAt())* 1000);
|
||||
|
||||
// storing data appended to data which gets verified
|
||||
this.signatureData = input.substring(position, mypos);
|
||||
|
||||
// Eight-octet Key ID of signer.
|
||||
this.keyId = input.substring(mypos, mypos +8);
|
||||
mypos += 8;
|
||||
|
||||
// One-octet public-key algorithm.
|
||||
this.publicKeyAlgorithm = input[mypos++].charCodeAt();
|
||||
|
||||
// One-octet hash algorithm.
|
||||
this.hashAlgorithm = input[mypos++].charCodeAt();
|
||||
|
||||
// Two-octet field holding left 16 bits of signed hash value.
|
||||
this.signedHashValue = (input[mypos++].charCodeAt() << 8) | input[mypos++].charCodeAt();
|
||||
var mpicount = 0;
|
||||
// Algorithm-Specific Fields for RSA signatures:
|
||||
// - multiprecision integer (MPI) of RSA signature value m**d mod n.
|
||||
if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4)
|
||||
mpicount = 1;
|
||||
// Algorithm-Specific Fields for DSA signatures:
|
||||
// - MPI of DSA value r.
|
||||
// - MPI of DSA value s.
|
||||
else if (this.publicKeyAlgorithm == 17)
|
||||
mpicount = 2;
|
||||
|
||||
this.MPIs = new Array();
|
||||
for (var i = 0; i < mpicount; i++) {
|
||||
this.MPIs[i] = new openpgp_type_mpi();
|
||||
if (this.MPIs[i].read(input, mypos, (mypos-position)) != null &&
|
||||
!this.packetLength < (mypos-position)) {
|
||||
mypos += this.MPIs[i].packetLength;
|
||||
} else {
|
||||
util.print_error('signature contains invalid MPI @:'+mypos);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
this.signatureType = input[mypos++].charCodeAt();
|
||||
this.publicKeyAlgorithm = input[mypos++].charCodeAt();
|
||||
this.hashAlgorithm = input[mypos++].charCodeAt();
|
||||
|
||||
// Two-octet scalar octet count for following hashed subpacket
|
||||
// data.
|
||||
var hashed_subpacket_count = (input[mypos++].charCodeAt() << 8) + input[mypos++].charCodeAt();
|
||||
|
||||
// Hashed subpacket data set (zero or more subpackets)
|
||||
var subpacket_length = 0;
|
||||
while (hashed_subpacket_count != subpacket_length) {
|
||||
if (hashed_subpacket_count < subpacket_length) {
|
||||
util.print_debug("openpgp.packet.signature.js\n"+"hashed missed something: "+mypos+" c:"+hashed_subpacket_count+" l:"+subpacket_length);
|
||||
}
|
||||
|
||||
subpacket_length += this._raw_read_signature_sub_packet(input,
|
||||
mypos + subpacket_length, hashed_subpacket_count
|
||||
- subpacket_length);
|
||||
}
|
||||
|
||||
mypos += hashed_subpacket_count;
|
||||
this.signatureData = input.substring(position, mypos);
|
||||
|
||||
// alert("signatureData: "+util.hexstrdump(this.signatureData));
|
||||
|
||||
// Two-octet scalar octet count for the following unhashed subpacket
|
||||
var subpacket_count = (input[mypos++].charCodeAt() << 8) + input[mypos++].charCodeAt();
|
||||
|
||||
// Unhashed subpacket data set (zero or more subpackets).
|
||||
subpacket_length = 0;
|
||||
while (subpacket_count != subpacket_length) {
|
||||
if (subpacket_count < subpacket_length) {
|
||||
util.print_debug("openpgp.packet.signature.js\n"+"missed something: "+subpacket_length+" c:"+subpacket_count+" "+" l:"+subpacket_length);
|
||||
}
|
||||
subpacket_length += this._raw_read_signature_sub_packet(input,
|
||||
mypos + subpacket_length, subpacket_count
|
||||
- subpacket_length);
|
||||
|
||||
}
|
||||
mypos += subpacket_count;
|
||||
// Two-octet field holding the left 16 bits of the signed hash
|
||||
// value.
|
||||
this.signedHashValue = (input[mypos++].charCodeAt() << 8) | input[mypos++].charCodeAt();
|
||||
// One or more multiprecision integers comprising the signature.
|
||||
// This portion is algorithm specific, as described above.
|
||||
var mpicount = 0;
|
||||
if (this.publicKeyAlgorithm > 0 && this.publicKeyAlgorithm < 4)
|
||||
mpicount = 1;
|
||||
else if (this.publicKeyAlgorithm == 17)
|
||||
mpicount = 2;
|
||||
|
||||
this.MPIs = new Array();
|
||||
for (var i = 0; i < mpicount; i++) {
|
||||
this.MPIs[i] = new openpgp_type_mpi();
|
||||
if (this.MPIs[i].read(input, mypos, (mypos-position)) != null &&
|
||||
!this.packetLength < (mypos-position)) {
|
||||
mypos += this.MPIs[i].packetLength;
|
||||
} else {
|
||||
util.print_error('signature contains invalid MPI @:'+mypos);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
util.print_error("openpgp.packet.signature.js\n"+'unknown signature packet version'+this.version);
|
||||
break;
|
||||
}
|
||||
// util.print_message("openpgp.packet.signature.js\n"+"end signature: l: "+this.packetLength+"m: "+mypos+" m-p: "+(mypos-position));
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* creates a string representation of a message signature packet (tag 2).
|
||||
* This can be only used on text data
|
||||
* @param signature_type [integer] should be 1 (one)
|
||||
* @param data [String] data to be signed
|
||||
* @param privatekey [openpgp_msg_privatekey] private key used to sign the message. (secMPIs MUST be unlocked)
|
||||
* @return string representation of a signature packet
|
||||
*/
|
||||
function write_message_signature(signature_type, data, privatekey) {
|
||||
var publickey = privatekey.privateKeyPacket.publicKey;
|
||||
var hash_algo = privatekey.getPreferredSignatureHashAlgorithm();
|
||||
var result = String.fromCharCode(4);
|
||||
result += String.fromCharCode(signature_type);
|
||||
result += String.fromCharCode(publickey.publicKeyAlgorithm);
|
||||
result += String.fromCharCode(hash_algo);
|
||||
var d = Math.round(new Date().getTime() / 1000);
|
||||
var datesubpacket = write_sub_signature_packet(2,""+
|
||||
String.fromCharCode((d >> 24) & 0xFF) +
|
||||
String.fromCharCode((d >> 16) & 0xFF) +
|
||||
String.fromCharCode((d >> 8) & 0xFF) +
|
||||
String.fromCharCode(d & 0xFF));
|
||||
var issuersubpacket = write_sub_signature_packet(16, privatekey.getKeyId());
|
||||
result += String.fromCharCode(((datesubpacket.length + issuersubpacket.length) >> 8) & 0xFF);
|
||||
result += String.fromCharCode ((datesubpacket.length + issuersubpacket.length) & 0xFF);
|
||||
result += datesubpacket;
|
||||
result += issuersubpacket;
|
||||
var trailer = '';
|
||||
|
||||
trailer += String.fromCharCode(4);
|
||||
trailer += String.fromCharCode(0xFF);
|
||||
trailer += String.fromCharCode((result.length) >> 24);
|
||||
trailer += String.fromCharCode(((result.length) >> 16) & 0xFF);
|
||||
trailer += String.fromCharCode(((result.length) >> 8) & 0xFF);
|
||||
trailer += String.fromCharCode((result.length) & 0xFF);
|
||||
var result2 = String.fromCharCode(0);
|
||||
result2 += String.fromCharCode(0);
|
||||
var hash = openpgp_crypto_hashData(hash_algo, data+result+trailer);
|
||||
util.print_debug("DSA Signature is calculated with:|"+data+result+trailer+"|\n"+util.hexstrdump(data+result+trailer)+"\n hash:"+util.hexstrdump(hash));
|
||||
result2 += hash.charAt(0);
|
||||
result2 += hash.charAt(1);
|
||||
result2 += openpgp_crypto_signData(hash_algo,privatekey.privateKeyPacket.publicKey.publicKeyAlgorithm,
|
||||
publickey.MPIs,
|
||||
privatekey.privateKeyPacket.secMPIs,
|
||||
data+result+trailer);
|
||||
return {openpgp: (openpgp_packet.write_packet_header(2, (result+result2).length)+result + result2),
|
||||
hash: util.get_hashAlgorithmString(hash_algo)};
|
||||
}
|
||||
/**
|
||||
* creates a string representation of a sub signature packet (See RFC 4880 5.2.3.1)
|
||||
* @param type [integer] subpacket signature type. Signature types as described in RFC4880 Section 5.2.3.2
|
||||
* @param data [String] data to be included
|
||||
* @return [String] a string-representation of a sub signature packet (See RFC 4880 5.2.3.1)
|
||||
*/
|
||||
function write_sub_signature_packet(type, data) {
|
||||
var result = "";
|
||||
result += openpgp_packet.encode_length(data.length+1);
|
||||
result += String.fromCharCode(type);
|
||||
result += data;
|
||||
return result;
|
||||
}
|
||||
|
||||
// V4 signature sub packets
|
||||
|
||||
this._raw_read_signature_sub_packet = function(input, position, len) {
|
||||
if (len < 0)
|
||||
util.print_debug("openpgp.packet.signature.js\n"+"_raw_read_signature_sub_packet length < 0 @:"+position);
|
||||
var mypos = position;
|
||||
var subplen = 0;
|
||||
// alert('starting signature subpackage read at position:'+position+' length:'+len);
|
||||
if (input[mypos].charCodeAt() < 192) {
|
||||
subplen = input[mypos++].charCodeAt();
|
||||
} else if (input[mypos].charCodeAt() >= 192 && input[mypos].charCodeAt() < 224) {
|
||||
subplen = ((input[mypos++].charCodeAt() - 192) << 8) + (input[mypos++].charCodeAt()) + 192;
|
||||
} else if (input[mypos].charCodeAt() > 223 && input[mypos].charCodeAt() < 255) {
|
||||
subplen = 1 << (input[mypos++].charCodeAt() & 0x1F);
|
||||
} else if (input[mypos].charCodeAt() < 255) {
|
||||
mypos++;
|
||||
subplen = (input[mypos++].charCodeAt() << 24) | (input[mypos++].charCodeAt() << 16)
|
||||
| (input[mypos++].charCodeAt() << 8) | input[mypos++].charCodeAt();
|
||||
}
|
||||
|
||||
var type = input[mypos++].charCodeAt() & 0x7F;
|
||||
// alert('signature subpacket type '+type+" with length: "+subplen);
|
||||
// subpacket type
|
||||
switch (type) {
|
||||
case 2: // Signature Creation Time
|
||||
this.creationTime = new Date(((input[mypos++].charCodeAt() << 24) | (input[mypos++].charCodeAt() << 16)
|
||||
| (input[mypos++].charCodeAt() << 8) | input[mypos++].charCodeAt())*1000);
|
||||
break;
|
||||
case 3: // Signature Expiration Time
|
||||
this.signatureExpirationTime = (input[mypos++].charCodeAt() << 24)
|
||||
| (input[mypos++].charCodeAt() << 16) | (input[mypos++].charCodeAt() << 8)
|
||||
| input[mypos++].charCodeAt();
|
||||
this.signatureNeverExpires = (this.signature_expiration_time == 0);
|
||||
|
||||
break;
|
||||
case 4: // Exportable Certification
|
||||
this.exportable = input[mypos++].charCodeAt() == 1;
|
||||
break;
|
||||
case 5: // Trust Signature
|
||||
this.trustLevel = input[mypos++].charCodeAt();
|
||||
this.trustAmount = input[mypos++].charCodeAt();
|
||||
break;
|
||||
case 6: // Regular Expression
|
||||
this.regular_expression = new String();
|
||||
for (var i = 0; i < subplen - 1; i++)
|
||||
this.regular_expression += (input[mypos++]);
|
||||
break;
|
||||
case 7: // Revocable
|
||||
this.revocable = input[mypos++].charCodeAt() == 1;
|
||||
break;
|
||||
case 9: // Key Expiration Time
|
||||
this.keyExpirationTime = (input[mypos++].charCodeAt() << 24)
|
||||
| (input[mypos++].charCodeAt() << 16) | (input[mypos++].charCodeAt() << 8)
|
||||
| input[mypos++].charCodeAt();
|
||||
this.keyNeverExpires = (this.keyExpirationTime == 0);
|
||||
break;
|
||||
case 11: // Preferred Symmetric Algorithms
|
||||
this.preferredSymmetricAlgorithms = new Array();
|
||||
for (var i = 0; i < subplen-1; i++) {
|
||||
this.preferredSymmetricAlgorithms = input[mypos++].charCodeAt();
|
||||
}
|
||||
break;
|
||||
case 12: // Revocation Key
|
||||
// (1 octet of class, 1 octet of public-key algorithm ID, 20
|
||||
// octets of
|
||||
// fingerprint)
|
||||
this.revocationKeyClass = input[mypos++].charCodeAt();
|
||||
this.revocationKeyAlgorithm = input[mypos++].charCodeAt();
|
||||
this.revocationKeyFingerprint = new Array();
|
||||
for ( var i = 0; i < 20; i++) {
|
||||
this.revocationKeyFingerprint = input[mypos++].charCodeAt();
|
||||
}
|
||||
break;
|
||||
case 16: // Issuer
|
||||
this.issuerKeyId = input.substring(mypos,mypos+8);
|
||||
mypos += 8;
|
||||
break;
|
||||
case 20: // Notation Data
|
||||
this.notationFlags = (input[mypos++].charCodeAt() << 24) |
|
||||
(input[mypos++].charCodeAt() << 16) |
|
||||
(input[mypos++].charCodeAt() << 8) |
|
||||
(input[mypos++].charCodeAt());
|
||||
var nameLength = (input[mypos++].charCodeAt() << 8) | (input[mypos++].charCodeAt());
|
||||
var valueLength = (input[mypos++].charCodeAt() << 8) | (input[mypos++].charCodeAt());
|
||||
this.notationName = "";
|
||||
for (var i = 0; i < nameLength; i++) {
|
||||
this.notationName += input[mypos++];
|
||||
}
|
||||
this.notationValue = "";
|
||||
for (var i = 0; i < valueLength; i++) {
|
||||
this.notationValue += input[mypos++];
|
||||
}
|
||||
break;
|
||||
case 21: // Preferred Hash Algorithms
|
||||
this.preferredHashAlgorithms = new Array();
|
||||
for (var i = 0; i < subplen-1; i++) {
|
||||
this.preferredHashAlgorithms = input[mypos++].charCodeAt();
|
||||
}
|
||||
break;
|
||||
case 22: // Preferred Compression Algorithms
|
||||
this.preferredCompressionAlgorithms = new Array();
|
||||
for ( var i = 0; i < subplen-1; i++) {
|
||||
this.preferredCompressionAlgorithms = input[mypos++].charCodeAt();
|
||||
}
|
||||
break;
|
||||
case 23: // Key Server Preferences
|
||||
this.keyServerPreferences = new Array();
|
||||
for ( var i = 0; i < subplen-1; i++) {
|
||||
this.keyServerPreferences = input[mypos++].charCodeAt();
|
||||
}
|
||||
break;
|
||||
case 24: // Preferred Key Server
|
||||
this.preferredKeyServer = new String();
|
||||
for ( var i = 0; i < subplen-1; i++) {
|
||||
this.preferredKeyServer += input[mypos++];
|
||||
}
|
||||
break;
|
||||
case 25: // Primary User ID
|
||||
this.isPrimaryUserID = input[mypos++] != 0;
|
||||
break;
|
||||
case 26: // Policy URI
|
||||
this.policyURI = new String();
|
||||
for ( var i = 0; i < subplen-1; i++) {
|
||||
this.policyURI += input[mypos++];
|
||||
}
|
||||
break;
|
||||
case 27: // Key Flags
|
||||
this.keyFlags = new Array();
|
||||
for ( var i = 0; i < subplen-1; i++) {
|
||||
this.keyFlags = input[mypos++].charCodeAt();
|
||||
}
|
||||
break;
|
||||
case 28: // Signer's User ID
|
||||
this.signersUserId = new String();
|
||||
for ( var i = 0; i < subplen-1; i++) {
|
||||
this.signersUserId += input[mypos++];
|
||||
}
|
||||
break;
|
||||
case 29: // Reason for Revocation
|
||||
this.reasonForRevocationFlag = input[mypos++].charCodeAt();
|
||||
this.reasonForRevocationString = new String();
|
||||
for ( var i = 0; i < subplen -2; i++) {
|
||||
this.reasonForRevocationString += input[mypos++];
|
||||
}
|
||||
break;
|
||||
case 30: // Features
|
||||
// TODO: to be implemented
|
||||
return subplen+1;
|
||||
case 31: // Signature Target
|
||||
// (1 octet public-key algorithm, 1 octet hash algorithm, N octets hash)
|
||||
this.signatureTargetPublicKeyAlgorithm = input[mypos++].charCodeAt();
|
||||
this.signatureTargetHashAlgorithm = input[mypos++].charCodeAt();
|
||||
var signatureTargetHashAlgorithmLength = 0;
|
||||
switch(this.signatureTargetHashAlgorithm) {
|
||||
case 1: // - MD5 [HAC] "MD5"
|
||||
case 2: // - SHA-1 [FIPS180] "SHA1"
|
||||
signatureTargetHashAlgorithmLength = 20;
|
||||
break;
|
||||
case 3: // - RIPE-MD/160 [HAC] "RIPEMD160"
|
||||
case 8: // - SHA256 [FIPS180] "SHA256"
|
||||
case 9: // - SHA384 [FIPS180] "SHA384"
|
||||
case 10: // - SHA512 [FIPS180] "SHA512"
|
||||
case 11: // - SHA224 [FIPS180] "SHA224"
|
||||
break;
|
||||
// 100 to 110 - Private/Experimental algorithm
|
||||
default:
|
||||
util.print_error("openpgp.packet.signature.js\n"+"unknown signature target hash algorithm:"+this.signatureTargetHashAlgorithm);
|
||||
return null;
|
||||
}
|
||||
this.signatureTargetHash = new Array();
|
||||
for (var i = 0; i < signatureTargetHashAlgorithmLength; i++) {
|
||||
this.signatureTargetHash[i] = input[mypos++];
|
||||
}
|
||||
case 32: // Embedded Signature
|
||||
this.embeddedSignature = new openpgp_packet_signature();
|
||||
this.embeddedSignature.read_packet(input, mypos, len -(mypos-position));
|
||||
return ((mypos+ this.embeddedSignature.packetLength) - position);
|
||||
break;
|
||||
case 100: // Private or experimental
|
||||
case 101: // Private or experimental
|
||||
case 102: // Private or experimental
|
||||
case 103: // Private or experimental
|
||||
case 104: // Private or experimental
|
||||
case 105: // Private or experimental
|
||||
case 106: // Private or experimental
|
||||
case 107: // Private or experimental
|
||||
case 108: // Private or experimental
|
||||
case 109: // Private or experimental
|
||||
case 110: // Private or experimental
|
||||
return subplen+1;
|
||||
util.print_error("openpgp.packet.signature.js\n"+'private or experimental signature subpacket type '+type+" @:"+mypos+" subplen:"+subplen+" len:"+len);
|
||||
break;
|
||||
case 0: // Reserved
|
||||
case 1: // Reserved
|
||||
case 8: // Reserved
|
||||
case 10: // Placeholder for backward compatibility
|
||||
case 13: // Reserved
|
||||
case 14: // Reserved
|
||||
case 15: // Reserved
|
||||
case 17: // Reserved
|
||||
case 18: // Reserved
|
||||
case 19: // Reserved
|
||||
default:
|
||||
util.print_error("openpgp.packet.signature.js\n"+'unknown signature subpacket type '+type+" @:"+mypos+" subplen:"+subplen+" len:"+len);
|
||||
return subplen+1;
|
||||
break;
|
||||
}
|
||||
return mypos -position;
|
||||
};
|
||||
/**
|
||||
* verifys the signature packet. Note: not signature types are implemented
|
||||
* @param data [String] data which on the signature applies
|
||||
* @param key [openpgp_msg_privatekey] the public key to verify the signature
|
||||
* @return
|
||||
*/
|
||||
function verify(data, key) {
|
||||
switch(this.signatureType) {
|
||||
// calculating the trailer
|
||||
case 0: // 0x00: Signature of a binary document.
|
||||
if (this.version == 4) {
|
||||
var trailer = '';
|
||||
trailer += String.fromCharCode(this.version);
|
||||
trailer += String.fromCharCode(0xFF);
|
||||
trailer += String.fromCharCode(this.signatureData.length >> 24);
|
||||
trailer += String.fromCharCode((this.signatureData.length >> 16) &0xFF);
|
||||
trailer += String.fromCharCode((this.signatureData.length >> 8) &0xFF);
|
||||
trailer += String.fromCharCode(this.signatureData.length & 0xFF);
|
||||
return openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
||||
this.MPIs, key.obj.publicKeyPacket.MPIs, data.substring(i)+this.signatureData+trailer);
|
||||
} else if (this.version == 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
case 1: // 0x01: Signature of a canonical text document.
|
||||
if (this.version == 4) {
|
||||
var trailer = '';
|
||||
trailer += String.fromCharCode(this.version);
|
||||
trailer += String.fromCharCode(0xFF);
|
||||
trailer += String.fromCharCode(this.signatureData.length >> 24);
|
||||
trailer += String.fromCharCode((this.signatureData.length >> 16) &0xFF);
|
||||
trailer += String.fromCharCode((this.signatureData.length >> 8) &0xFF);
|
||||
trailer += String.fromCharCode(this.signatureData.length &0xFF);
|
||||
return openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
||||
this.MPIs, key.obj.publicKeyPacket.MPIs, data+this.signatureData+trailer);
|
||||
} else if (this.version == 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
case 2: // 0x02: Standalone signature.
|
||||
// This signature is a signature of only its own subpacket contents.
|
||||
// It is calculated identically to a signature over a zero-length
|
||||
// binary document. Note that it doesn't make sense to have a V3
|
||||
// standalone signature.
|
||||
if (this.version == 3)
|
||||
return false;
|
||||
|
||||
var trailer = '';
|
||||
trailer += String.fromCharCode(this.version);
|
||||
trailer += String.fromCharCode(0xFF);
|
||||
trailer += String.fromCharCode(this.signatureData.length >> 24);
|
||||
trailer += String.fromCharCode((this.signatureData.length >> 16) &0xFF);
|
||||
trailer += String.fromCharCode((this.signatureData.length >> 8) &0xFF);
|
||||
trailer += String.fromCharCode(this.signatureData.length &0xFF);
|
||||
return openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
||||
this.MPIs, key.obj.publicKeyPacket.MPIs, this.signatureData+trailer);
|
||||
case 16:
|
||||
// 0x10: Generic certification of a User ID and Public-Key packet.
|
||||
// The issuer of this certification does not make any particular
|
||||
// assertion as to how well the certifier has checked that the owner
|
||||
// of the key is in fact the person described by the User ID.
|
||||
case 17:
|
||||
// 0x11: Persona certification of a User ID and Public-Key packet.
|
||||
// The issuer of this certification has not done any verification of
|
||||
// the claim that the owner of this key is the User ID specified.
|
||||
case 18:
|
||||
// 0x12: Casual certification of a User ID and Public-Key packet.
|
||||
// The issuer of this certification has done some casual
|
||||
// verification of the claim of identity.
|
||||
case 19:
|
||||
// 0x13: Positive certification of a User ID and Public-Key packet.
|
||||
// The issuer of this certification has done substantial
|
||||
// verification of the claim of identity.
|
||||
//
|
||||
// Most OpenPGP implementations make their "key signatures" as 0x10
|
||||
// certifications. Some implementations can issue 0x11-0x13
|
||||
// certifications, but few differentiate between the types.
|
||||
case 48:
|
||||
// 0x30: Certification revocation signature
|
||||
// This signature revokes an earlier User ID certification signature
|
||||
// (signature class 0x10 through 0x13) or direct-key signature
|
||||
// (0x1F). It should be issued by the same key that issued the
|
||||
// revoked signature or an authorized revocation key. The signature
|
||||
// is computed over the same data as the certificate that it
|
||||
// revokes, and should have a later creation date than that
|
||||
// certificate.
|
||||
|
||||
var trailer = '';
|
||||
trailer += String.fromCharCode(this.version);
|
||||
trailer += String.fromCharCode(0xFF);
|
||||
trailer += String.fromCharCode(this.signatureData.length >> 24);
|
||||
trailer += String.fromCharCode((this.signatureData.length >> 16) &0xFF);
|
||||
trailer += String.fromCharCode((this.signatureData.length >> 8) &0xFF);
|
||||
trailer += String.fromCharCode(this.signatureData.length &0xFF);
|
||||
return openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
||||
this.MPIs, key.MPIs, data+this.signatureData+trailer);
|
||||
|
||||
case 24:
|
||||
// 0x18: Subkey Binding Signature
|
||||
// This signature is a statement by the top-level signing key that
|
||||
// indicates that it owns the subkey. This signature is calculated
|
||||
// directly on the primary key and subkey, and not on any User ID or
|
||||
// other packets. A signature that binds a signing subkey MUST have
|
||||
// an Embedded Signature subpacket in this binding signature that
|
||||
// contains a 0x19 signature made by the signing subkey on the
|
||||
// primary key and subkey.
|
||||
if (this.version == 3)
|
||||
return false;
|
||||
|
||||
var trailer = '';
|
||||
trailer += String.fromCharCode(this.version);
|
||||
trailer += String.fromCharCode(0xFF);
|
||||
trailer += String.fromCharCode(this.signatureData.length >> 24);
|
||||
trailer += String.fromCharCode((this.signatureData.length >> 16) &0xFF);
|
||||
trailer += String.fromCharCode((this.signatureData.length >> 8) &0xFF);
|
||||
trailer += String.fromCharCode(this.signatureData.length &0xFF);
|
||||
return openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
||||
this.MPIs, key.MPIs, data+this.signatureData+trailer);
|
||||
case 25:
|
||||
// 0x19: Primary Key Binding Signature
|
||||
// This signature is a statement by a signing subkey, indicating
|
||||
// that it is owned by the primary key and subkey. This signature
|
||||
// is calculated the same way as a 0x18 signature: directly on the
|
||||
// primary key and subkey, and not on any User ID or other packets.
|
||||
|
||||
// When a signature is made over a key, the hash data starts with the
|
||||
// octet 0x99, followed by a two-octet length of the key, and then body
|
||||
// of the key packet. (Note that this is an old-style packet header for
|
||||
// a key packet with two-octet length.) A subkey binding signature
|
||||
// (type 0x18) or primary key binding signature (type 0x19) then hashes
|
||||
// the subkey using the same format as the main key (also using 0x99 as
|
||||
// the first octet).
|
||||
case 31:
|
||||
// 0x1F: Signature directly on a key
|
||||
// This signature is calculated directly on a key. It binds the
|
||||
// information in the Signature subpackets to the key, and is
|
||||
// appropriate to be used for subpackets that provide information
|
||||
// about the key, such as the Revocation Key subpacket. It is also
|
||||
// appropriate for statements that non-self certifiers want to make
|
||||
// about the key itself, rather than the binding between a key and a
|
||||
// name.
|
||||
case 32:
|
||||
// 0x20: Key revocation signature
|
||||
// The signature is calculated directly on the key being revoked. A
|
||||
// revoked key is not to be used. Only revocation signatures by the
|
||||
// key being revoked, or by an authorized revocation key, should be
|
||||
// considered valid revocation signatures.
|
||||
case 40:
|
||||
// 0x28: Subkey revocation signature
|
||||
// The signature is calculated directly on the subkey being revoked.
|
||||
// A revoked subkey is not to be used. Only revocation signatures
|
||||
// by the top-level signature key that is bound to this subkey, or
|
||||
// by an authorized revocation key, should be considered valid
|
||||
// revocation signatures.
|
||||
var trailer = '';
|
||||
trailer += String.fromCharCode(this.version);
|
||||
trailer += String.fromCharCode(0xFF);
|
||||
trailer += String.fromCharCode(this.signatureData.length >> 24);
|
||||
trailer += String.fromCharCode((this.signatureData.length >> 16) &0xFF);
|
||||
trailer += String.fromCharCode((this.signatureData.length >> 8) &0xFF);
|
||||
trailer += String.fromCharCode(this.signatureData.length &0xFF);
|
||||
return openpgp_crypto_verifySignature(this.publicKeyAlgorithm, this.hashAlgorithm,
|
||||
this.MPIs, key.MPIs, data+this.signatureData+trailer);
|
||||
|
||||
|
||||
// Key revocation signatures (types 0x20 and 0x28)
|
||||
// hash only the key being revoked.
|
||||
case 64:
|
||||
// 0x40: Timestamp signature.
|
||||
// This signature is only meaningful for the timestamp contained in
|
||||
// it.
|
||||
case 80:
|
||||
// 0x50: Third-Party Confirmation signature.
|
||||
// This signature is a signature over some other OpenPGP Signature
|
||||
// packet(s). It is analogous to a notary seal on the signed data.
|
||||
// A third-party signature SHOULD include Signature Target
|
||||
// subpacket(s) to give easy identification. Note that we really do
|
||||
// mean SHOULD. There are plausible uses for this (such as a blind
|
||||
// party that only sees the signature, not the key or source
|
||||
// document) that cannot include a target subpacket.
|
||||
default:
|
||||
util.print_error("openpgp.packet.signature.js\n"+"signature verification for type"+ this.signatureType+" not implemented");
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* generates debug output (pretty print)
|
||||
* @return String which gives some information about the signature packet
|
||||
*/
|
||||
|
||||
function toString () {
|
||||
if (this.version == 3) {
|
||||
var result = '5.2. Signature Packet (Tag 2)\n'+
|
||||
"Packet Length: :"+this.packetLength+'\n'+
|
||||
"Packet version: :"+this.version+'\n'+
|
||||
"One-octet signature type :"+this.signatureType+'\n'+
|
||||
"Four-octet creation time. :"+this.creationTime+'\n'+
|
||||
"Eight-octet Key ID of signer. :"+util.hexidump(this.keyId)+'\n'+
|
||||
"One-octet public-key algorithm. :"+this.publicKeyAlgorithm+'\n'+
|
||||
"One-octet hash algorithm. :"+this.hashAlgorithm+'\n'+
|
||||
"Two-octet field holding left\n" +
|
||||
" 16 bits of signed hash value. :"+this.signedHashValue+'\n';
|
||||
} else {
|
||||
var result = '5.2. Signature Packet (Tag 2)\n'+
|
||||
"Packet Length: :"+this.packetLength+'\n'+
|
||||
"Packet version: :"+this.version+'\n'+
|
||||
"One-octet signature type :"+this.signatureType+'\n'+
|
||||
"One-octet public-key algorithm. :"+this.publicKeyAlgorithm+'\n'+
|
||||
"One-octet hash algorithm. :"+this.hashAlgorithm+'\n'+
|
||||
"Two-octet field holding left\n" +
|
||||
" 16 bits of signed hash value. :"+this.signedHashValue+'\n'+
|
||||
"Signature Creation Time :"+this.creationTime+'\n'+
|
||||
"Signature Expiration Time :"+this.signatureExpirationTime+'\n'+
|
||||
"Signature Never Expires :"+this.signatureNeverExpires+'\n'+
|
||||
"Exportable Certification :"+this.exportable+'\n'+
|
||||
"Trust Signature level: :"+this.trustLevel+' amount'+this.trustAmount+'\n'+
|
||||
"Regular Expression :"+this.regular_expression+'\n'+
|
||||
"Revocable :"+this.revocable+'\n'+
|
||||
"Key Expiration Time :"+this.keyExpirationTime+" "+this.keyNeverExpires+'\n'+
|
||||
"Preferred Symmetric Algorithms :"+this.preferredSymmetricAlgorithms+'\n'+
|
||||
"Revocation Key"+'\n'+
|
||||
" ( 1 octet of class, :"+this.revocationKeyClass +'\n'+
|
||||
" 1 octet of public-key ID, :" +this.revocationKeyAlgorithm+'\n'+
|
||||
" 20 octets of fingerprint) :"+this.revocationKeyFingerprint+'\n'+
|
||||
"Issuer :"+util.hexstrdump(this.issuerKeyId)+'\n'+
|
||||
"Preferred Hash Algorithms :"+this.preferredHashAlgorithms+'\n'+
|
||||
"Preferred Compression Alg. :"+this.preferredCompressionAlgorithms+'\n'+
|
||||
"Key Server Preferences :"+this.keyServerPreferences+'\n'+
|
||||
"Preferred Key Server :"+this.preferredKeyServer+'\n'+
|
||||
"Primary User ID :"+this.isPrimaryUserID+'\n'+
|
||||
"Policy URI :"+this.policyURI+'\n'+
|
||||
"Key Flags :"+this.keyFlags+'\n'+
|
||||
"Signer's User ID :"+this.signersUserId+'\n'+
|
||||
"Notation :"+this.notationName+" = "+this.notationValue+"\n"+
|
||||
"Reason for Revocation\n"+
|
||||
" Flag :"+this.reasonForRevocationFlag+'\n'+
|
||||
" Reason :"+this.reasonForRevocationString+'\nMPI:\n';
|
||||
}
|
||||
for (var i = 0; i < this.MPIs.length; i++) {
|
||||
result += this.MPIs[i].toString();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the issuer key id of this signature
|
||||
* @return [String] issuer key id as string (8bytes)
|
||||
*/
|
||||
function getIssuer() {
|
||||
if (this.version == 4)
|
||||
return this.issuerKeyId;
|
||||
if (this.verions == 4)
|
||||
return this.keyId;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to get the corresponding public key out of the public keyring for the issuer created this signature
|
||||
* @return {obj: [openpgp_msg_publickey], text: [String]} if found the public key will be returned. null otherwise
|
||||
*/
|
||||
function getIssuerKey() {
|
||||
var result = null;
|
||||
if (this.version == 4) {
|
||||
result = openpgp.keyring.getPublicKeysForKeyId(this.issuerKeyId);
|
||||
} else if (this.version == 3) {
|
||||
result = openpgp.keyring.getPublicKeysForKeyId(this.keyId);
|
||||
} else return null;
|
||||
if (result.length == 0)
|
||||
return null;
|
||||
return result[0];
|
||||
}
|
||||
this.getIssuerKey = getIssuerKey;
|
||||
this.getIssuer = getIssuer;
|
||||
this.write_message_signature = write_message_signature;
|
||||
this.verify = verify;
|
||||
this.read_packet = read_packet;
|
||||
this.toString = toString;
|
||||
}
|
||||
153
src/packet/openpgp.packet.userattribute.js
Executable file
153
src/packet/openpgp.packet.userattribute.js
Executable file
@@ -0,0 +1,153 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* The User Attribute packet is a variation of the User ID packet. It
|
||||
* is capable of storing more types of data than the User ID packet,
|
||||
* which is limited to text. Like the User ID packet, a User Attribute
|
||||
* packet may be certified by the key owner ("self-signed") or any other
|
||||
* key owner who cares to certify it. Except as noted, a User Attribute
|
||||
* packet may be used anywhere that a User ID packet may be used.
|
||||
*
|
||||
* While User Attribute packets are not a required part of the OpenPGP
|
||||
* standard, implementations SHOULD provide at least enough
|
||||
* compatibility to properly handle a certification signature on the
|
||||
* User Attribute packet. A simple way to do this is by treating the
|
||||
* User Attribute packet as a User ID packet with opaque contents, but
|
||||
* an implementation may use any method desired.
|
||||
*/
|
||||
function openpgp_packet_userattribute() {
|
||||
this.tagType = 17;
|
||||
this.certificationSignatures = new Array();
|
||||
this.certificationRevocationSignatures = new Array();
|
||||
this.revocationSignatures = new Array();
|
||||
this.parentNode = null;
|
||||
|
||||
/**
|
||||
* parsing function for a user attribute packet (tag 17).
|
||||
* @param input [string] payload of a tag 17 packet
|
||||
* @param position [integer] position to start reading from the input string
|
||||
* @param len [integer] length of the packet or the remaining length of input at position
|
||||
* @return [openpgp_packet_encrypteddata] object representation
|
||||
*/
|
||||
function read_packet (input, position, len) {
|
||||
var total_len = 0;
|
||||
this.packetLength = len;
|
||||
this.userattributes = new Array();
|
||||
var count = 0;
|
||||
var mypos = position;
|
||||
while (len != total_len) {
|
||||
var current_len = 0;
|
||||
// 4.2.2.1. One-Octet Lengths
|
||||
if (input[mypos].charCodeAt() < 192) {
|
||||
packet_length = input[mypos++].charCodeAt();
|
||||
current_len = 1;
|
||||
// 4.2.2.2. Two-Octet Lengths
|
||||
} else if (input[mypos].charCodeAt() >= 192 && input[mypos].charCodeAt() < 224) {
|
||||
packet_length = ((input[mypos++].charCodeAt() - 192) << 8)
|
||||
+ (input[mypos++].charCodeAt()) + 192;
|
||||
current_len = 2;
|
||||
// 4.2.2.4. Partial Body Lengths
|
||||
} else if (input[mypos].charCodeAt() > 223 && input[mypos].charCodeAt() < 255) {
|
||||
packet_length = 1 << (input[mypos++].charCodeAt() & 0x1F);
|
||||
current_len = 1;
|
||||
// 4.2.2.3. Five-Octet Lengths
|
||||
} else {
|
||||
current_len = 5;
|
||||
mypos++;
|
||||
packet_length = (input[mypos++].charCodeAt() << 24) | (input[mypos++].charCodeAt() << 16)
|
||||
| (input[mypos++].charCodeAt() << 8) | input[mypos++].charCodeAt();
|
||||
}
|
||||
|
||||
var subpackettype = input[mypos++].charCodeAt();
|
||||
packet_length--;
|
||||
current_len++;
|
||||
this.userattributes[count] = new Array();
|
||||
this.userattributes[count] = input.substring(mypos, mypos + packet_length);
|
||||
mypos += packet_length;
|
||||
total_len += current_len+packet_length;
|
||||
}
|
||||
this.packetLength = mypos - position;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* generates debug output (pretty print)
|
||||
* @return String which gives some information about the user attribute packet
|
||||
*/
|
||||
function toString() {
|
||||
var result = '5.12. User Attribute Packet (Tag 17)\n'+
|
||||
' AttributePackets: (count = '+this.userattributes.length+')\n';
|
||||
for (var i = 0; i < this.userattributes.length; i++) {
|
||||
result += ' ('+this.userattributes[i].length+') bytes: ['+util.hexidump(this.userattributes[i])+']\n';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Continue parsing packets belonging to the user attribute packet such as signatures
|
||||
* @param parent_node [openpgp_*] the parent object
|
||||
* @param input [String] input string to read the packet(s) from
|
||||
* @param position [integer] start position for the parser
|
||||
* @param len [integer] length of the packet(s) or remaining length of input
|
||||
* @return [integer] length of nodes read
|
||||
*/
|
||||
function read_nodes(parent_node, input, position, len) {
|
||||
|
||||
this.parentNode = parent_node;
|
||||
var exit = false;
|
||||
var pos = position;
|
||||
var l = len;
|
||||
while (input.length != pos) {
|
||||
var result = openpgp_packet.read_packet(input, pos, l);
|
||||
if (result == null) {
|
||||
util.print_error("openpgp.packet.userattribute.js\n"+'[user_attr] parsing ends here @:' + pos + " l:" + l);
|
||||
break;
|
||||
} else {
|
||||
switch (result.tagType) {
|
||||
case 2: // Signature Packet
|
||||
if (result.signatureType > 15
|
||||
&& result.signatureType < 20) // certification
|
||||
// //
|
||||
// signature
|
||||
this.certificationSignatures[this.certificationSignatures.length] = result;
|
||||
else if (result.signatureType == 32) // certification revocation signature
|
||||
this.certificationRevocationSignatures[this.certificationRevocationSignatures.length] = result;
|
||||
pos += result.packetLength + result.headerLength;
|
||||
l = len - (pos - position);
|
||||
break;
|
||||
default:
|
||||
this.data = input;
|
||||
this.position = position - parent_node.packetLength;
|
||||
this.len = pos - position;
|
||||
return this.len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.data = input;
|
||||
this.position = position - parent_node.packetLength;
|
||||
this.len = pos - position;
|
||||
return this.len;
|
||||
|
||||
}
|
||||
|
||||
this.read_packet = read_packet;
|
||||
this.read_nodes = read_nodes;
|
||||
this.toString = toString;
|
||||
|
||||
};
|
||||
333
src/packet/openpgp.packet.userid.js
Executable file
333
src/packet/openpgp.packet.userid.js
Executable file
@@ -0,0 +1,333 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* A User ID packet consists of UTF-8 text that is intended to represent
|
||||
* the name and email address of the key holder. By convention, it
|
||||
* includes an RFC 2822 [RFC2822] mail name-addr, but there are no
|
||||
* restrictions on its content. The packet length in the header
|
||||
* specifies the length of the User ID.
|
||||
*/
|
||||
|
||||
function openpgp_packet_userid() {
|
||||
this.tagType = 13;
|
||||
this.certificationSignatures = new Array();
|
||||
this.certificationRevocationSignatures = new Array();
|
||||
this.revocationSignatures = new Array();
|
||||
this.parentNode = null;
|
||||
|
||||
/**
|
||||
* parsing function for a user id packet (tag 13).
|
||||
* @param input [string] payload of a tag 13 packet
|
||||
* @param position [integer] position to start reading from the input string
|
||||
* @param len [integer] length of the packet or the remaining length of input at position
|
||||
* @return [openpgp_packet_encrypteddata] object representation
|
||||
*/
|
||||
function read_packet(input, position, len) {
|
||||
this.text = '';
|
||||
this.packetLength = len;
|
||||
|
||||
for ( var i = 0; i < len; i++) {
|
||||
this.text += input[position + i];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a string representation of the user id packet
|
||||
* @param user_id [String] the user id as string ("John Doe <john.doe@mail.us")
|
||||
* @return [String] string representation
|
||||
*/
|
||||
function write_packet(user_id) {
|
||||
this.text = user_id;
|
||||
var result = openpgp_packet.write_packet_header(13,this.text.length);
|
||||
result += this.text;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Continue parsing packets belonging to the userid packet such as signatures
|
||||
* @param parent_node [openpgp_*] the parent object
|
||||
* @param input [String] input string to read the packet(s) from
|
||||
* @param position [integer] start position for the parser
|
||||
* @param len [integer] length of the packet(s) or remaining length of input
|
||||
* @return [integer] length of nodes read
|
||||
*/
|
||||
function read_nodes(parent_node, input, position, len) {
|
||||
if (parent_node.tagType == 6) { // public key
|
||||
this.parentNode = parent_node;
|
||||
var pos = position;
|
||||
var l = len;
|
||||
while (input.length != pos) {
|
||||
var result = openpgp_packet.read_packet(input, pos, l - (pos - position));
|
||||
if (result == null) {
|
||||
util.print_error('[user_id] parsing ends here @:' + pos + " l:" + l);
|
||||
break;
|
||||
} else {
|
||||
|
||||
pos += result.packetLength + result.headerLength;
|
||||
l = input.length - pos;
|
||||
switch (result.tagType) {
|
||||
case 2: // Signature Packet
|
||||
if (result.signatureType > 15
|
||||
&& result.signatureType < 20) { // certification
|
||||
// //
|
||||
// signature
|
||||
this.certificationSignatures[this.certificationSignatures.length] = result;
|
||||
break;
|
||||
} else if (result.signatureType == 48) {// certification revocation signature
|
||||
this.certificationRevocationSignatures[this.certificationRevocationSignatures.length] = result;
|
||||
break;
|
||||
} else if (result.signatureType == 24) { // omg. standalone signature
|
||||
this.certificationSignatures[this.certificationSignatures.length] = result;
|
||||
break;
|
||||
} else {
|
||||
util.debug("unknown sig t: "+result.signatureType+"@"+(pos - (result.packetLength + result.headerLength)));
|
||||
}
|
||||
default:
|
||||
this.data = input;
|
||||
this.position = position - parent_node.packetLength;
|
||||
this.len = pos - position -(result.headerLength + result.packetLength);
|
||||
return this.len;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.data = input;
|
||||
this.position = position - parent_node.packetLength;
|
||||
this.len = pos - position -(result.headerLength + result.packetLength);
|
||||
return this.len;
|
||||
} else if (parent_node.tagType == 5) { // secret Key
|
||||
this.parentNode = parent_node;
|
||||
var exit = false;
|
||||
var pos = position;
|
||||
while (input.length != pos) {
|
||||
var result = openpgp_packet.read_packet(input, pos, l - (pos - position));
|
||||
if (result == null) {
|
||||
util.print_error('parsing ends here @:' + pos + " l:" + l);
|
||||
break;
|
||||
} else {
|
||||
pos += result.packetLength + result.headerLength;
|
||||
l = input.length - pos;
|
||||
switch (result.tagType) {
|
||||
case 2: // Signature Packet certification signature
|
||||
if (result.signatureType > 15
|
||||
&& result.signatureType < 20)
|
||||
this.certificationSignatures[this.certificationSignatures.length] = result;
|
||||
// certification revocation signature
|
||||
else if (result.signatureType == 48)
|
||||
this.certificationRevocationSignatures[this.certificationRevocationSignatures.length] = result;
|
||||
default:
|
||||
this.data = input;
|
||||
this.position = position - parent_node.packetLength;
|
||||
this.len = pos - position -(result.headerLength + result.packetLength);
|
||||
return this.len;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
util.print_error("unknown parent node for a userId packet "+parent_node.tagType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* generates debug output (pretty print)
|
||||
* @return String which gives some information about the user id packet
|
||||
*/
|
||||
function toString() {
|
||||
var result = ' 5.11. User ID Packet (Tag 13)\n' + ' text ('
|
||||
+ this.text.length + '): "' + this.text.replace("<", "<")
|
||||
+ '"\n';
|
||||
result +="certification signatures:\n";
|
||||
for (var i = 0; i < this.certificationSignatures.length; i++) {
|
||||
result += " "+this.certificationSignatures[i].toString();
|
||||
}
|
||||
result +="certification revocation signatures:\n";
|
||||
for (var i = 0; i < this.certificationRevocationSignatures.length; i++) {
|
||||
result += " "+this.certificationRevocationSignatures[i].toString();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* lookup function to find certification revocation signatures
|
||||
* @param keyId string containing the key id of the issuer of this signature
|
||||
* @return a CertificationRevocationSignature if found; otherwise null
|
||||
*/
|
||||
function hasCertificationRevocationSignature(keyId) {
|
||||
for (var i = 0; i < this.certificationRevocationSignatures.length; i++) {
|
||||
if ((this.certificationRevocationSignatures[i].version == 3 &&
|
||||
this.certificationRevocationSignatures[i].keyId == keyId) ||
|
||||
(this.certificationRevocationSignatures[i].version == 4 &&
|
||||
this.certificationRevocationSignatures[i].issuerKeyId == keyId))
|
||||
return this.certificationRevocationSignatures[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies all certification signatures. This method does not consider possible revocation signatures.
|
||||
* @param publicKeyPacket the top level key material
|
||||
* @return an array of integers corresponding to the array of certification signatures. The meaning of each integer is the following:
|
||||
* 0 = bad signature
|
||||
* 1 = signature expired
|
||||
* 2 = issuer key not available
|
||||
* 3 = revoked
|
||||
* 4 = signature valid
|
||||
* 5 = signature by key owner expired
|
||||
* 6 = signature by key owner revoked
|
||||
*/
|
||||
function verifyCertificationSignatures(publicKeyPacket) {
|
||||
result = new Array();
|
||||
for (var i = 0 ; i < this.certificationSignatures.length; i++) {
|
||||
// A certification signature (type 0x10 through 0x13) hashes the User
|
||||
// ID being bound to the key into the hash context after the above
|
||||
// data. A V3 certification hashes the contents of the User ID or
|
||||
// attribute packet packet, without any header. A V4 certification
|
||||
// hashes the constant 0xB4 for User ID certifications or the constant
|
||||
// 0xD1 for User Attribute certifications, followed by a four-octet
|
||||
// number giving the length of the User ID or User Attribute data, and
|
||||
// then the User ID or User Attribute data.
|
||||
|
||||
if (this.certificationSignatures[i].version == 4) {
|
||||
if (this.certificationSignatures[i].signatureExpirationTime != null &&
|
||||
this.certificationSignatures[i].signatureExpirationTime != null &&
|
||||
this.certificationSignatures[i].signatureExpirationTime != 0 &&
|
||||
!this.certificationSignatures[i].signatureNeverExpires &&
|
||||
new Date(this.certificationSignatures[i].creationTime.getTime() +(this.certificationSignatures[i].signatureExpirationTime*1000)) < new Date()) {
|
||||
if (this.certificationSignatures[i].issuerKeyId == publicKeyPacket.getKeyId())
|
||||
result[i] = 5;
|
||||
else
|
||||
result[i] = 1;
|
||||
continue;
|
||||
}
|
||||
if (this.certificationSignatures[i].issuerKeyId == null) {
|
||||
result[i] = 0;
|
||||
continue;
|
||||
}
|
||||
var issuerPublicKey = openpgp.keyring.getPublicKeysForKeyId(this.certificationSignatures[i].issuerKeyId);
|
||||
if (issuerPublicKey == null || issuerPublicKey.length == 0) {
|
||||
result[i] = 2;
|
||||
continue;
|
||||
}
|
||||
// TODO: try to verify all returned issuer public keys (key ids are not unique!)
|
||||
var issuerPublicKey = issuerPublicKey[0];
|
||||
var signingKey = issuerPublicKey.obj.getSigningKey();
|
||||
if (signingKey == null) {
|
||||
result[i] = 0;
|
||||
continue;
|
||||
}
|
||||
var revocation = this.hasCertificationRevocationSignature(this.certificationSignatures[i].issuerKeyId);
|
||||
if (revocation != null && revocation.creationTime >
|
||||
this.certificationSignatures[i].creationTime) {
|
||||
var signaturedata = String.fromCharCode(0x99)+ publicKeyPacket.header.substring(1)+
|
||||
publicKeyPacket.data+String.fromCharCode(0xB4)+
|
||||
String.fromCharCode((this.text.length >> 24) & 0xFF)+
|
||||
String.fromCharCode((this.text.length >> 16) & 0xFF)+
|
||||
String.fromCharCode((this.text.length >> 8) & 0xFF)+
|
||||
String.fromCharCode((this.text.length) & 0xFF)+
|
||||
this.text;
|
||||
if (revocation.verify(signaturedata, signingKey)) {
|
||||
if (this.certificationSignatures[i].issuerKeyId == publicKeyPacket.getKeyId())
|
||||
result[i] = 6;
|
||||
else
|
||||
result[i] = 3;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
var signaturedata = String.fromCharCode(0x99)+ publicKeyPacket.header.substring(1)+
|
||||
publicKeyPacket.data+String.fromCharCode(0xB4)+
|
||||
String.fromCharCode((this.text.length >> 24) & 0xFF)+
|
||||
String.fromCharCode((this.text.length >> 16) & 0xFF)+
|
||||
String.fromCharCode((this.text.length >> 8) & 0xFF)+
|
||||
String.fromCharCode((this.text.length) & 0xFF)+
|
||||
this.text;
|
||||
if (this.certificationSignatures[i].verify(signaturedata, signingKey)) {
|
||||
result[i] = 4;
|
||||
} else
|
||||
result[i] = 0;
|
||||
} else if (this.certificationSignatures[i].version == 3) {
|
||||
if (this.certificationSignatures[i].keyId == null) {
|
||||
result[i] = 0;
|
||||
continue;
|
||||
}
|
||||
var issuerPublicKey = openpgp.keyring.getPublicKeysForKeyId(this.certificationSignatures[i].keyId);
|
||||
if (issuerPublicKey == null || issuerPublicKey.length == 0) {
|
||||
result[i] = 2;
|
||||
continue;
|
||||
}
|
||||
issuerPublicKey = issuerPublicKey[0];
|
||||
var signingKey = publicKey.obj.getSigningKey();
|
||||
if (signingKey == null) {
|
||||
result[i] = 0;
|
||||
continue;
|
||||
}
|
||||
var revocation = this.hasCertificationRevocationSignature(this.certificationSignatures[i].keyId);
|
||||
if (revocation != null && revocation.creationTime >
|
||||
this.certificationSignatures[i].creationTime) {
|
||||
var signaturedata = String.fromCharCode(0x99)+ this.publicKeyPacket.header.substring(1)+
|
||||
this.publicKeyPacket.data+this.text;
|
||||
if (revocation.verify(signaturedata, signingKey)) {
|
||||
if (revocation.keyId == publicKeyPacket.getKeyId())
|
||||
result[i] = 6;
|
||||
else
|
||||
result[i] = 3;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
var signaturedata = String.fromCharCode(0x99)+ publicKeyPacket.header.substring(1)+
|
||||
publicKeyPacket.data+this.text;
|
||||
if (this.certificationSignatures[i].verify(signaturedata, signingKey)) {
|
||||
result[i] = 4;
|
||||
} else
|
||||
result[i] = 0;
|
||||
} else {
|
||||
result[i] = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* verifies the signatures of the user id
|
||||
* @return 0 if the userid is valid; 1 = userid expired; 2 = userid revoked
|
||||
*/
|
||||
function verify(publicKeyPacket) {
|
||||
var result = this.verifyCertificationSignatures(publicKeyPacket);
|
||||
if (result.indexOf(6) != -1)
|
||||
return 2;
|
||||
if (result.indexOf(5) != -1)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: implementation missing
|
||||
function addCertification(publicKeyPacket, privateKeyPacket) {
|
||||
|
||||
}
|
||||
|
||||
// TODO: implementation missing
|
||||
function revokeCertification(publicKeyPacket, privateKeyPacket) {
|
||||
|
||||
}
|
||||
|
||||
this.hasCertificationRevocationSignature = hasCertificationRevocationSignature;
|
||||
this.verifyCertificationSignatures = verifyCertificationSignatures;
|
||||
this.verify = verify;
|
||||
this.read_packet = read_packet;
|
||||
this.toString = toString;
|
||||
this.read_nodes = read_nodes;
|
||||
}
|
||||
47
src/type/openpgp.type.keyid.js
Executable file
47
src/type/openpgp.type.keyid.js
Executable file
@@ -0,0 +1,47 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* Implementation of type key id (RFC4880 3.3)
|
||||
* A Key ID is an eight-octet scalar that identifies a key.
|
||||
Implementations SHOULD NOT assume that Key IDs are unique. The
|
||||
section "Enhanced Key Formats" below describes how Key IDs are
|
||||
formed.
|
||||
*/
|
||||
function openpgp_type_keyid() {
|
||||
/**
|
||||
* parsing method for a key id
|
||||
* @param input [String] input to read the key id from
|
||||
* @param position [integer] position where to start reading the key id from input
|
||||
* @return this object
|
||||
*/
|
||||
function read_packet(input, position) {
|
||||
this.bytes = input.substring(position, position+8);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* generates debug output (pretty print)
|
||||
* @return [String] Key Id as hexadecimal string
|
||||
*/
|
||||
function toString() {
|
||||
return util.hexstrdump(this.bytes);
|
||||
}
|
||||
|
||||
this.read_packet = read_packet;
|
||||
this.toString = toString;
|
||||
};
|
||||
132
src/type/openpgp.type.mpi.js
Executable file
132
src/type/openpgp.type.mpi.js
Executable file
@@ -0,0 +1,132 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
// Hint: We hold our MPIs as an array of octets in big endian format preceeding a two
|
||||
// octet scalar: MPI: [a,b,c,d,e,f]
|
||||
// - MPI size: (a << 8) | b
|
||||
// - MPI = c | d << 8 | e << ((MPI.length -2)*8) | f ((MPI.length -2)*8)
|
||||
|
||||
/**
|
||||
* Implementation of type MPI (RFC4880 3.2)
|
||||
* Multiprecision integers (also called MPIs) are unsigned integers used
|
||||
* to hold large integers such as the ones used in cryptographic
|
||||
* calculations.
|
||||
* An MPI consists of two pieces: a two-octet scalar that is the length
|
||||
* of the MPI in bits followed by a string of octets that contain the
|
||||
* actual integer.
|
||||
*/
|
||||
function openpgp_type_mpi() {
|
||||
this.MPI = null;
|
||||
this.mpiBitLength = null;
|
||||
this.mpiByteLength = null;
|
||||
this.data = null;
|
||||
/**
|
||||
* parsing function for a mpi (RFC 4880 3.2).
|
||||
* @param input [string] payload of mpi data
|
||||
* @param position [integer] position to start reading from the input string
|
||||
* @param len [integer] length of the packet or the remaining length of input at position
|
||||
* @return [openpgp_type_mpi] object representation
|
||||
*/
|
||||
function read(input, position, len) {
|
||||
var mypos = position;
|
||||
|
||||
this.mpiBitLength = (input[mypos++].charCodeAt() << 8) | input[mypos++].charCodeAt();
|
||||
|
||||
// Additional rules:
|
||||
//
|
||||
// The size of an MPI is ((MPI.length + 7) / 8) + 2 octets.
|
||||
//
|
||||
// The length field of an MPI describes the length starting from its
|
||||
// most significant non-zero bit. Thus, the MPI [00 02 01] is not
|
||||
// formed correctly. It should be [00 01 01].
|
||||
|
||||
// TODO: Verification of this size method! This size calculation as
|
||||
// specified above is not applicable in JavaScript
|
||||
this.mpiByteLength = (this.mpiBitLength - (this.mpiBitLength % 8)) / 8;
|
||||
if (this.mpiBitLength % 8 != 0)
|
||||
this.mpiByteLength++;
|
||||
|
||||
this.MPI = input.substring(mypos,mypos+this.mpiByteLength);
|
||||
this.data = input.substring(position, position+2+this.mpiByteLength);
|
||||
this.packetLength = this.mpiByteLength +2;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* generates debug output (pretty print)
|
||||
* @return String which gives some information about the mpi
|
||||
*/
|
||||
function toString() {
|
||||
var r = " MPI("+this.mpiBitLength+"b/"+this.mpiByteLength+"B) : 0x";
|
||||
r+=util.hexstrdump(this.MPI);
|
||||
return r+'\n';
|
||||
}
|
||||
|
||||
/**
|
||||
* converts the mpi to an BigInteger object
|
||||
* @return [BigInteger]
|
||||
*/
|
||||
function getBigInteger() {
|
||||
return new BigInteger(util.hexstrdump(this.MPI),16);
|
||||
}
|
||||
|
||||
|
||||
function getBits(num) {
|
||||
for (var i = 0; i < 9; i++)
|
||||
if (num >> i == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the length of the mpi in bytes
|
||||
* @return [integer] mpi byte length
|
||||
*/
|
||||
function getByteLength() {
|
||||
return this.mpiByteLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates an mpi from the specified string
|
||||
* @param data [String] data to read the mpi from
|
||||
* @return [openpgp_type_mpi]
|
||||
*/
|
||||
function create(data) {
|
||||
this.MPI = data;
|
||||
this.mpiBitLength = (data.length -1) *8 + getBits(data.charCodeAt(0));
|
||||
this.mpiByteLength = data.length;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* converts the mpi object to a string as specified in RFC4880 3.2
|
||||
* @return [String] mpi byte representation
|
||||
*/
|
||||
function toBin() {
|
||||
var result = String.fromCharCode((this.mpiBitLength >> 8) & 0xFF);
|
||||
result += String.fromCharCode(this.mpiBitLength & 0xFF);
|
||||
result += this.MPI;
|
||||
return result;
|
||||
}
|
||||
|
||||
this.read = read;
|
||||
this.toBigInteger = getBigInteger;
|
||||
this.toString = toString;
|
||||
this.create = create;
|
||||
this.toBin = toBin;
|
||||
this.getByteLength = getByteLength;
|
||||
}
|
||||
|
||||
98
src/type/openpgp.type.s2k.js
Executable file
98
src/type/openpgp.type.s2k.js
Executable file
@@ -0,0 +1,98 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/**
|
||||
* Implementation of the String-to-key specifier (RFC4880 3.7)
|
||||
* String-to-key (S2K) specifiers are used to convert passphrase strings
|
||||
into symmetric-key encryption/decryption keys. They are used in two
|
||||
places, currently: to encrypt the secret part of private keys in the
|
||||
private keyring, and to convert passphrases to encryption keys for
|
||||
symmetrically encrypted messages.
|
||||
*/
|
||||
function openpgp_type_s2k() {
|
||||
/**
|
||||
* parsing function for a string-to-key specifier (RFC 4880 3.7).
|
||||
* @param input [string] payload of string-to-key specifier
|
||||
* @param position [integer] position to start reading from the input string
|
||||
* @return [openpgp_type_s2k] object representation
|
||||
*/
|
||||
function read(input, position) {
|
||||
var mypos = position;
|
||||
this.type = input[mypos++].charCodeAt();
|
||||
switch (this.type) {
|
||||
case 0: // Simple S2K
|
||||
// Octet 1: hash algorithm
|
||||
this.hashAlgorithm = input[mypos++].charCodeAt();
|
||||
this.s2kLength = 1;
|
||||
break;
|
||||
|
||||
case 1: // Salted S2K
|
||||
// Octet 1: hash algorithm
|
||||
this.hashAlgorithm = input[mypos++].charCodeAt();
|
||||
|
||||
// Octets 2-9: 8-octet salt value
|
||||
this.saltValue = input.substring(mypos, mypos+8);
|
||||
mypos += 8;
|
||||
this.s2kLength = 9;
|
||||
break;
|
||||
|
||||
case 3: // Iterated and Salted S2K
|
||||
// Octet 1: hash algorithm
|
||||
this.hashAlgorithm = input[mypos++].charCodeAt();
|
||||
|
||||
// Octets 2-9: 8-octet salt value
|
||||
this.saltValue = input.substring(mypos, mypos+8);
|
||||
mypos += 8;
|
||||
|
||||
// Octet 10: count, a one-octet, coded value
|
||||
this.EXPBIAS = 6;
|
||||
var c = input[mypos++].charCodeAt();
|
||||
this.count = (16 + (c & 15)) << ((c >> 4) + this.EXPBIAS);
|
||||
this.s2kLength = 10;
|
||||
break;
|
||||
|
||||
case 2: // Reserved value
|
||||
default:
|
||||
util.print_error("unknown s2k type! "+this.type);
|
||||
break;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* produces a key using the specified passphrase and the defined hashAlgorithm
|
||||
* @param passphrase [String] passphrase containing user input
|
||||
* @return [String] produced key with a length corresponding to hashAlgorithm hash length
|
||||
*/
|
||||
function produce_key(passphrase) {
|
||||
if (this.type == 0) {
|
||||
return openpgp_crypto_hashData(this.hashAlgorithm,passphrase);
|
||||
} else if (this.type == 1) {
|
||||
return openpgp_crypto_hashData(this.hashAlgorithm,this.saltValue+passphrase);
|
||||
} else if (this.type == 3) {
|
||||
var isp = this.saltValue+passphrase;
|
||||
while (isp.length < this.count)
|
||||
isp += this.saltValue+passphrase;
|
||||
if (isp.length < this.count)
|
||||
isp = isp.substr(0, this.count);
|
||||
return openpgp_crypto_hashData(this.hashAlgorithm,isp);
|
||||
} else return null;
|
||||
}
|
||||
|
||||
this.read = read;
|
||||
this.produce_key = produce_key;
|
||||
}
|
||||
217
src/util/util.js
Executable file
217
src/util/util.js
Executable file
@@ -0,0 +1,217 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
var Util = function() {
|
||||
|
||||
this.hexdump = function(str) {
|
||||
var r="";
|
||||
var e=str.length;
|
||||
var c=0;
|
||||
var h;
|
||||
var i = 0;
|
||||
while(c<e){
|
||||
h=str.charCodeAt(c++).toString(16);
|
||||
while(h.length<2) h="0"+h;
|
||||
r+=" "+h;
|
||||
i++;
|
||||
if (i % 32 == 0)
|
||||
r+="\n ";
|
||||
}
|
||||
return r;
|
||||
};
|
||||
/**
|
||||
* create hexstring from a binary
|
||||
* @param str [String] string to convert
|
||||
* @return [String] string containing the hexadecimal values
|
||||
*/
|
||||
this.hexstrdump = function(str) {
|
||||
if (str == null)
|
||||
return "";
|
||||
var r="";
|
||||
var e=str.length;
|
||||
var c=0;
|
||||
var h;
|
||||
while(c<e){
|
||||
h=str[c++].charCodeAt().toString(16);
|
||||
while(h.length<2) h="0"+h;
|
||||
r+=""+h;
|
||||
}
|
||||
return r;
|
||||
};
|
||||
/**
|
||||
* creating a hex string from an binary array of integers (0..255)
|
||||
* @param [Array[integer 0..255]] array to convert
|
||||
* @return [String] hexadecimal representation of the array
|
||||
*/
|
||||
this.hexidump = function(str) {
|
||||
var r="";
|
||||
var e=str.length;
|
||||
var c=0;
|
||||
var h;
|
||||
while(c<e){
|
||||
h=str[c++].toString(16);
|
||||
while(h.length<2) h="0"+h;
|
||||
r+=""+h;
|
||||
}
|
||||
return r;
|
||||
};
|
||||
|
||||
/**
|
||||
* convert a string to an array of integers(0.255)
|
||||
* @param [String] string to convert
|
||||
* @return [Array [Integer 0..255]] array of (binary) integers
|
||||
*/
|
||||
this.str2bin = function(str) {
|
||||
var result = new Array();
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
result[i] = str.charCodeAt(i);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* convert an array of integers(0.255) to a string
|
||||
* @param [Array [Integer 0..255]] array of (binary) integers to convert
|
||||
* @return [String] string representation of the array
|
||||
*/
|
||||
this.bin2str = function(bin) {
|
||||
var result = "";
|
||||
for (var i = 0; i < bin.length; i++) {
|
||||
result += String.fromCharCode(bin[i]);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* calculates a 16bit sum of a string by adding each character codes modulus 65535
|
||||
* @param text [String] string to create a sum of
|
||||
* @return [Integer] an integer containing the sum of all character codes % 65535
|
||||
*/
|
||||
this.calc_checksum = function(text) {
|
||||
var checksum = { s: 0, add: function (sadd) { this.s = (this.s + sadd) % 65536; }};
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
checksum.add(text.charCodeAt(i));
|
||||
}
|
||||
return checksum.s;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to print a debug message. Debug
|
||||
* messages are only printed if
|
||||
* openpgp.config.debug is set to true. The calling
|
||||
* Javascript context MUST define
|
||||
* a "showMessages(text)" function. Line feeds ('\n')
|
||||
* are automatically converted to HTML line feeds '<br/>'
|
||||
* @param str [String] string of the debug message
|
||||
* @return [String] an HTML tt entity containing a paragraph with a style attribute where the debug message is HTMLencoded in.
|
||||
*/
|
||||
this.print_debug = function(str) {
|
||||
if (openpgp.config.debug) {
|
||||
str = openpgp_encoding_html_encode(str);
|
||||
showMessages("<tt><p style=\"background-color: #ffffff; width: 652px; word-break: break-word; padding: 5px; border-bottom: 1px solid black;\">"+str.replace(/\n/g,"<br>")+"</p></tt>");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to print an error message.
|
||||
* The calling Javascript context MUST define
|
||||
* a "showMessages(text)" function. Line feeds ('\n')
|
||||
* are automatically converted to HTML line feeds '<br/>'
|
||||
* @param str [String] string of the error message
|
||||
* @return [String] a HTML paragraph entity with a style attribute containing the HTML encoded error message
|
||||
*/
|
||||
this.print_error = function(str) {
|
||||
str = openpgp_encoding_html_encode(str);
|
||||
showMessages("<p style=\"font-size: 80%; background-color: #FF8888; margin:0; width: 652px; word-break: break-word; padding: 5px; border-bottom: 1px solid black;\"><span style=\"color: #888;\"><b>ERROR:</b></span> "+str.replace(/\n/g,"<br>")+"</p>");
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to print an info message.
|
||||
* The calling Javascript context MUST define
|
||||
* a "showMessages(text)" function. Line feeds ('\n')
|
||||
* are automatically converted to HTML line feeds '<br/>'.
|
||||
* @param str [String] string of the info message
|
||||
* @return [String] a HTML paragraph entity with a style attribute containing the HTML encoded info message
|
||||
*/
|
||||
this.print_info = function(str) {
|
||||
str = openpgp_encoding_html_encode(str);
|
||||
showMessages("<p style=\"font-size: 80%; background-color: #88FF88; margin:0; width: 652px; word-break: break-word; padding: 5px; border-bottom: 1px solid black;\"><span style=\"color: #888;\"><b>INFO:</b></span> "+str.replace(/\n/g,"<br>")+"</p>");
|
||||
};
|
||||
|
||||
this.print_warning = function(str) {
|
||||
str = openpgp_encoding_html_encode(str);
|
||||
showMessages("<p style=\"font-size: 80%; background-color: #FFAA88; margin:0; width: 652px; word-break: break-word; padding: 5px; border-bottom: 1px solid black;\"><span style=\"color: #888;\"><b>WARNING:</b></span> "+str.replace(/\n/g,"<br>")+"</p>");
|
||||
};
|
||||
|
||||
this.getLeftNBits = function (string, bitcount) {
|
||||
var rest = bitcount % 8;
|
||||
if (rest == 0)
|
||||
return string.substring(0, bitcount / 8);
|
||||
var bytes = (bitcount - rest) / 8 +1;
|
||||
var result = string.substring(0, bytes);
|
||||
return this.shiftRight(result, 8-rest); // +String.fromCharCode(string.charCodeAt(bytes -1) << (8-rest) & 0xFF);
|
||||
};
|
||||
/**
|
||||
* Shifting a string to n bits right
|
||||
* @param value [String] the string to shift
|
||||
* @param bitcount [Integer] amount of bits to shift (MUST be smaller than 9)
|
||||
* @return [String] resulting string.
|
||||
*/
|
||||
this.shiftRight = function(value, bitcount) {
|
||||
var temp = util.str2bin(value);
|
||||
if (bitcount % 8 != 0) {
|
||||
for (var i = temp.length-1; i >= 0; i--) {
|
||||
temp[i] >>= bitcount % 8;
|
||||
if (i > 0)
|
||||
temp[i] |= (temp[i - 1] << (8 - (bitcount % 8))) & 0xFF;
|
||||
}
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
return util.bin2str(temp);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the algorithm type as string
|
||||
* @return [String] String representing the message type
|
||||
*/
|
||||
this.get_hashAlgorithmString = function(algo) {
|
||||
switch(algo) {
|
||||
case 1:
|
||||
return "MD5";
|
||||
case 2:
|
||||
return "SHA1";
|
||||
case 3:
|
||||
return "RIPEMD160";
|
||||
case 8:
|
||||
return "SHA256";
|
||||
case 9:
|
||||
return "SHA384";
|
||||
case 10:
|
||||
return "SHA512";
|
||||
case 11:
|
||||
return "SHA224";
|
||||
}
|
||||
return "unknown";
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* an instance that should be used.
|
||||
*/
|
||||
var util = new Util();
|
||||
17
test/ciphers/hash/md5.js
Normal file
17
test/ciphers/hash/md5.js
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
unittests.register("MD5 test with test vectors from RFC 1321", function() {
|
||||
var result = new Array();
|
||||
result[0] = new test_result("MD5 (\"\") = d41d8cd98f00b204e9800998ecf8427e",
|
||||
util.hexstrdump(MD5("")) == "d41d8cd98f00b204e9800998ecf8427e");
|
||||
result[1] = new test_result("MD5 (\"a\") = 0cc175b9c0f1b6a831c399e269772661",
|
||||
util.hexstrdump(MD5 ("abc")) == "900150983cd24fb0d6963f7d28e17f72");
|
||||
result[2] = new test_result("MD5 (\"message digest\") = f96b697d7cb7938d525a2f31aaf161d0",
|
||||
util.hexstrdump(MD5 ("message digest")) == "f96b697d7cb7938d525a2f31aaf161d0");
|
||||
result[3] = new test_result("MD5 (\"abcdefghijklmnopqrstuvwxyz\") = c3fcd3d76192e4007dfb496cca67e13b",
|
||||
util.hexstrdump(MD5 ("abcdefghijklmnopqrstuvwxyz")) == "c3fcd3d76192e4007dfb496cca67e13b");
|
||||
result[4] = new test_result("MD5 (\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\") = d174ab98d277d9f5a5611c2c9f419d9f",
|
||||
util.hexstrdump(MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")) == "d174ab98d277d9f5a5611c2c9f419d9f");
|
||||
result[5] = new test_result("MD5 (\"12345678901234567890123456789012345678901234567890123456789012345678901234567890\") = 57edf4a22be3c955ac49da2e2107b67a",
|
||||
util.hexstrdump(MD5 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890")) == "57edf4a22be3c955ac49da2e2107b67a");
|
||||
return result;
|
||||
});
|
||||
13
test/ciphers/hash/ripe-md.js
Normal file
13
test/ciphers/hash/ripe-md.js
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
unittests.register("RIPE-MD 160 bits test with test vectors from http://homes.esat.kuleuven.be/~bosselae/ripemd160.html", function() {
|
||||
var result = new Array();
|
||||
result[0] = new test_result("RMDstring (\"\") = 9c1185a5c5e9fc54612808977ee8f548b2258d31",
|
||||
util.hexstrdump(RMDstring("")) == "9c1185a5c5e9fc54612808977ee8f548b2258d31");
|
||||
result[1] = new test_result("RMDstring (\"a\") = 0bdc9d2d256b3ee9daae347be6f4dc835a467ffe",
|
||||
util.hexstrdump(RMDstring("a")) == "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe");
|
||||
result[2] = new test_result("RMDstring (\"abc\") = 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc",
|
||||
util.hexstrdump(RMDstring("abc")) == "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc");
|
||||
result[3] = new test_result("RMDstring (\"message digest\") = 5d0689ef49d2fae572b881b123a85ffa21595f36",
|
||||
util.hexstrdump(RMDstring("message digest")) == "5d0689ef49d2fae572b881b123a85ffa21595f36");
|
||||
return result;
|
||||
});
|
||||
26
test/ciphers/hash/sha.js
Normal file
26
test/ciphers/hash/sha.js
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
unittests.register("SHA* test with test vectors from NIST FIPS 180-2", function() {
|
||||
var result = new Array();
|
||||
|
||||
result[0] = new test_result("SHA1 - a9993e364706816aba3e25717850c26c9cd0d89d = str_sha1(\"abc\") ",
|
||||
"a9993e364706816aba3e25717850c26c9cd0d89d" == util.hexstrdump(str_sha1("abc")));
|
||||
result[1] = new test_result("SHA1 - 84983e441c3bd26ebaae4aa1f95129e5e54670f1 = str_sha1(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ",
|
||||
"84983e441c3bd26ebaae4aa1f95129e5e54670f1" == util.hexstrdump(str_sha1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")));
|
||||
result[2] = new test_result("SHA224 - 23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 = str_sha224(\"abc\") ",
|
||||
"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7" == util.hexstrdump(str_sha224("abc")));
|
||||
result[3] = new test_result("SHA224 - 75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525 = str_sha224(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ",
|
||||
"75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525" == util.hexstrdump(str_sha224("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")));
|
||||
result[4] = new test_result("SHA256 - ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad = str_sha256(\"abc\") ",
|
||||
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" == util.hexstrdump(str_sha256("abc")));
|
||||
result[5] = new test_result("SHA256 - 248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1 = str_sha256(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ",
|
||||
"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" == util.hexstrdump(str_sha256("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")));
|
||||
result[6] = new test_result("SHA384 - cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7 = str_sha384(\"abc\") ",
|
||||
"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7" == util.hexstrdump(str_sha384("abc")));
|
||||
result[7] = new test_result("SHA384 - 3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b = str384(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ",
|
||||
"3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b" == util.hexstrdump(str_sha384("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")));
|
||||
result[8] = new test_result("SHA512 - ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f = str_sha512(\"abc\") ",
|
||||
"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f" == util.hexstrdump(str_sha512("abc")));
|
||||
result[9] = new test_result("SHA512 - 204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445 = str_sha512(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\") ",
|
||||
"204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445" == util.hexstrdump(str_sha512("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")));
|
||||
return result;
|
||||
});
|
||||
8
test/example-test.js
Normal file
8
test/example-test.js
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
unittests.register("Example test", function() {
|
||||
var result = new Array();
|
||||
|
||||
result[0] = new test_result("test1 - testing on (\"str\" == \"str\")", ("str" == "str"));
|
||||
result[1] = new test_result("test2 - testing on (1 == 1)", (1 == 1));
|
||||
return result;
|
||||
});
|
||||
151
test/index.html
Normal file
151
test/index.html
Normal file
@@ -0,0 +1,151 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<script type="text/javascript" src="../resources/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="../src/ciphers/hash/sha.js"></script>
|
||||
<script type="text/javascript" src="../src/ciphers/hash/md5.js"></script>
|
||||
<script type="text/javascript" src="../src/ciphers/hash/ripe-md.js"></script>
|
||||
|
||||
<!-- crypto libs -->
|
||||
<script type="text/javascript" src="../src/ciphers/symmetric/aes.js"></script>
|
||||
<script type="text/javascript" src="../src/ciphers/symmetric/cast5.js"></script>
|
||||
<script type="text/javascript" src="../src/ciphers/symmetric/dessrc.js"></script>
|
||||
<script type="text/javascript" src="../src/ciphers/symmetric/twofish.js"></script>
|
||||
<script type="text/javascript" src="../src/ciphers/symmetric/blowfish.js"></script>
|
||||
|
||||
<script type="text/javascript" src="../src/ciphers/asymmetric/jsbn.js"></script>
|
||||
<script type="text/javascript" src="../src/ciphers/asymmetric/jsbn2.js"></script>
|
||||
<script type="text/javascript" src="../src/ciphers/asymmetric/dsa.js"></script>
|
||||
<script type="text/javascript" src="../src/ciphers/asymmetric/elgamal.js"></script>
|
||||
<script type="text/javascript" src="../src/ciphers/asymmetric/rsa.js"></script>
|
||||
|
||||
<script type="text/javascript" src="../src/ciphers/openpgp.crypto.js"></script>
|
||||
<script type="text/javascript" src="../src/ciphers/openpgp.cfb.js"></script>
|
||||
|
||||
<!-- compression -->
|
||||
|
||||
<!-- encoding -->
|
||||
<script type="text/javascript" src="../src/encoding/base64.js"></script>
|
||||
<script type="text/javascript" src="../src/encoding/openpgp.encoding.asciiarmor.js"></script>
|
||||
<script type="text/javascript" src="../src/encoding/openpgp.encoding.js"></script>
|
||||
|
||||
<!-- openpgp types -->
|
||||
<script type="text/javascript" src="../src/type/openpgp.type.keyid.js"></script>
|
||||
<script type="text/javascript" src="../src/type/openpgp.type.mpi.js"></script>
|
||||
<script type="text/javascript" src="../src/type/openpgp.type.s2k.js"></script>
|
||||
|
||||
<!-- openpgp packets -->
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.compressed.js"></script>
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.encrypteddata.js"></script>
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.encryptedintegrityprotecteddata.js"></script>
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.encryptedsessionkey.js"></script>
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.keymaterial.js"></script>
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.literaldata.js"></script>
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.marker.js"></script>
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.modificationdetectioncode.js"></script>
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.onepasssignature.js"></script>
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.signature.js"></script>
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.userattribute.js"></script>
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.userid.js"></script>
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.js"></script>
|
||||
|
||||
<!-- openpgp impl. -->
|
||||
<script type="text/javascript" src="../src/openpgp.js"></script>
|
||||
<script type="text/javascript" src="../src/config/openpgp.config.js"></script>
|
||||
<script type="text/javascript" src="../src/openpgp.keyring.js"></script>
|
||||
<script type="text/javascript" src="../src/openpgp.msg.message.js"></script>
|
||||
<script type="text/javascript" src="../src/openpgp.msg.privatekey.js"></script>
|
||||
<script type="text/javascript" src="../src/openpgp.msg.publickey.js"></script>
|
||||
<script type="text/javascript" src="../src/util/util.js"></script>
|
||||
|
||||
<!-- unit test -->
|
||||
<script type="text/javascript" src="unittest.js"></script>
|
||||
<script type="text/javascript" src="example-test.js"></script>
|
||||
|
||||
<script type="text/javascript" src="ciphers/hash/md5.js"></script>
|
||||
<script type="text/javascript" src="ciphers/hash/sha.js"></script>
|
||||
<script type="text/javascript" src="ciphers/hash/ripe-md.js"></script>
|
||||
|
||||
<title>OpenPGP.js testpage</title>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<style>
|
||||
* {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
#debug, #testoutput {
|
||||
border: 1px dotted #aaa;
|
||||
background-color: #eee;
|
||||
margin: 5px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.successful {
|
||||
background-color: #afa;
|
||||
}
|
||||
.failed {
|
||||
background-color: #faa;
|
||||
|
||||
}
|
||||
#unittests tbody tr th {
|
||||
background-color: #eee;
|
||||
border: 1px dotted #aaa;
|
||||
}
|
||||
|
||||
#unittests tbody tr td {
|
||||
padding: 2px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.unittesttitle {
|
||||
font-weight: bold;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.unittestrow {
|
||||
border-top: 1px solid #aaa;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
openpgp.init();
|
||||
// message function required by util.print_message, util.print_debug, util.print_warning
|
||||
|
||||
function showMessages(str) {
|
||||
$('#debug').append(str);
|
||||
}
|
||||
|
||||
function unit_tests() {
|
||||
$('#unittests').empty();
|
||||
$('#unittests').append("<tr><th>Unit</th><th>Description</th><th>Result</th></tr>");
|
||||
var result = unittests.runAll();
|
||||
var html = "";
|
||||
for (var i = 0; i < result.length; i++) {
|
||||
html += "<tr class=\"unittestrow\"><td rowspan=\""+result[i].tests.length+"\" class=\"unittesttitle\">"+result[i].title+"</td>";
|
||||
if (result[i].tests.length > 0) {
|
||||
html += "<td>"+result[i].tests[0].description+"</td><td "+(result[i].tests[0].result ? "class=\"successful\">ok</td>" : "class=\"failed\">FAILED</td>" )+"</tr>";
|
||||
}
|
||||
for (var j = 1; j < result[i].tests.length; j++) {
|
||||
html +="<tr><td>"+result[i].tests[j].description+"</td><td "+(result[i].tests[j].result ? "class=\"successful\">ok</td>" : "class=\"failed\">FAILED</td>")+"</tr>";
|
||||
}
|
||||
}
|
||||
$('#unittests').append(html);
|
||||
}
|
||||
|
||||
</script>
|
||||
<a href="index.html">Unit Tests</a> | <a href="parser.html">Parser</a> | <a href="encryption.html">Encryption / Decryption</a>
|
||||
<p><input id="enabledebug" type="checkbox" onclick="($('#enabledebug').is(':checked') ? openpgp.config.debug = true : openpgp.config.debug = false)"> Print Debug Messages </p>
|
||||
<h1>Unit tests</h1>
|
||||
|
||||
<table id="unittests"></table><br>
|
||||
<button type="submit" onmousedown="unit_tests();">Run unit tests</button>
|
||||
|
||||
<!-- src/util/util.js print_debug() writes to -->
|
||||
<h2>Messages</h2>
|
||||
<div id="debug"></div>
|
||||
</body>
|
||||
</html>
|
||||
126
test/parser.html
Normal file
126
test/parser.html
Normal file
@@ -0,0 +1,126 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<script type="text/javascript" src="../resources/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="../src/ciphers/hash/sha.js"></script>
|
||||
<script type="text/javascript" src="../src/ciphers/hash/md5.js"></script>
|
||||
<script type="text/javascript" src="../src/ciphers/hash/ripe-md.js"></script>
|
||||
|
||||
<!-- crypto libs -->
|
||||
<script type="text/javascript" src="../src/ciphers/symmetric/aes.js"></script>
|
||||
<script type="text/javascript" src="../src/ciphers/symmetric/cast5.js"></script>
|
||||
<script type="text/javascript" src="../src/ciphers/symmetric/dessrc.js"></script>
|
||||
<script type="text/javascript" src="../src/ciphers/symmetric/twofish.js"></script>
|
||||
<script type="text/javascript" src="../src/ciphers/symmetric/blowfish.js"></script>
|
||||
|
||||
<script type="text/javascript" src="../src/ciphers/asymmetric/jsbn.js"></script>
|
||||
<script type="text/javascript" src="../src/ciphers/asymmetric/jsbn2.js"></script>
|
||||
<script type="text/javascript" src="../src/ciphers/asymmetric/dsa.js"></script>
|
||||
<script type="text/javascript" src="../src/ciphers/asymmetric/elgamal.js"></script>
|
||||
<script type="text/javascript" src="../src/ciphers/asymmetric/rsa.js"></script>
|
||||
|
||||
<script type="text/javascript" src="../src/ciphers/openpgp.crypto.js"></script>
|
||||
<script type="text/javascript" src="../src/ciphers/openpgp.cfb.js"></script>
|
||||
|
||||
<!-- compression -->
|
||||
|
||||
<!-- encoding -->
|
||||
<script type="text/javascript" src="../src/encoding/base64.js"></script>
|
||||
<script type="text/javascript" src="../src/encoding/openpgp.encoding.asciiarmor.js"></script>
|
||||
<script type="text/javascript" src="../src/encoding/openpgp.encoding.js"></script>
|
||||
|
||||
<!-- openpgp types -->
|
||||
<script type="text/javascript" src="../src/type/openpgp.type.keyid.js"></script>
|
||||
<script type="text/javascript" src="../src/type/openpgp.type.mpi.js"></script>
|
||||
<script type="text/javascript" src="../src/type/openpgp.type.s2k.js"></script>
|
||||
|
||||
<!-- openpgp packets -->
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.compressed.js"></script>
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.encrypteddata.js"></script>
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.encryptedintegrityprotecteddata.js"></script>
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.encryptedsessionkey.js"></script>
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.keymaterial.js"></script>
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.literaldata.js"></script>
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.marker.js"></script>
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.modificationdetectioncode.js"></script>
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.onepasssignature.js"></script>
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.signature.js"></script>
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.userattribute.js"></script>
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.userid.js"></script>
|
||||
<script type="text/javascript" src="../src/packet/openpgp.packet.js"></script>
|
||||
|
||||
<!-- openpgp impl. -->
|
||||
<script type="text/javascript" src="../src/openpgp.js"></script>
|
||||
<script type="text/javascript" src="../src/config/openpgp.config.js"></script>
|
||||
<script type="text/javascript" src="../src/openpgp.keyring.js"></script>
|
||||
<script type="text/javascript" src="../src/openpgp.msg.message.js"></script>
|
||||
<script type="text/javascript" src="../src/openpgp.msg.privatekey.js"></script>
|
||||
<script type="text/javascript" src="../src/openpgp.msg.publickey.js"></script>
|
||||
<script type="text/javascript" src="../src/util/util.js"></script>
|
||||
|
||||
<!-- unit test -->
|
||||
<script type="text/javascript" src="unittest.js"></script>
|
||||
<script type="text/javascript" src="example-test.js"></script>
|
||||
<title>OpenPGP.js testpage</title>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<style>
|
||||
* {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
#debug, #testoutput {
|
||||
border: 1px dotted #aaa;
|
||||
background-color: #eee;
|
||||
margin: 5px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
openpgp.init();
|
||||
|
||||
// message function required by util.print_message, util.print_debug, util.print_warning
|
||||
|
||||
function showMessages(str) {
|
||||
$('#debug').append(str);
|
||||
}
|
||||
|
||||
function test() {
|
||||
$('#testoutput').empty();
|
||||
var value = $('input:radio[name=message_type]:checked').val();
|
||||
var result = null;
|
||||
if (value == 0) {
|
||||
result = openpgp.read_message($('#testinput').val());
|
||||
} else if (value == 1) {
|
||||
result = openpgp.read_publicKey($('#testinput').val());
|
||||
} else if (value == 2) {
|
||||
result = openpgp.read_privateKey($('#testinput').val());
|
||||
}
|
||||
for (var i = 0; i < result.length; i++)
|
||||
$('#testoutput').text(result[i].toString());
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
$('#enabledebug').is(':checked') ? openpgp.config.debug = true : openpgp.config.debug = false;
|
||||
});
|
||||
</script>
|
||||
<a href="index.html">Unit Tests</a> | <a href="parser.html">Parser</a> | <a href="encryption.html">Encryption / Decryption</a>
|
||||
<p><input id="enabledebug" type="checkbox" onclick="($('#enabledebug').is(':checked') ? openpgp.config.debug = true : openpgp.config.debug = false)"> Print Debug Messages </p>
|
||||
<h1>Parser</h1>
|
||||
<input type="radio" name="message_type" value="0" checked="checked">OpenPGP Message |
|
||||
<input type="radio" name="message_type" value="1">OpenPGP Public Key |
|
||||
<input type="radio" name="message_type" value="2">OpenPGP Private Key<br>
|
||||
|
||||
<textarea id="testinput" cols="80" rows="25"></textarea><button onmousedown="test();" type="submit">parse</button>
|
||||
<h2>Test output</h2>
|
||||
<pre id="testoutput"></pre>
|
||||
|
||||
<!-- src/util/util.js print_debug() writes to -->
|
||||
<h2>Messages</h2>
|
||||
<div id="debug"></div>
|
||||
</body>
|
||||
</html>
|
||||
21
test/unittest.js
Normal file
21
test/unittest.js
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
var unittests = {
|
||||
tests: Array(),
|
||||
register: function(str_title, func_runtest) {
|
||||
this.tests[this.tests.length] = {title: str_title, run: func_runtest};
|
||||
|
||||
},
|
||||
|
||||
runAll: function() {
|
||||
var result = new Array();
|
||||
for (var i = 0; i < this.tests.length; i++) {
|
||||
result[i] = {tests: this.tests[i].run(), title: this.tests[i].title };
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
function test_result(str_description, boolean_result) {
|
||||
this.description = str_description;
|
||||
this.result = boolean_result;
|
||||
}
|
||||
70
webmail/googlemail.com/gmail.js
Executable file
70
webmail/googlemail.com/gmail.js
Executable file
@@ -0,0 +1,70 @@
|
||||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2011 Recurity Labs GmbH
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
// The google mail interface
|
||||
// these functions retrieve an email out of html
|
||||
var Gmail = {
|
||||
|
||||
getMail : function(callback) {
|
||||
var unquote_printable = function(text) {
|
||||
var result = "";
|
||||
while (text.indexOf("=") != -1) {
|
||||
var i = text.indexOf("=");
|
||||
result += text.substring(0, i);
|
||||
result += String.fromCharCode(parseInt(text.substring(i+1, i+3),16));
|
||||
text = text.substring(i+3);
|
||||
}
|
||||
result += text;
|
||||
return result;
|
||||
};
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "https://mail.google.com/mail/h/?v=om&th="+document.location.hash.split("/")[1],true);
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState == 4) {
|
||||
var mail = new Object();
|
||||
var msg = xhr.responseText.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n");
|
||||
var header = msg.substring(0, msg.indexOf("\r\n\r\n")).replace(/\r\n /g," ").split("\r\n");
|
||||
mail.body = msg.substring(msg.indexOf("\r\n\r\n")+4);
|
||||
for (var i = 0; i < header.length; i++) {
|
||||
var split = header[i].split(": ")
|
||||
if (split[0] == "Content-Transfer-Encoding" && split[1] == "quoted-printable")
|
||||
mail.body = unquote_printable(mail.body);
|
||||
}
|
||||
mail.account = document.getElementsByTagName("title")[0].textContent.split(" - ")[2];
|
||||
|
||||
for (var i = 0; i < header.length; i++) {
|
||||
var split = header[i].split(": ");
|
||||
if (split.length < 2) continue;
|
||||
if (split[0] == "To")
|
||||
mail.to = split[1].split(", ");
|
||||
else if (split[0] == "CC")
|
||||
mail.cc = split[1].split(", ");
|
||||
else if (split[0] == "Subject")
|
||||
mail.subject = split[1];
|
||||
else if (split[0] == "From")
|
||||
mail.from = split[1];
|
||||
else if (split[0] == "Date")
|
||||
mail.date = new Date(split[1]);
|
||||
}
|
||||
callback(mail);
|
||||
|
||||
}
|
||||
};
|
||||
xhr.send();
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user