mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-04-04 05:17:36 +03:00
Initial import.
This commit is contained in:
commit
40981bd7bd
63 changed files with 7603 additions and 0 deletions
6
.classpath
Normal file
6
.classpath
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/Android Library"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
33
.project
Normal file
33
.project
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>KeePassDroid</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
16
AndroidManifest.xml
Normal file
16
AndroidManifest.xml
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.keepass"
|
||||
android:versionCode="1" android:versionName="0.0.1">
|
||||
<application android:label="@string/app_name" android:icon="@drawable/keepass_icon">
|
||||
<activity android:name=".KeePass"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".GroupActivity"></activity>
|
||||
<activity android:name=".EntryActivity"></activity>
|
||||
</application>
|
||||
</manifest>
|
339
COPYING.gpl-2.0
Normal file
339
COPYING.gpl-2.0
Normal file
|
@ -0,0 +1,339 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
67
LICENSE
Normal file
67
LICENSE
Normal file
|
@ -0,0 +1,67 @@
|
|||
The KeePass icon was created by Christopher Bolin and is licensed under the terms of the GPLv2 or GPLv3:
|
||||
http://commons.wikimedia.org/wiki/File:KeePass_icon.png
|
||||
|
||||
Files under src/org/bouncycaste1x/*:
|
||||
|
||||
Copyright (c) 2000 - 2008 The Legion Of The Bouncy Castle
|
||||
(http://www.bouncycastle.org)
|
||||
|
||||
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", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Files under src/org/phoneid/*:
|
||||
|
||||
KeePass for J2ME
|
||||
|
||||
Copyright 2007 Naomaru Itoi <nao@phoneid.org>
|
||||
|
||||
This file was derived from
|
||||
|
||||
Java clone of KeePass - A KeePass file viewer for Java
|
||||
Copyright 2006 Bill Zwicky <billzwicky@users.sourceforge.net>
|
||||
|
||||
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; version 2
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Files under src/com/android/keepass/* :
|
||||
|
||||
Copyright 2009 Brian Pellin <bpellin@gmail.com>.
|
||||
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
|
BIN
res/drawable/keepass_icon.png
Normal file
BIN
res/drawable/keepass_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 43 KiB |
53
res/layout/entry_view.xml
Normal file
53
res/layout/entry_view.xml
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical" android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<TableRow>
|
||||
<TextView android:layout_width="100px"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/entry_title" />
|
||||
<TextView android:id="@+id/entry_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"/>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TextView android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/entry_user_name" />
|
||||
<TextView android:id="@+id/entry_user_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"/>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TextView android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/entry_url" />
|
||||
<TextView android:id="@+id/entry_url"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"/>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TextView android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/entry_password" />
|
||||
<TextView android:id="@+id/entry_password"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"/>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TextView android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/entry_comment" />
|
||||
<TextView android:id="@+id/entry_comment"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"/>
|
||||
</TableRow>
|
||||
|
||||
</TableLayout>
|
12
res/layout/list.xml
Normal file
12
res/layout/list.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
<ListView android:id="@android:id/list"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
<TextView android:id="@android:id/empty"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/no_keys"/>
|
||||
</LinearLayout>
|
31
res/layout/password.xml
Normal file
31
res/layout/password.xml
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical" android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/pass_filename" />
|
||||
<EditText android:id="@+id/pass_filename"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:singleLine="true"/>
|
||||
|
||||
<TextView android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/entry_password" />
|
||||
<EditText android:id="@+id/pass_password"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:password="true"
|
||||
android:singleLine="true"/>
|
||||
|
||||
<Button android:id="@+id/pass_ok"
|
||||
android:text="@string/pass_ok"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
4
res/layout/row.xml
Normal file
4
res/layout/row.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView android:id="@+id/text1" xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
21
res/values/strings.xml
Normal file
21
res/values/strings.xml
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="app_name">KeePass</string>
|
||||
<string name="no_keys">No keys in database.</string>
|
||||
<string name="FileNotFound">/sdcard/keepass/keepass.kdb not found</string>
|
||||
<string name="InvalidPassword">Invalid password.</string>
|
||||
<string name="pass_ok">Ok</string>
|
||||
<string name="entry_title">Name: </string>
|
||||
<string name="entry_user_name">User Name: </string>
|
||||
<string name="entry_url">URL: </string>
|
||||
<string name="entry_password">Password: </string>
|
||||
<string name="entry_comment">Comments: </string>
|
||||
<string name="MaskedPassword">*****</string>
|
||||
<string name="menu_show_password">Show Password</string>
|
||||
<string name="menu_hide_password">Hide Password</string>
|
||||
<string name="menu_copy_url">Copy URL</string>
|
||||
<string name="menu_copy_user">Copy User</string>
|
||||
<string name="menu_copy_pass">Copy Password</string>
|
||||
<string name="pass_filename">Filename:</string>
|
||||
</resources>
|
140
src/com/android/keepass/EntryActivity.java
Normal file
140
src/com/android/keepass/EntryActivity.java
Normal file
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Copyright 2009 Brian Pellin.
|
||||
*
|
||||
* This file is part of KeePassDroid.
|
||||
*
|
||||
* KeePassDroid is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePassDroid 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 KeePassDroid. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.android.keepass;
|
||||
|
||||
import org.phoneid.keepassj2me.PwEntry;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.text.ClipboardManager;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class EntryActivity extends Activity {
|
||||
public static final String KEY_ENTRY = "entry";
|
||||
|
||||
private static final int MENU_PASS = Menu.FIRST;
|
||||
private static final int MENU_COPY_URL = Menu.FIRST + 1;
|
||||
private static final int MENU_COPY_USER = Menu.FIRST + 2;
|
||||
private static final int MENU_COPY_PASS = Menu.FIRST + 3;
|
||||
|
||||
|
||||
public static void Launch(Activity act, PwEntry pw) {
|
||||
Intent i = new Intent(act, EntryActivity.class);
|
||||
|
||||
KeePass.gPwEntry.put(KeePass.gNumPwEntry, pw);
|
||||
i.putExtra(KEY_ENTRY, KeePass.gNumPwEntry);
|
||||
KeePass.gNumPwEntry++;
|
||||
|
||||
act.startActivity(i);
|
||||
}
|
||||
|
||||
private PwEntry mEntry;
|
||||
private int mId;
|
||||
private boolean showPassword = true;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.entry_view);
|
||||
|
||||
Intent i = getIntent();
|
||||
mId = i.getIntExtra(KEY_ENTRY, -1);
|
||||
assert(mId < 0);
|
||||
|
||||
mEntry = KeePass.gPwEntry.get(mId);
|
||||
|
||||
fillData();
|
||||
}
|
||||
|
||||
private void fillData() {
|
||||
populateText(R.id.entry_title, mEntry.title);
|
||||
populateText(R.id.entry_user_name, mEntry.username);
|
||||
populateText(R.id.entry_url, mEntry.url);
|
||||
populateText(R.id.entry_password, getString(R.string.MaskedPassword));
|
||||
populateText(R.id.entry_comment, mEntry.additional);
|
||||
|
||||
}
|
||||
|
||||
private void populateText(int viewId, String text) {
|
||||
TextView tv = (TextView) findViewById(viewId);
|
||||
tv.setText(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
|
||||
menu.add(0, MENU_PASS, 0, R.string.menu_show_password);
|
||||
menu.findItem(MENU_PASS).setIcon(android.R.drawable.ic_menu_view);
|
||||
menu.add(0, MENU_COPY_URL, 0, R.string.menu_copy_url);
|
||||
menu.findItem(MENU_COPY_URL).setIcon(android.R.drawable.ic_menu_upload);
|
||||
menu.add(0, MENU_COPY_USER, 0, R.string.menu_copy_user);
|
||||
menu.findItem(MENU_COPY_USER).setIcon(android.R.drawable.ic_menu_set_as);
|
||||
menu.add(0, MENU_COPY_PASS, 0, R.string.menu_copy_pass);
|
||||
menu.findItem(MENU_COPY_PASS).setIcon(android.R.drawable.ic_menu_agenda);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch ( item.getItemId() ) {
|
||||
case MENU_PASS:
|
||||
if ( showPassword ) {
|
||||
populateText(R.id.entry_password, new String(mEntry.getPassword()));
|
||||
item.setTitle(R.string.menu_hide_password);
|
||||
showPassword = false;
|
||||
} else {
|
||||
populateText(R.id.entry_password, getString(R.string.MaskedPassword));
|
||||
item.setTitle(R.string.menu_show_password);
|
||||
showPassword = true;
|
||||
}
|
||||
return true;
|
||||
|
||||
case MENU_COPY_URL:
|
||||
copyToClipboard(mEntry.url);
|
||||
return true;
|
||||
case MENU_COPY_USER:
|
||||
copyToClipboard(mEntry.username);
|
||||
return true;
|
||||
case MENU_COPY_PASS:
|
||||
copyToClipboard(new String(mEntry.getPassword()));
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void copyToClipboard(String text) {
|
||||
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
||||
clipboard.setText(text);
|
||||
}
|
||||
|
||||
}
|
99
src/com/android/keepass/GroupActivity.java
Normal file
99
src/com/android/keepass/GroupActivity.java
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright 2009 Brian Pellin.
|
||||
*
|
||||
* This file is part of KeePassDroid.
|
||||
*
|
||||
* KeePassDroid is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePassDroid 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 KeePassDroid. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.android.keepass;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
import org.phoneid.keepassj2me.PwEntry;
|
||||
import org.phoneid.keepassj2me.PwGroup;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ListActivity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.ListView;
|
||||
|
||||
public class GroupActivity extends ListActivity {
|
||||
|
||||
public static final String KEY_ENTRY = "entry";
|
||||
|
||||
private Vector mGroups;
|
||||
private Vector mEntries;
|
||||
|
||||
public static void Launch(Activity act, Vector groups, Vector entries) {
|
||||
Intent i = new Intent(act, GroupActivity.class);
|
||||
|
||||
KeePass.gGroups.put(KeePass.gNumEntries, groups);
|
||||
KeePass.gEntries.put(KeePass.gNumEntries, entries);
|
||||
|
||||
i.putExtra(KEY_ENTRY, KeePass.gNumEntries);
|
||||
|
||||
KeePass.gNumEntries++;
|
||||
|
||||
act.startActivity(i);
|
||||
}
|
||||
|
||||
private int mId;
|
||||
|
||||
@Override
|
||||
protected void onListItemClick(ListView l, View v, int position, long id) {
|
||||
// TODO Auto-generated method stub
|
||||
super.onListItemClick(l, v, position, id);
|
||||
int size = mGroups.size();
|
||||
PwItemView iv;
|
||||
if (position < size ) {
|
||||
PwGroup group = (PwGroup) mGroups.elementAt(position);
|
||||
iv = new PwGroupView(this, group);
|
||||
} else {
|
||||
PwEntry entry = (PwEntry) mEntries.elementAt(position - size);
|
||||
iv = new PwEntryView(this, entry);
|
||||
}
|
||||
iv.onClick();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.list);
|
||||
|
||||
mId = getIntent().getIntExtra(KEY_ENTRY, -1);
|
||||
assert(mId >= 0);
|
||||
|
||||
mGroups = KeePass.gGroups.get(mId);
|
||||
assert(mGroups != null);
|
||||
mEntries = KeePass.gEntries.get(mId);
|
||||
assert(mEntries != null);
|
||||
|
||||
|
||||
setListAdapter(new PwListAdapter(this, mGroups, mEntries));
|
||||
getListView().setTextFilterEnabled(true);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
KeePass.gGroups.remove(mId);
|
||||
KeePass.gEntries.remove(mId);
|
||||
}
|
||||
|
||||
}
|
179
src/com/android/keepass/KeePass.java
Normal file
179
src/com/android/keepass/KeePass.java
Normal file
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* Copyright 2009 Brian Pellin.
|
||||
*
|
||||
* This file is part of KeePassDroid.
|
||||
*
|
||||
* KeePassDroid is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePassDroid 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 KeePassDroid. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.android.keepass;
|
||||
|
||||
import org.bouncycastle1.crypto.InvalidCipherTextException;
|
||||
import org.phoneid.keepassj2me.ImporterV3;
|
||||
import org.phoneid.keepassj2me.PwEntry;
|
||||
import org.phoneid.keepassj2me.PwManager;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Vector;
|
||||
|
||||
public class KeePass extends Activity {
|
||||
|
||||
|
||||
private PwManager mPM;
|
||||
public static HashMap<Integer, Vector> gGroups = new HashMap<Integer, Vector>();
|
||||
public static HashMap<Integer, Vector> gEntries = new HashMap<Integer, Vector>();
|
||||
public static Integer gNumEntries = new Integer(0);
|
||||
|
||||
public static HashMap<Integer, PwEntry> gPwEntry = new HashMap<Integer, PwEntry>();
|
||||
public static Integer gNumPwEntry = new Integer(0);
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.password);
|
||||
|
||||
Button confirmButton = (Button) findViewById(R.id.pass_ok);
|
||||
confirmButton.setOnClickListener(new ClickHandler(this));
|
||||
|
||||
loadDefaultPrefs();
|
||||
|
||||
//setEditText(R.id.pass_password, "12345");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
setEditText(R.id.pass_password, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
|
||||
saveDefaultPrefs();
|
||||
}
|
||||
|
||||
private void loadDefaultPrefs() {
|
||||
SharedPreferences settings = getPreferences(MODE_PRIVATE);
|
||||
String lastfn = settings.getString("lastFile", "");
|
||||
|
||||
if (lastfn == "") {
|
||||
lastfn = "/sdcard/keepass/keepass.kdb";
|
||||
}
|
||||
|
||||
setEditText(R.id.pass_filename, lastfn);
|
||||
}
|
||||
|
||||
private void saveDefaultPrefs() {
|
||||
SharedPreferences settings = getPreferences(MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = settings.edit();
|
||||
editor.putString("lastFile", getEditText(R.id.pass_filename));
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
private boolean fillData(String filename, String password) {
|
||||
FileInputStream fis;
|
||||
try {
|
||||
fis = new FileInputStream(filename);
|
||||
} catch (FileNotFoundException e) {
|
||||
errorMessage(R.string.FileNotFound);
|
||||
return false;
|
||||
}
|
||||
|
||||
ImporterV3 Importer = new ImporterV3();
|
||||
|
||||
try {
|
||||
mPM = Importer.openDatabase(fis, password);
|
||||
if ( mPM != null ) {
|
||||
mPM.constructTree(null);
|
||||
}
|
||||
} catch (InvalidCipherTextException e) {
|
||||
errorMessage(R.string.InvalidPassword);
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
errorMessage("IO Error");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private void errorMessage(CharSequence text)
|
||||
{
|
||||
Toast.makeText(this, text, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
private void errorMessage(int resId)
|
||||
{
|
||||
Toast.makeText(this, resId, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
gGroups.remove(requestCode);
|
||||
gEntries.remove(requestCode);
|
||||
}
|
||||
|
||||
private class ClickHandler implements View.OnClickListener {
|
||||
private Activity mAct;
|
||||
|
||||
ClickHandler(Activity act) {
|
||||
mAct = act;
|
||||
}
|
||||
|
||||
public void onClick(View view) {
|
||||
if ( fillData(getEditText(R.id.pass_filename),getEditText(R.id.pass_password)) ) {
|
||||
GroupActivity.Launch(mAct, mPM.getGrpRoots(), new Vector());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String getEditText(int resId) {
|
||||
EditText te = (EditText) findViewById(resId);
|
||||
assert(te == null);
|
||||
|
||||
if (te != null) {
|
||||
return te.getText().toString();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private void setEditText(int resId, String str) {
|
||||
EditText te = (EditText) findViewById(resId);
|
||||
assert(te == null);
|
||||
|
||||
if (te != null) {
|
||||
te.setText(str);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
50
src/com/android/keepass/PwEntryView.java
Normal file
50
src/com/android/keepass/PwEntryView.java
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 2009 Brian Pellin.
|
||||
*
|
||||
* This file is part of KeePassDroid.
|
||||
*
|
||||
* KeePassDroid is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePassDroid 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 KeePassDroid. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.android.keepass;
|
||||
|
||||
import org.phoneid.keepassj2me.PwEntry;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
public class PwEntryView extends PwItemView {
|
||||
|
||||
private Activity mAct;
|
||||
private PwEntry mPw;
|
||||
|
||||
public PwEntryView(Activity act, PwEntry pw) {
|
||||
super(act, pw.title);
|
||||
mAct = act;
|
||||
|
||||
mPw = pw;
|
||||
|
||||
}
|
||||
|
||||
public void setEntry(PwEntry pw) {
|
||||
super.setTitle(pw.title);
|
||||
|
||||
mPw = pw;
|
||||
}
|
||||
|
||||
@Override
|
||||
void onClick() {
|
||||
EntryActivity.Launch(mAct, mPw);
|
||||
|
||||
}
|
||||
}
|
51
src/com/android/keepass/PwGroupView.java
Normal file
51
src/com/android/keepass/PwGroupView.java
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright 2009 Brian Pellin.
|
||||
*
|
||||
* This file is part of KeePassDroid.
|
||||
*
|
||||
* KeePassDroid is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePassDroid 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 KeePassDroid. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.android.keepass;
|
||||
|
||||
import org.phoneid.keepassj2me.PwGroup;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
public class PwGroupView extends PwItemView {
|
||||
|
||||
private PwGroup mPw;
|
||||
private Activity mAct;
|
||||
|
||||
public PwGroupView(Activity act, PwGroup pw) {
|
||||
super(act, pw.name);
|
||||
mAct = act;
|
||||
mPw = pw;
|
||||
|
||||
}
|
||||
|
||||
public void setGroup(PwGroup pw) {
|
||||
super.setTitle(pw.name);
|
||||
|
||||
mPw = pw;
|
||||
}
|
||||
|
||||
@Override
|
||||
void onClick() {
|
||||
GroupActivity.Launch(mAct, mPw.childGroups, mPw.childEntries);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
42
src/com/android/keepass/PwItemView.java
Normal file
42
src/com/android/keepass/PwItemView.java
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2009 Brian Pellin.
|
||||
*
|
||||
* This file is part of KeePassDroid.
|
||||
*
|
||||
* KeePassDroid is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePassDroid 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 KeePassDroid. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.android.keepass;
|
||||
|
||||
import android.content.Context;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
abstract public class PwItemView extends LinearLayout {
|
||||
private TextView mTitle;
|
||||
|
||||
PwItemView(Context context, String title) {
|
||||
super(context);
|
||||
|
||||
mTitle = new TextView(context);
|
||||
mTitle.setText(title);
|
||||
addView(mTitle, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT));
|
||||
}
|
||||
|
||||
void setTitle(String title) {
|
||||
mTitle.setText(title);
|
||||
}
|
||||
|
||||
abstract void onClick();
|
||||
}
|
95
src/com/android/keepass/PwListAdapter.java
Normal file
95
src/com/android/keepass/PwListAdapter.java
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright 2009 Brian Pellin.
|
||||
*
|
||||
* This file is part of KeePassDroid.
|
||||
*
|
||||
* KeePassDroid is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePassDroid 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 KeePassDroid. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.android.keepass;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
|
||||
import org.phoneid.keepassj2me.PwEntry;
|
||||
import org.phoneid.keepassj2me.PwGroup;
|
||||
|
||||
public class PwListAdapter extends BaseAdapter {
|
||||
|
||||
private Activity mAct;
|
||||
private Vector mGroupList;
|
||||
private Vector mEntryList;
|
||||
|
||||
PwListAdapter(Activity act, Vector gl, Vector el) {
|
||||
mAct = act;
|
||||
mGroupList = gl;
|
||||
mEntryList = el;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
|
||||
return mGroupList.size() + mEntryList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
int size = mGroupList.size();
|
||||
|
||||
if ( position < size ) {
|
||||
return createGroupView(position, convertView);
|
||||
} else {
|
||||
return createEntryView(position - size, convertView);
|
||||
}
|
||||
}
|
||||
|
||||
private PwGroupView createGroupView(int position, View convertView) {
|
||||
PwGroupView gv;
|
||||
if (convertView == null || ! (convertView instanceof PwGroupView)) {
|
||||
PwGroup group = (PwGroup) mGroupList.elementAt(position);
|
||||
gv = new PwGroupView(mAct, group);
|
||||
} else {
|
||||
gv = (PwGroupView) convertView;
|
||||
gv.setGroup((PwGroup) mGroupList.elementAt(position));
|
||||
}
|
||||
return gv;
|
||||
}
|
||||
|
||||
private PwEntryView createEntryView(int position, View convertView) {
|
||||
PwEntryView ev;
|
||||
if (convertView == null || ! (convertView instanceof PwEntryView) ) {
|
||||
ev = new PwEntryView(mAct, (PwEntry) mEntryList.elementAt(position));
|
||||
} else {
|
||||
ev = (PwEntryView) convertView;
|
||||
ev.setEntry((PwEntry) mEntryList.elementAt(position));
|
||||
}
|
||||
return ev;
|
||||
}
|
||||
|
||||
}
|
52
src/com/android/keepass/R.java
Normal file
52
src/com/android/keepass/R.java
Normal file
|
@ -0,0 +1,52 @@
|
|||
/* AUTO-GENERATED FILE. DO NOT MODIFY.
|
||||
*
|
||||
* This class was automatically generated by the
|
||||
* aapt tool from the resource data it found. It
|
||||
* should not be modified by hand.
|
||||
*/
|
||||
|
||||
package com.android.keepass;
|
||||
|
||||
public final class R {
|
||||
public static final class attr {
|
||||
}
|
||||
public static final class drawable {
|
||||
public static final int keepass_icon=0x7f020000;
|
||||
}
|
||||
public static final class id {
|
||||
public static final int entry_comment=0x7f050004;
|
||||
public static final int entry_password=0x7f050003;
|
||||
public static final int entry_title=0x7f050000;
|
||||
public static final int entry_url=0x7f050002;
|
||||
public static final int entry_user_name=0x7f050001;
|
||||
public static final int pass_filename=0x7f050005;
|
||||
public static final int pass_ok=0x7f050007;
|
||||
public static final int pass_password=0x7f050006;
|
||||
public static final int text1=0x7f050008;
|
||||
}
|
||||
public static final class layout {
|
||||
public static final int entry_view=0x7f030000;
|
||||
public static final int list=0x7f030001;
|
||||
public static final int password=0x7f030002;
|
||||
public static final int row=0x7f030003;
|
||||
}
|
||||
public static final class string {
|
||||
public static final int FileNotFound=0x7f040002;
|
||||
public static final int InvalidPassword=0x7f040003;
|
||||
public static final int MaskedPassword=0x7f04000a;
|
||||
public static final int app_name=0x7f040000;
|
||||
public static final int entry_comment=0x7f040009;
|
||||
public static final int entry_password=0x7f040008;
|
||||
public static final int entry_title=0x7f040005;
|
||||
public static final int entry_url=0x7f040007;
|
||||
public static final int entry_user_name=0x7f040006;
|
||||
public static final int menu_copy_pass=0x7f04000f;
|
||||
public static final int menu_copy_url=0x7f04000d;
|
||||
public static final int menu_copy_user=0x7f04000e;
|
||||
public static final int menu_hide_password=0x7f04000c;
|
||||
public static final int menu_show_password=0x7f04000b;
|
||||
public static final int no_keys=0x7f040001;
|
||||
public static final int pass_filename=0x7f040010;
|
||||
public static final int pass_ok=0x7f040004;
|
||||
}
|
||||
}
|
56
src/org/bouncycastle1/crypto/BlockCipher.java
Normal file
56
src/org/bouncycastle1/crypto/BlockCipher.java
Normal file
|
@ -0,0 +1,56 @@
|
|||
package org.bouncycastle1.crypto;
|
||||
|
||||
|
||||
/**
|
||||
* Block cipher engines are expected to conform to this interface.
|
||||
*/
|
||||
public interface BlockCipher
|
||||
{
|
||||
/**
|
||||
* Initialise the cipher.
|
||||
*
|
||||
* @param forEncryption if true the cipher is initialised for
|
||||
* encryption, if false for decryption.
|
||||
* @param params the key and other data required by the cipher.
|
||||
* @exception IllegalArgumentException if the params argument is
|
||||
* inappropriate.
|
||||
*/
|
||||
public void init(boolean forEncryption, CipherParameters params)
|
||||
throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Return the name of the algorithm the cipher implements.
|
||||
*
|
||||
* @return the name of the algorithm the cipher implements.
|
||||
*/
|
||||
public String getAlgorithmName();
|
||||
|
||||
/**
|
||||
* Return the block size for this cipher (in bytes).
|
||||
*
|
||||
* @return the block size for this cipher in bytes.
|
||||
*/
|
||||
public int getBlockSize();
|
||||
|
||||
/**
|
||||
* Process one block of input from the array in and write it to
|
||||
* the out array.
|
||||
*
|
||||
* @param in the array containing the input data.
|
||||
* @param inOff offset into the in array the data starts at.
|
||||
* @param out the array the output data will be copied into.
|
||||
* @param outOff the offset into the out array the output will start at.
|
||||
* @exception DataLengthException if there isn't enough data in in, or
|
||||
* space in out.
|
||||
* @exception IllegalStateException if the cipher isn't initialised.
|
||||
* @return the number of bytes processed and produced.
|
||||
*/
|
||||
public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
|
||||
throws DataLengthException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Reset the cipher. After resetting the cipher is in the same state
|
||||
* as it was after the last init (if there was one).
|
||||
*/
|
||||
public void reset();
|
||||
}
|
322
src/org/bouncycastle1/crypto/BufferedBlockCipher.java
Normal file
322
src/org/bouncycastle1/crypto/BufferedBlockCipher.java
Normal file
|
@ -0,0 +1,322 @@
|
|||
package org.bouncycastle1.crypto;
|
||||
|
||||
|
||||
/**
|
||||
* A wrapper class that allows block ciphers to be used to process data in
|
||||
* a piecemeal fashion. The BufferedBlockCipher outputs a block only when the
|
||||
* buffer is full and more data is being added, or on a doFinal.
|
||||
* <p>
|
||||
* Note: in the case where the underlying cipher is either a CFB cipher or an
|
||||
* OFB one the last block may not be a multiple of the block size.
|
||||
*/
|
||||
public class BufferedBlockCipher
|
||||
{
|
||||
protected byte[] buf;
|
||||
protected int bufOff;
|
||||
|
||||
protected boolean forEncryption;
|
||||
protected BlockCipher cipher;
|
||||
|
||||
protected boolean partialBlockOkay;
|
||||
protected boolean pgpCFB;
|
||||
|
||||
/**
|
||||
* constructor for subclasses
|
||||
*/
|
||||
protected BufferedBlockCipher()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a buffered block cipher without padding.
|
||||
*
|
||||
* @param cipher the underlying block cipher this buffering object wraps.
|
||||
*/
|
||||
public BufferedBlockCipher(
|
||||
BlockCipher cipher)
|
||||
{
|
||||
this.cipher = cipher;
|
||||
|
||||
buf = new byte[cipher.getBlockSize()];
|
||||
bufOff = 0;
|
||||
|
||||
//
|
||||
// check if we can handle partial blocks on doFinal.
|
||||
//
|
||||
String name = cipher.getAlgorithmName();
|
||||
int idx = name.indexOf('/') + 1;
|
||||
|
||||
pgpCFB = (idx > 0 && name.startsWith("PGP", idx));
|
||||
|
||||
if (pgpCFB)
|
||||
{
|
||||
partialBlockOkay = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
partialBlockOkay = (idx > 0 && (name.startsWith("CFB", idx) || name.startsWith("OFB", idx) || name.startsWith("OpenPGP", idx) || name.startsWith("SIC", idx) || name.startsWith("GCTR", idx)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return the cipher this object wraps.
|
||||
*
|
||||
* @return the cipher this object wraps.
|
||||
*/
|
||||
public BlockCipher getUnderlyingCipher()
|
||||
{
|
||||
return cipher;
|
||||
}
|
||||
|
||||
/**
|
||||
* initialise the cipher.
|
||||
*
|
||||
* @param forEncryption if true the cipher is initialised for
|
||||
* encryption, if false for decryption.
|
||||
* @param params the key and other data required by the cipher.
|
||||
* @exception IllegalArgumentException if the params argument is
|
||||
* inappropriate.
|
||||
*/
|
||||
public void init(
|
||||
boolean forEncryption,
|
||||
CipherParameters params)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
this.forEncryption = forEncryption;
|
||||
|
||||
reset();
|
||||
|
||||
cipher.init(forEncryption, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the blocksize for the underlying cipher.
|
||||
*
|
||||
* @return the blocksize for the underlying cipher.
|
||||
*/
|
||||
public int getBlockSize()
|
||||
{
|
||||
return cipher.getBlockSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* return the size of the output buffer required for an update
|
||||
* an input of len bytes.
|
||||
*
|
||||
* @param len the length of the input.
|
||||
* @return the space required to accommodate a call to update
|
||||
* with len bytes of input.
|
||||
*/
|
||||
public int getUpdateOutputSize(
|
||||
int len)
|
||||
{
|
||||
int total = len + bufOff;
|
||||
int leftOver;
|
||||
|
||||
if (pgpCFB)
|
||||
{
|
||||
leftOver = total % buf.length - (cipher.getBlockSize() + 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
leftOver = total % buf.length;
|
||||
}
|
||||
|
||||
return total - leftOver;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the size of the output buffer required for an update plus a
|
||||
* doFinal with an input of len bytes.
|
||||
*
|
||||
* @param len the length of the input.
|
||||
* @return the space required to accommodate a call to update and doFinal
|
||||
* with len bytes of input.
|
||||
*/
|
||||
public int getOutputSize(
|
||||
int len)
|
||||
{
|
||||
int total = len + bufOff;
|
||||
int leftOver;
|
||||
|
||||
if (pgpCFB)
|
||||
{
|
||||
leftOver = total % buf.length - (cipher.getBlockSize() + 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
leftOver = total % buf.length;
|
||||
if (leftOver == 0)
|
||||
{
|
||||
return total;
|
||||
}
|
||||
}
|
||||
|
||||
return total - leftOver + buf.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* process a single byte, producing an output block if neccessary.
|
||||
*
|
||||
* @param in the input byte.
|
||||
* @param out the space for any output that might be produced.
|
||||
* @param outOff the offset from which the output will be copied.
|
||||
* @return the number of output bytes copied to out.
|
||||
* @exception DataLengthException if there isn't enough space in out.
|
||||
* @exception IllegalStateException if the cipher isn't initialised.
|
||||
*/
|
||||
public int processByte(
|
||||
byte in,
|
||||
byte[] out,
|
||||
int outOff)
|
||||
throws DataLengthException, IllegalStateException
|
||||
{
|
||||
int resultLen = 0;
|
||||
|
||||
buf[bufOff++] = in;
|
||||
|
||||
if (bufOff == buf.length)
|
||||
{
|
||||
resultLen = cipher.processBlock(buf, 0, out, outOff);
|
||||
bufOff = 0;
|
||||
}
|
||||
|
||||
return resultLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* process an array of bytes, producing output if necessary.
|
||||
*
|
||||
* @param in the input byte array.
|
||||
* @param inOff the offset at which the input data starts.
|
||||
* @param len the number of bytes to be copied out of the input array.
|
||||
* @param out the space for any output that might be produced.
|
||||
* @param outOff the offset from which the output will be copied.
|
||||
* @return the number of output bytes copied to out.
|
||||
* @exception DataLengthException if there isn't enough space in out.
|
||||
* @exception IllegalStateException if the cipher isn't initialised.
|
||||
*/
|
||||
public int processBytes(
|
||||
byte[] in,
|
||||
int inOff,
|
||||
int len,
|
||||
byte[] out,
|
||||
int outOff)
|
||||
throws DataLengthException, IllegalStateException
|
||||
{
|
||||
if (len < 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Can't have a negative input length!");
|
||||
}
|
||||
|
||||
int blockSize = getBlockSize();
|
||||
int length = getUpdateOutputSize(len);
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
if ((outOff + length) > out.length)
|
||||
{
|
||||
throw new DataLengthException("output buffer too short");
|
||||
}
|
||||
}
|
||||
|
||||
int resultLen = 0;
|
||||
int gapLen = buf.length - bufOff;
|
||||
|
||||
if (len > gapLen)
|
||||
{
|
||||
System.arraycopy(in, inOff, buf, bufOff, gapLen);
|
||||
|
||||
resultLen += cipher.processBlock(buf, 0, out, outOff);
|
||||
|
||||
bufOff = 0;
|
||||
len -= gapLen;
|
||||
inOff += gapLen;
|
||||
|
||||
while (len > buf.length)
|
||||
{
|
||||
resultLen += cipher.processBlock(in, inOff, out, outOff + resultLen);
|
||||
|
||||
len -= blockSize;
|
||||
inOff += blockSize;
|
||||
}
|
||||
}
|
||||
|
||||
System.arraycopy(in, inOff, buf, bufOff, len);
|
||||
|
||||
bufOff += len;
|
||||
|
||||
if (bufOff == buf.length)
|
||||
{
|
||||
resultLen += cipher.processBlock(buf, 0, out, outOff + resultLen);
|
||||
bufOff = 0;
|
||||
}
|
||||
|
||||
return resultLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the last block in the buffer.
|
||||
*
|
||||
* @param out the array the block currently being held is copied into.
|
||||
* @param outOff the offset at which the copying starts.
|
||||
* @return the number of output bytes copied to out.
|
||||
* @exception DataLengthException if there is insufficient space in out for
|
||||
* the output, or the input is not block size aligned and should be.
|
||||
* @exception IllegalStateException if the underlying cipher is not
|
||||
* initialised.
|
||||
* @exception InvalidCipherTextException if padding is expected and not found.
|
||||
* @exception DataLengthException if the input is not block size
|
||||
* aligned.
|
||||
*/
|
||||
public int doFinal(
|
||||
byte[] out,
|
||||
int outOff)
|
||||
throws DataLengthException, IllegalStateException, InvalidCipherTextException
|
||||
{
|
||||
int resultLen = 0;
|
||||
|
||||
if (outOff + bufOff > out.length)
|
||||
{
|
||||
throw new DataLengthException("output buffer too short for doFinal()");
|
||||
}
|
||||
|
||||
if (bufOff != 0 && partialBlockOkay)
|
||||
{
|
||||
cipher.processBlock(buf, 0, buf, 0);
|
||||
resultLen = bufOff;
|
||||
bufOff = 0;
|
||||
System.arraycopy(buf, 0, out, outOff, resultLen);
|
||||
}
|
||||
else if (bufOff != 0)
|
||||
{
|
||||
throw new DataLengthException("data not block size aligned");
|
||||
}
|
||||
|
||||
reset();
|
||||
|
||||
return resultLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the buffer and cipher. After resetting the object is in the same
|
||||
* state as it was after the last init (if there was one).
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
//
|
||||
// clean the buffer.
|
||||
//
|
||||
for (int i = 0; i < buf.length; i++)
|
||||
{
|
||||
buf[i] = 0;
|
||||
}
|
||||
|
||||
bufOff = 0;
|
||||
|
||||
//
|
||||
// reset the underlying cipher.
|
||||
//
|
||||
cipher.reset();
|
||||
}
|
||||
}
|
8
src/org/bouncycastle1/crypto/CipherParameters.java
Normal file
8
src/org/bouncycastle1/crypto/CipherParameters.java
Normal file
|
@ -0,0 +1,8 @@
|
|||
package org.bouncycastle1.crypto;
|
||||
|
||||
/**
|
||||
* all parameter classes implement this.
|
||||
*/
|
||||
public interface CipherParameters
|
||||
{
|
||||
}
|
26
src/org/bouncycastle1/crypto/CryptoException.java
Normal file
26
src/org/bouncycastle1/crypto/CryptoException.java
Normal file
|
@ -0,0 +1,26 @@
|
|||
package org.bouncycastle1.crypto;
|
||||
|
||||
/**
|
||||
* the foundation class for the hard exceptions thrown by the crypto packages.
|
||||
*/
|
||||
public class CryptoException
|
||||
extends Exception
|
||||
{
|
||||
/**
|
||||
* base constructor.
|
||||
*/
|
||||
public CryptoException()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* create a CryptoException with the given message.
|
||||
*
|
||||
* @param message the message to be carried with the exception.
|
||||
*/
|
||||
public CryptoException(
|
||||
String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
}
|
29
src/org/bouncycastle1/crypto/DataLengthException.java
Normal file
29
src/org/bouncycastle1/crypto/DataLengthException.java
Normal file
|
@ -0,0 +1,29 @@
|
|||
package org.bouncycastle1.crypto;
|
||||
|
||||
/**
|
||||
* this exception is thrown if a buffer that is meant to have output
|
||||
* copied into it turns out to be too short, or if we've been given
|
||||
* insufficient input. In general this exception will get thrown rather
|
||||
* than an ArrayOutOfBounds exception.
|
||||
*/
|
||||
public class DataLengthException
|
||||
extends RuntimeCryptoException
|
||||
{
|
||||
/**
|
||||
* base constructor.
|
||||
*/
|
||||
public DataLengthException()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* create a DataLengthException with the given message.
|
||||
*
|
||||
* @param message the message to be carried with the exception.
|
||||
*/
|
||||
public DataLengthException(
|
||||
String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
}
|
51
src/org/bouncycastle1/crypto/Digest.java
Normal file
51
src/org/bouncycastle1/crypto/Digest.java
Normal file
|
@ -0,0 +1,51 @@
|
|||
package org.bouncycastle1.crypto;
|
||||
|
||||
/**
|
||||
* interface that a message digest conforms to.
|
||||
*/
|
||||
public interface Digest
|
||||
{
|
||||
/**
|
||||
* return the algorithm name
|
||||
*
|
||||
* @return the algorithm name
|
||||
*/
|
||||
public String getAlgorithmName();
|
||||
|
||||
/**
|
||||
* return the size, in bytes, of the digest produced by this message digest.
|
||||
*
|
||||
* @return the size, in bytes, of the digest produced by this message digest.
|
||||
*/
|
||||
public int getDigestSize();
|
||||
|
||||
/**
|
||||
* update the message digest with a single byte.
|
||||
*
|
||||
* @param in the input byte to be entered.
|
||||
*/
|
||||
public void update(byte in);
|
||||
|
||||
/**
|
||||
* update the message digest with a block of bytes.
|
||||
*
|
||||
* @param in the byte array containing the data.
|
||||
* @param inOff the offset into the byte array where the data starts.
|
||||
* @param len the length of the data.
|
||||
*/
|
||||
public void update(byte[] in, int inOff, int len);
|
||||
|
||||
/**
|
||||
* close the digest, producing the final digest value. The doFinal
|
||||
* call leaves the digest reset.
|
||||
*
|
||||
* @param out the array the digest is to be copied into.
|
||||
* @param outOff the offset into the out array the digest is to start at.
|
||||
*/
|
||||
public int doFinal(byte[] out, int outOff);
|
||||
|
||||
/**
|
||||
* reset the digest back to it's initial state.
|
||||
*/
|
||||
public void reset();
|
||||
}
|
13
src/org/bouncycastle1/crypto/ExtendedDigest.java
Normal file
13
src/org/bouncycastle1/crypto/ExtendedDigest.java
Normal file
|
@ -0,0 +1,13 @@
|
|||
package org.bouncycastle1.crypto;
|
||||
|
||||
public interface ExtendedDigest
|
||||
extends Digest
|
||||
{
|
||||
/**
|
||||
* Return the size in bytes of the internal buffer the digest applies it's compression
|
||||
* function to.
|
||||
*
|
||||
* @return byte length of the digests internal buffer.
|
||||
*/
|
||||
public int getByteLength();
|
||||
}
|
27
src/org/bouncycastle1/crypto/InvalidCipherTextException.java
Normal file
27
src/org/bouncycastle1/crypto/InvalidCipherTextException.java
Normal file
|
@ -0,0 +1,27 @@
|
|||
package org.bouncycastle1.crypto;
|
||||
|
||||
/**
|
||||
* this exception is thrown whenever we find something we don't expect in a
|
||||
* message.
|
||||
*/
|
||||
public class InvalidCipherTextException
|
||||
extends CryptoException
|
||||
{
|
||||
/**
|
||||
* base constructor.
|
||||
*/
|
||||
public InvalidCipherTextException()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* create a InvalidCipherTextException with the given message.
|
||||
*
|
||||
* @param message the message to be carried with the exception.
|
||||
*/
|
||||
public InvalidCipherTextException(
|
||||
String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
}
|
71
src/org/bouncycastle1/crypto/Mac.java
Normal file
71
src/org/bouncycastle1/crypto/Mac.java
Normal file
|
@ -0,0 +1,71 @@
|
|||
package org.bouncycastle1.crypto;
|
||||
|
||||
|
||||
/**
|
||||
* The base interface for implementations of message authentication codes (MACs).
|
||||
*/
|
||||
public interface Mac
|
||||
{
|
||||
/**
|
||||
* Initialise the MAC.
|
||||
*
|
||||
* @param params the key and other data required by the MAC.
|
||||
* @exception IllegalArgumentException if the params argument is
|
||||
* inappropriate.
|
||||
*/
|
||||
public void init(CipherParameters params)
|
||||
throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Return the name of the algorithm the MAC implements.
|
||||
*
|
||||
* @return the name of the algorithm the MAC implements.
|
||||
*/
|
||||
public String getAlgorithmName();
|
||||
|
||||
/**
|
||||
* Return the block size for this MAC (in bytes).
|
||||
*
|
||||
* @return the block size for this MAC in bytes.
|
||||
*/
|
||||
public int getMacSize();
|
||||
|
||||
/**
|
||||
* add a single byte to the mac for processing.
|
||||
*
|
||||
* @param in the byte to be processed.
|
||||
* @exception IllegalStateException if the MAC is not initialised.
|
||||
*/
|
||||
public void update(byte in)
|
||||
throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* @param in the array containing the input.
|
||||
* @param inOff the index in the array the data begins at.
|
||||
* @param len the length of the input starting at inOff.
|
||||
* @exception IllegalStateException if the MAC is not initialised.
|
||||
* @exception DataLengthException if there isn't enough data in in.
|
||||
*/
|
||||
public void update(byte[] in, int inOff, int len)
|
||||
throws DataLengthException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Compute the final statge of the MAC writing the output to the out
|
||||
* parameter.
|
||||
* <p>
|
||||
* doFinal leaves the MAC in the same state it was after the last init.
|
||||
*
|
||||
* @param out the array the MAC is to be output to.
|
||||
* @param outOff the offset into the out buffer the output is to start at.
|
||||
* @exception DataLengthException if there isn't enough space in out.
|
||||
* @exception IllegalStateException if the MAC is not initialised.
|
||||
*/
|
||||
public int doFinal(byte[] out, int outOff)
|
||||
throws DataLengthException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Reset the MAC. At the end of resetting the MAC should be in the
|
||||
* in the same state it was after the last init (if there was one).
|
||||
*/
|
||||
public void reset();
|
||||
}
|
142
src/org/bouncycastle1/crypto/PBEParametersGenerator.java
Normal file
142
src/org/bouncycastle1/crypto/PBEParametersGenerator.java
Normal file
|
@ -0,0 +1,142 @@
|
|||
package org.bouncycastle1.crypto;
|
||||
|
||||
/**
|
||||
* super class for all Password Based Encryption (PBE) parameter generator classes.
|
||||
*/
|
||||
public abstract class PBEParametersGenerator
|
||||
{
|
||||
protected byte[] password;
|
||||
protected byte[] salt;
|
||||
protected int iterationCount;
|
||||
|
||||
/**
|
||||
* base constructor.
|
||||
*/
|
||||
protected PBEParametersGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* initialise the PBE generator.
|
||||
*
|
||||
* @param password the password converted into bytes (see below).
|
||||
* @param salt the salt to be mixed with the password.
|
||||
* @param iterationCount the number of iterations the "mixing" function
|
||||
* is to be applied for.
|
||||
*/
|
||||
public void init(
|
||||
byte[] password,
|
||||
byte[] salt,
|
||||
int iterationCount)
|
||||
{
|
||||
this.password = password;
|
||||
this.salt = salt;
|
||||
this.iterationCount = iterationCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the password byte array.
|
||||
*
|
||||
* @return the password byte array.
|
||||
*/
|
||||
public byte[] getPassword()
|
||||
{
|
||||
return password;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the salt byte array.
|
||||
*
|
||||
* @return the salt byte array.
|
||||
*/
|
||||
public byte[] getSalt()
|
||||
{
|
||||
return salt;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the iteration count.
|
||||
*
|
||||
* @return the iteration count.
|
||||
*/
|
||||
public int getIterationCount()
|
||||
{
|
||||
return iterationCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* generate derived parameters for a key of length keySize.
|
||||
*
|
||||
* @param keySize the length, in bits, of the key required.
|
||||
* @return a parameters object representing a key.
|
||||
*/
|
||||
public abstract CipherParameters generateDerivedParameters(int keySize);
|
||||
|
||||
/**
|
||||
* generate derived parameters for a key of length keySize, and
|
||||
* an initialisation vector (IV) of length ivSize.
|
||||
*
|
||||
* @param keySize the length, in bits, of the key required.
|
||||
* @param ivSize the length, in bits, of the iv required.
|
||||
* @return a parameters object representing a key and an IV.
|
||||
*/
|
||||
public abstract CipherParameters generateDerivedParameters(int keySize, int ivSize);
|
||||
|
||||
/**
|
||||
* generate derived parameters for a key of length keySize, specifically
|
||||
* for use with a MAC.
|
||||
*
|
||||
* @param keySize the length, in bits, of the key required.
|
||||
* @return a parameters object representing a key.
|
||||
*/
|
||||
public abstract CipherParameters generateDerivedMacParameters(int keySize);
|
||||
|
||||
/**
|
||||
* converts a password to a byte array according to the scheme in
|
||||
* PKCS5 (ascii, no padding)
|
||||
*
|
||||
* @param password a character array reqpresenting the password.
|
||||
* @return a byte array representing the password.
|
||||
*/
|
||||
public static byte[] PKCS5PasswordToBytes(
|
||||
char[] password)
|
||||
{
|
||||
byte[] bytes = new byte[password.length];
|
||||
|
||||
for (int i = 0; i != bytes.length; i++)
|
||||
{
|
||||
bytes[i] = (byte)password[i];
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* converts a password to a byte array according to the scheme in
|
||||
* PKCS12 (unicode, big endian, 2 zero pad bytes at the end).
|
||||
*
|
||||
* @param password a character array reqpresenting the password.
|
||||
* @return a byte array representing the password.
|
||||
*/
|
||||
public static byte[] PKCS12PasswordToBytes(
|
||||
char[] password)
|
||||
{
|
||||
if (password.length > 0)
|
||||
{
|
||||
// +1 for extra 2 pad bytes.
|
||||
byte[] bytes = new byte[(password.length + 1) * 2];
|
||||
|
||||
for (int i = 0; i != password.length; i ++)
|
||||
{
|
||||
bytes[i * 2] = (byte)(password[i] >>> 8);
|
||||
bytes[i * 2 + 1] = (byte)password[i];
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
}
|
26
src/org/bouncycastle1/crypto/RuntimeCryptoException.java
Normal file
26
src/org/bouncycastle1/crypto/RuntimeCryptoException.java
Normal file
|
@ -0,0 +1,26 @@
|
|||
package org.bouncycastle1.crypto;
|
||||
|
||||
/**
|
||||
* the foundation class for the exceptions thrown by the crypto packages.
|
||||
*/
|
||||
public class RuntimeCryptoException
|
||||
extends RuntimeException
|
||||
{
|
||||
/**
|
||||
* base constructor.
|
||||
*/
|
||||
public RuntimeCryptoException()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* create a RuntimeCryptoException with the given message.
|
||||
*
|
||||
* @param message the message to be carried with the exception.
|
||||
*/
|
||||
public RuntimeCryptoException(
|
||||
String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
}
|
138
src/org/bouncycastle1/crypto/SecureRandom.java
Normal file
138
src/org/bouncycastle1/crypto/SecureRandom.java
Normal file
|
@ -0,0 +1,138 @@
|
|||
//package java.security;
|
||||
package org.bouncycastle1.crypto;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import org.bouncycastle1.crypto.digests.SHA1Digest;
|
||||
import org.bouncycastle1.crypto.digests.SHA256Digest;
|
||||
import org.bouncycastle1.crypto.prng.RandomGenerator;
|
||||
import org.bouncycastle1.crypto.prng.DigestRandomGenerator;
|
||||
|
||||
/**
|
||||
* An implementation of SecureRandom specifically for the light-weight API, JDK
|
||||
* 1.0, and the J2ME. Random generation is based on the traditional SHA1 with
|
||||
* counter. Calling setSeed will always increase the entropy of the hash.
|
||||
*/
|
||||
public class SecureRandom extends java.util.Random
|
||||
{
|
||||
private static SecureRandom rand = new SecureRandom(new DigestRandomGenerator(new SHA1Digest()));
|
||||
|
||||
protected RandomGenerator generator;
|
||||
|
||||
// public constructors
|
||||
public SecureRandom()
|
||||
{
|
||||
super(0);
|
||||
this.generator = new DigestRandomGenerator(new SHA1Digest());
|
||||
setSeed(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public SecureRandom(byte[] inSeed)
|
||||
{
|
||||
super(0);
|
||||
this.generator = new DigestRandomGenerator(new SHA1Digest());
|
||||
setSeed(inSeed);
|
||||
}
|
||||
|
||||
protected SecureRandom(
|
||||
RandomGenerator generator)
|
||||
{
|
||||
super(0);
|
||||
this.generator = generator;
|
||||
}
|
||||
|
||||
// protected constructors
|
||||
// protected SecureRandom(SecureRandomSpi srs, Provider provider);
|
||||
|
||||
// public class methods
|
||||
public static SecureRandom getInstance(String algorithm)
|
||||
{
|
||||
if (algorithm.equals("SHA1PRNG"))
|
||||
{
|
||||
return new SecureRandom(new DigestRandomGenerator(new SHA1Digest()));
|
||||
}
|
||||
if (algorithm.equals("SHA256PRNG"))
|
||||
{
|
||||
return new SecureRandom(new DigestRandomGenerator(new SHA256Digest()));
|
||||
}
|
||||
return new SecureRandom(); // follow old behaviour
|
||||
}
|
||||
|
||||
public static SecureRandom getInstance(String algorithm, String provider)
|
||||
{
|
||||
return getInstance(algorithm);
|
||||
}
|
||||
|
||||
public static byte[] getSeed(int numBytes)
|
||||
{
|
||||
byte[] rv = new byte[numBytes];
|
||||
|
||||
rand.setSeed(System.currentTimeMillis());
|
||||
rand.nextBytes(rv);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
// public instance methods
|
||||
public byte[] generateSeed(int numBytes)
|
||||
{
|
||||
byte[] rv = new byte[numBytes];
|
||||
|
||||
nextBytes(rv);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
// public final Provider getProvider();
|
||||
public void setSeed(byte[] inSeed)
|
||||
{
|
||||
generator.addSeedMaterial(inSeed);
|
||||
}
|
||||
|
||||
// public methods overriding random
|
||||
public void nextBytes(byte[] bytes)
|
||||
{
|
||||
generator.nextBytes(bytes);
|
||||
}
|
||||
|
||||
public void setSeed(long rSeed)
|
||||
{
|
||||
if (rSeed != 0) // to avoid problems with Random calling setSeed in construction
|
||||
{
|
||||
generator.addSeedMaterial(rSeed);
|
||||
}
|
||||
}
|
||||
|
||||
public int nextInt()
|
||||
{
|
||||
byte[] intBytes = new byte[4];
|
||||
|
||||
nextBytes(intBytes);
|
||||
|
||||
int result = 0;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
result = (result << 8) + (intBytes[i] & 0xff);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected final int next(int numBits)
|
||||
{
|
||||
int size = (numBits + 7) / 8;
|
||||
byte[] bytes = new byte[size];
|
||||
|
||||
nextBytes(bytes);
|
||||
|
||||
int result = 0;
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
result = (result << 8) + (bytes[i] & 0xff);
|
||||
}
|
||||
|
||||
return result & ((1 << numBits) - 1);
|
||||
}
|
||||
}
|
135
src/org/bouncycastle1/crypto/digests/GeneralDigest.java
Normal file
135
src/org/bouncycastle1/crypto/digests/GeneralDigest.java
Normal file
|
@ -0,0 +1,135 @@
|
|||
package org.bouncycastle1.crypto.digests;
|
||||
|
||||
import org.bouncycastle1.crypto.ExtendedDigest;
|
||||
|
||||
/**
|
||||
* base implementation of MD4 family style digest as outlined in
|
||||
* "Handbook of Applied Cryptography", pages 344 - 347.
|
||||
*/
|
||||
public abstract class GeneralDigest
|
||||
implements ExtendedDigest
|
||||
{
|
||||
private static final int BYTE_LENGTH = 64;
|
||||
private byte[] xBuf;
|
||||
private int xBufOff;
|
||||
|
||||
private long byteCount;
|
||||
|
||||
/**
|
||||
* Standard constructor
|
||||
*/
|
||||
protected GeneralDigest()
|
||||
{
|
||||
xBuf = new byte[4];
|
||||
xBufOff = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor. We are using copy constructors in place
|
||||
* of the Object.clone() interface as this interface is not
|
||||
* supported by J2ME.
|
||||
*/
|
||||
protected GeneralDigest(GeneralDigest t)
|
||||
{
|
||||
xBuf = new byte[t.xBuf.length];
|
||||
System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length);
|
||||
|
||||
xBufOff = t.xBufOff;
|
||||
byteCount = t.byteCount;
|
||||
}
|
||||
|
||||
public void update(
|
||||
byte in)
|
||||
{
|
||||
xBuf[xBufOff++] = in;
|
||||
|
||||
if (xBufOff == xBuf.length)
|
||||
{
|
||||
processWord(xBuf, 0);
|
||||
xBufOff = 0;
|
||||
}
|
||||
|
||||
byteCount++;
|
||||
}
|
||||
|
||||
public void update(
|
||||
byte[] in,
|
||||
int inOff,
|
||||
int len)
|
||||
{
|
||||
//
|
||||
// fill the current word
|
||||
//
|
||||
while ((xBufOff != 0) && (len > 0))
|
||||
{
|
||||
update(in[inOff]);
|
||||
|
||||
inOff++;
|
||||
len--;
|
||||
}
|
||||
|
||||
//
|
||||
// process whole words.
|
||||
//
|
||||
while (len > xBuf.length)
|
||||
{
|
||||
processWord(in, inOff);
|
||||
|
||||
inOff += xBuf.length;
|
||||
len -= xBuf.length;
|
||||
byteCount += xBuf.length;
|
||||
}
|
||||
|
||||
//
|
||||
// load in the remainder.
|
||||
//
|
||||
while (len > 0)
|
||||
{
|
||||
update(in[inOff]);
|
||||
|
||||
inOff++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
public void finish()
|
||||
{
|
||||
long bitLength = (byteCount << 3);
|
||||
|
||||
//
|
||||
// add the pad bytes.
|
||||
//
|
||||
update((byte)128);
|
||||
|
||||
while (xBufOff != 0)
|
||||
{
|
||||
update((byte)0);
|
||||
}
|
||||
|
||||
processLength(bitLength);
|
||||
|
||||
processBlock();
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
byteCount = 0;
|
||||
|
||||
xBufOff = 0;
|
||||
for (int i = 0; i < xBuf.length; i++)
|
||||
{
|
||||
xBuf[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int getByteLength()
|
||||
{
|
||||
return BYTE_LENGTH;
|
||||
}
|
||||
|
||||
protected abstract void processWord(byte[] in, int inOff);
|
||||
|
||||
protected abstract void processLength(long bitLength);
|
||||
|
||||
protected abstract void processBlock();
|
||||
}
|
375
src/org/bouncycastle1/crypto/digests/LongDigest.java
Normal file
375
src/org/bouncycastle1/crypto/digests/LongDigest.java
Normal file
|
@ -0,0 +1,375 @@
|
|||
package org.bouncycastle1.crypto.digests;
|
||||
|
||||
import org.bouncycastle1.crypto.ExtendedDigest;
|
||||
|
||||
/**
|
||||
* Base class for SHA-384 and SHA-512.
|
||||
*/
|
||||
public abstract class LongDigest
|
||||
implements ExtendedDigest
|
||||
{
|
||||
private static final int BYTE_LENGTH = 128;
|
||||
|
||||
private byte[] xBuf;
|
||||
private int xBufOff;
|
||||
|
||||
private long byteCount1;
|
||||
private long byteCount2;
|
||||
|
||||
protected long H1, H2, H3, H4, H5, H6, H7, H8;
|
||||
|
||||
private long[] W = new long[80];
|
||||
private int wOff;
|
||||
|
||||
/**
|
||||
* Constructor for variable length word
|
||||
*/
|
||||
protected LongDigest()
|
||||
{
|
||||
xBuf = new byte[8];
|
||||
xBufOff = 0;
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor. We are using copy constructors in place
|
||||
* of the Object.clone() interface as this interface is not
|
||||
* supported by J2ME.
|
||||
*/
|
||||
protected LongDigest(LongDigest t)
|
||||
{
|
||||
xBuf = new byte[t.xBuf.length];
|
||||
System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length);
|
||||
|
||||
xBufOff = t.xBufOff;
|
||||
byteCount1 = t.byteCount1;
|
||||
byteCount2 = t.byteCount2;
|
||||
|
||||
H1 = t.H1;
|
||||
H2 = t.H2;
|
||||
H3 = t.H3;
|
||||
H4 = t.H4;
|
||||
H5 = t.H5;
|
||||
H6 = t.H6;
|
||||
H7 = t.H7;
|
||||
H8 = t.H8;
|
||||
|
||||
System.arraycopy(t.W, 0, W, 0, t.W.length);
|
||||
wOff = t.wOff;
|
||||
}
|
||||
|
||||
public void update(
|
||||
byte in)
|
||||
{
|
||||
xBuf[xBufOff++] = in;
|
||||
|
||||
if (xBufOff == xBuf.length)
|
||||
{
|
||||
processWord(xBuf, 0);
|
||||
xBufOff = 0;
|
||||
}
|
||||
|
||||
byteCount1++;
|
||||
}
|
||||
|
||||
public void update(
|
||||
byte[] in,
|
||||
int inOff,
|
||||
int len)
|
||||
{
|
||||
//
|
||||
// fill the current word
|
||||
//
|
||||
while ((xBufOff != 0) && (len > 0))
|
||||
{
|
||||
update(in[inOff]);
|
||||
|
||||
inOff++;
|
||||
len--;
|
||||
}
|
||||
|
||||
//
|
||||
// process whole words.
|
||||
//
|
||||
while (len > xBuf.length)
|
||||
{
|
||||
processWord(in, inOff);
|
||||
|
||||
inOff += xBuf.length;
|
||||
len -= xBuf.length;
|
||||
byteCount1 += xBuf.length;
|
||||
}
|
||||
|
||||
//
|
||||
// load in the remainder.
|
||||
//
|
||||
while (len > 0)
|
||||
{
|
||||
update(in[inOff]);
|
||||
|
||||
inOff++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
public void finish()
|
||||
{
|
||||
adjustByteCounts();
|
||||
|
||||
long lowBitLength = byteCount1 << 3;
|
||||
long hiBitLength = byteCount2;
|
||||
|
||||
//
|
||||
// add the pad bytes.
|
||||
//
|
||||
update((byte)128);
|
||||
|
||||
while (xBufOff != 0)
|
||||
{
|
||||
update((byte)0);
|
||||
}
|
||||
|
||||
processLength(lowBitLength, hiBitLength);
|
||||
|
||||
processBlock();
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
byteCount1 = 0;
|
||||
byteCount2 = 0;
|
||||
|
||||
xBufOff = 0;
|
||||
for (int i = 0; i < xBuf.length; i++)
|
||||
{
|
||||
xBuf[i] = 0;
|
||||
}
|
||||
|
||||
wOff = 0;
|
||||
for (int i = 0; i != W.length; i++)
|
||||
{
|
||||
W[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int getByteLength()
|
||||
{
|
||||
return BYTE_LENGTH;
|
||||
}
|
||||
|
||||
protected void processWord(
|
||||
byte[] in,
|
||||
int inOff)
|
||||
{
|
||||
W[wOff++] = ((long)(in[inOff] & 0xff) << 56)
|
||||
| ((long)(in[inOff + 1] & 0xff) << 48)
|
||||
| ((long)(in[inOff + 2] & 0xff) << 40)
|
||||
| ((long)(in[inOff + 3] & 0xff) << 32)
|
||||
| ((long)(in[inOff + 4] & 0xff) << 24)
|
||||
| ((long)(in[inOff + 5] & 0xff) << 16)
|
||||
| ((long)(in[inOff + 6] & 0xff) << 8)
|
||||
| ((in[inOff + 7] & 0xff));
|
||||
|
||||
if (wOff == 16)
|
||||
{
|
||||
processBlock();
|
||||
}
|
||||
}
|
||||
|
||||
protected void unpackWord(
|
||||
long word,
|
||||
byte[] out,
|
||||
int outOff)
|
||||
{
|
||||
out[outOff] = (byte)(word >>> 56);
|
||||
out[outOff + 1] = (byte)(word >>> 48);
|
||||
out[outOff + 2] = (byte)(word >>> 40);
|
||||
out[outOff + 3] = (byte)(word >>> 32);
|
||||
out[outOff + 4] = (byte)(word >>> 24);
|
||||
out[outOff + 5] = (byte)(word >>> 16);
|
||||
out[outOff + 6] = (byte)(word >>> 8);
|
||||
out[outOff + 7] = (byte)word;
|
||||
}
|
||||
|
||||
/**
|
||||
* adjust the byte counts so that byteCount2 represents the
|
||||
* upper long (less 3 bits) word of the byte count.
|
||||
*/
|
||||
private void adjustByteCounts()
|
||||
{
|
||||
if (byteCount1 > 0x1fffffffffffffffL)
|
||||
{
|
||||
byteCount2 += (byteCount1 >>> 61);
|
||||
byteCount1 &= 0x1fffffffffffffffL;
|
||||
}
|
||||
}
|
||||
|
||||
protected void processLength(
|
||||
long lowW,
|
||||
long hiW)
|
||||
{
|
||||
if (wOff > 14)
|
||||
{
|
||||
processBlock();
|
||||
}
|
||||
|
||||
W[14] = hiW;
|
||||
W[15] = lowW;
|
||||
}
|
||||
|
||||
protected void processBlock()
|
||||
{
|
||||
adjustByteCounts();
|
||||
|
||||
//
|
||||
// expand 16 word block into 80 word blocks.
|
||||
//
|
||||
for (int t = 16; t <= 79; t++)
|
||||
{
|
||||
W[t] = Sigma1(W[t - 2]) + W[t - 7] + Sigma0(W[t - 15]) + W[t - 16];
|
||||
}
|
||||
|
||||
//
|
||||
// set up working variables.
|
||||
//
|
||||
long a = H1;
|
||||
long b = H2;
|
||||
long c = H3;
|
||||
long d = H4;
|
||||
long e = H5;
|
||||
long f = H6;
|
||||
long g = H7;
|
||||
long h = H8;
|
||||
|
||||
int t = 0;
|
||||
for(int i = 0; i < 10; i ++)
|
||||
{
|
||||
// t = 8 * i
|
||||
h += Sum1(e) + Ch(e, f, g) + K[t] + W[t++];
|
||||
d += h;
|
||||
h += Sum0(a) + Maj(a, b, c);
|
||||
|
||||
// t = 8 * i + 1
|
||||
g += Sum1(d) + Ch(d, e, f) + K[t] + W[t++];
|
||||
c += g;
|
||||
g += Sum0(h) + Maj(h, a, b);
|
||||
|
||||
// t = 8 * i + 2
|
||||
f += Sum1(c) + Ch(c, d, e) + K[t] + W[t++];
|
||||
b += f;
|
||||
f += Sum0(g) + Maj(g, h, a);
|
||||
|
||||
// t = 8 * i + 3
|
||||
e += Sum1(b) + Ch(b, c, d) + K[t] + W[t++];
|
||||
a += e;
|
||||
e += Sum0(f) + Maj(f, g, h);
|
||||
|
||||
// t = 8 * i + 4
|
||||
d += Sum1(a) + Ch(a, b, c) + K[t] + W[t++];
|
||||
h += d;
|
||||
d += Sum0(e) + Maj(e, f, g);
|
||||
|
||||
// t = 8 * i + 5
|
||||
c += Sum1(h) + Ch(h, a, b) + K[t] + W[t++];
|
||||
g += c;
|
||||
c += Sum0(d) + Maj(d, e, f);
|
||||
|
||||
// t = 8 * i + 6
|
||||
b += Sum1(g) + Ch(g, h, a) + K[t] + W[t++];
|
||||
f += b;
|
||||
b += Sum0(c) + Maj(c, d, e);
|
||||
|
||||
// t = 8 * i + 7
|
||||
a += Sum1(f) + Ch(f, g, h) + K[t] + W[t++];
|
||||
e += a;
|
||||
a += Sum0(b) + Maj(b, c, d);
|
||||
}
|
||||
|
||||
H1 += a;
|
||||
H2 += b;
|
||||
H3 += c;
|
||||
H4 += d;
|
||||
H5 += e;
|
||||
H6 += f;
|
||||
H7 += g;
|
||||
H8 += h;
|
||||
|
||||
//
|
||||
// reset the offset and clean out the word buffer.
|
||||
//
|
||||
wOff = 0;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
W[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* SHA-384 and SHA-512 functions (as for SHA-256 but for longs) */
|
||||
private long Ch(
|
||||
long x,
|
||||
long y,
|
||||
long z)
|
||||
{
|
||||
return ((x & y) ^ ((~x) & z));
|
||||
}
|
||||
|
||||
private long Maj(
|
||||
long x,
|
||||
long y,
|
||||
long z)
|
||||
{
|
||||
return ((x & y) ^ (x & z) ^ (y & z));
|
||||
}
|
||||
|
||||
private long Sum0(
|
||||
long x)
|
||||
{
|
||||
return ((x << 36)|(x >>> 28)) ^ ((x << 30)|(x >>> 34)) ^ ((x << 25)|(x >>> 39));
|
||||
}
|
||||
|
||||
private long Sum1(
|
||||
long x)
|
||||
{
|
||||
return ((x << 50)|(x >>> 14)) ^ ((x << 46)|(x >>> 18)) ^ ((x << 23)|(x >>> 41));
|
||||
}
|
||||
|
||||
private long Sigma0(
|
||||
long x)
|
||||
{
|
||||
return ((x << 63)|(x >>> 1)) ^ ((x << 56)|(x >>> 8)) ^ (x >>> 7);
|
||||
}
|
||||
|
||||
private long Sigma1(
|
||||
long x)
|
||||
{
|
||||
return ((x << 45)|(x >>> 19)) ^ ((x << 3)|(x >>> 61)) ^ (x >>> 6);
|
||||
}
|
||||
|
||||
/* SHA-384 and SHA-512 Constants
|
||||
* (represent the first 64 bits of the fractional parts of the
|
||||
* cube roots of the first sixty-four prime numbers)
|
||||
*/
|
||||
static final long K[] = {
|
||||
0x428a2f98d728ae22L, 0x7137449123ef65cdL, 0xb5c0fbcfec4d3b2fL, 0xe9b5dba58189dbbcL,
|
||||
0x3956c25bf348b538L, 0x59f111f1b605d019L, 0x923f82a4af194f9bL, 0xab1c5ed5da6d8118L,
|
||||
0xd807aa98a3030242L, 0x12835b0145706fbeL, 0x243185be4ee4b28cL, 0x550c7dc3d5ffb4e2L,
|
||||
0x72be5d74f27b896fL, 0x80deb1fe3b1696b1L, 0x9bdc06a725c71235L, 0xc19bf174cf692694L,
|
||||
0xe49b69c19ef14ad2L, 0xefbe4786384f25e3L, 0x0fc19dc68b8cd5b5L, 0x240ca1cc77ac9c65L,
|
||||
0x2de92c6f592b0275L, 0x4a7484aa6ea6e483L, 0x5cb0a9dcbd41fbd4L, 0x76f988da831153b5L,
|
||||
0x983e5152ee66dfabL, 0xa831c66d2db43210L, 0xb00327c898fb213fL, 0xbf597fc7beef0ee4L,
|
||||
0xc6e00bf33da88fc2L, 0xd5a79147930aa725L, 0x06ca6351e003826fL, 0x142929670a0e6e70L,
|
||||
0x27b70a8546d22ffcL, 0x2e1b21385c26c926L, 0x4d2c6dfc5ac42aedL, 0x53380d139d95b3dfL,
|
||||
0x650a73548baf63deL, 0x766a0abb3c77b2a8L, 0x81c2c92e47edaee6L, 0x92722c851482353bL,
|
||||
0xa2bfe8a14cf10364L, 0xa81a664bbc423001L, 0xc24b8b70d0f89791L, 0xc76c51a30654be30L,
|
||||
0xd192e819d6ef5218L, 0xd69906245565a910L, 0xf40e35855771202aL, 0x106aa07032bbd1b8L,
|
||||
0x19a4c116b8d2d0c8L, 0x1e376c085141ab53L, 0x2748774cdf8eeb99L, 0x34b0bcb5e19b48a8L,
|
||||
0x391c0cb3c5c95a63L, 0x4ed8aa4ae3418acbL, 0x5b9cca4f7763e373L, 0x682e6ff3d6b2b8a3L,
|
||||
0x748f82ee5defb2fcL, 0x78a5636f43172f60L, 0x84c87814a1f0ab72L, 0x8cc702081a6439ecL,
|
||||
0x90befffa23631e28L, 0xa4506cebde82bde9L, 0xbef9a3f7b2c67915L, 0xc67178f2e372532bL,
|
||||
0xca273eceea26619cL, 0xd186b8c721c0c207L, 0xeada7dd6cde0eb1eL, 0xf57d4f7fee6ed178L,
|
||||
0x06f067aa72176fbaL, 0x0a637dc5a2c898a6L, 0x113f9804bef90daeL, 0x1b710b35131c471bL,
|
||||
0x28db77f523047d84L, 0x32caab7b40c72493L, 0x3c9ebe0a15c9bebcL, 0x431d67c49c100d4cL,
|
||||
0x4cc5d4becb3e42b6L, 0x597f299cfc657e2aL, 0x5fcb6fab3ad6faecL, 0x6c44198c4a475817L
|
||||
};
|
||||
}
|
294
src/org/bouncycastle1/crypto/digests/SHA1Digest.java
Normal file
294
src/org/bouncycastle1/crypto/digests/SHA1Digest.java
Normal file
|
@ -0,0 +1,294 @@
|
|||
package org.bouncycastle1.crypto.digests;
|
||||
|
||||
/**
|
||||
* implementation of SHA-1 as outlined in "Handbook of Applied Cryptography", pages 346 - 349.
|
||||
*
|
||||
* It is interesting to ponder why the, apart from the extra IV, the other difference here from MD5
|
||||
* is the "endienness" of the word processing!
|
||||
*/
|
||||
public class SHA1Digest
|
||||
extends org.bouncycastle1.crypto.digests.GeneralDigest
|
||||
{
|
||||
private static final int DIGEST_LENGTH = 20;
|
||||
|
||||
private int H1, H2, H3, H4, H5;
|
||||
|
||||
private int[] X = new int[80];
|
||||
private int xOff;
|
||||
|
||||
/**
|
||||
* Standard constructor
|
||||
*/
|
||||
public SHA1Digest()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor. This will copy the state of the provided
|
||||
* message digest.
|
||||
*/
|
||||
public SHA1Digest(SHA1Digest t)
|
||||
{
|
||||
super(t);
|
||||
|
||||
H1 = t.H1;
|
||||
H2 = t.H2;
|
||||
H3 = t.H3;
|
||||
H4 = t.H4;
|
||||
H5 = t.H5;
|
||||
|
||||
System.arraycopy(t.X, 0, X, 0, t.X.length);
|
||||
xOff = t.xOff;
|
||||
}
|
||||
|
||||
public String getAlgorithmName()
|
||||
{
|
||||
return "SHA-1";
|
||||
}
|
||||
|
||||
public int getDigestSize()
|
||||
{
|
||||
return DIGEST_LENGTH;
|
||||
}
|
||||
|
||||
protected void processWord(
|
||||
byte[] in,
|
||||
int inOff)
|
||||
{
|
||||
X[xOff++] = (in[inOff] & 0xff) << 24 | (in[inOff + 1] & 0xff) << 16
|
||||
| (in[inOff + 2] & 0xff) << 8 | in[inOff + 3] & 0xff;
|
||||
|
||||
if (xOff == 16)
|
||||
{
|
||||
processBlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void unpackWord(
|
||||
int word,
|
||||
byte[] out,
|
||||
int outOff)
|
||||
{
|
||||
out[outOff++] = (byte)(word >>> 24);
|
||||
out[outOff++] = (byte)(word >>> 16);
|
||||
out[outOff++] = (byte)(word >>> 8);
|
||||
out[outOff++] = (byte)word;
|
||||
}
|
||||
|
||||
protected void processLength(
|
||||
long bitLength)
|
||||
{
|
||||
if (xOff > 14)
|
||||
{
|
||||
processBlock();
|
||||
}
|
||||
|
||||
X[14] = (int)(bitLength >>> 32);
|
||||
X[15] = (int)(bitLength & 0xffffffff);
|
||||
}
|
||||
|
||||
public int doFinal(
|
||||
byte[] out,
|
||||
int outOff)
|
||||
{
|
||||
finish();
|
||||
|
||||
unpackWord(H1, out, outOff);
|
||||
unpackWord(H2, out, outOff + 4);
|
||||
unpackWord(H3, out, outOff + 8);
|
||||
unpackWord(H4, out, outOff + 12);
|
||||
unpackWord(H5, out, outOff + 16);
|
||||
|
||||
reset();
|
||||
|
||||
return DIGEST_LENGTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* reset the chaining variables
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
super.reset();
|
||||
|
||||
H1 = 0x67452301;
|
||||
H2 = 0xefcdab89;
|
||||
H3 = 0x98badcfe;
|
||||
H4 = 0x10325476;
|
||||
H5 = 0xc3d2e1f0;
|
||||
|
||||
xOff = 0;
|
||||
for (int i = 0; i != X.length; i++)
|
||||
{
|
||||
X[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Additive constants
|
||||
//
|
||||
private static final int Y1 = 0x5a827999;
|
||||
private static final int Y2 = 0x6ed9eba1;
|
||||
private static final int Y3 = 0x8f1bbcdc;
|
||||
private static final int Y4 = 0xca62c1d6;
|
||||
|
||||
private int f(
|
||||
int u,
|
||||
int v,
|
||||
int w)
|
||||
{
|
||||
return ((u & v) | ((~u) & w));
|
||||
}
|
||||
|
||||
private int h(
|
||||
int u,
|
||||
int v,
|
||||
int w)
|
||||
{
|
||||
return (u ^ v ^ w);
|
||||
}
|
||||
|
||||
private int g(
|
||||
int u,
|
||||
int v,
|
||||
int w)
|
||||
{
|
||||
return ((u & v) | (u & w) | (v & w));
|
||||
}
|
||||
|
||||
protected void processBlock()
|
||||
{
|
||||
//
|
||||
// expand 16 word block into 80 word block.
|
||||
//
|
||||
for (int i = 16; i < 80; i++)
|
||||
{
|
||||
int t = X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16];
|
||||
X[i] = t << 1 | t >>> 31;
|
||||
}
|
||||
|
||||
//
|
||||
// set up working variables.
|
||||
//
|
||||
int A = H1;
|
||||
int B = H2;
|
||||
int C = H3;
|
||||
int D = H4;
|
||||
int E = H5;
|
||||
|
||||
//
|
||||
// round 1
|
||||
//
|
||||
int idx = 0;
|
||||
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
// E = rotateLeft(A, 5) + f(B, C, D) + E + X[idx++] + Y1
|
||||
// B = rotateLeft(B, 30)
|
||||
E += (A << 5 | A >>> 27) + f(B, C, D) + X[idx++] + Y1;
|
||||
B = B << 30 | B >>> 2;
|
||||
|
||||
D += (E << 5 | E >>> 27) + f(A, B, C) + X[idx++] + Y1;
|
||||
A = A << 30 | A >>> 2;
|
||||
|
||||
C += (D << 5 | D >>> 27) + f(E, A, B) + X[idx++] + Y1;
|
||||
E = E << 30 | E >>> 2;
|
||||
|
||||
B += (C << 5 | C >>> 27) + f(D, E, A) + X[idx++] + Y1;
|
||||
D = D << 30 | D >>> 2;
|
||||
|
||||
A += (B << 5 | B >>> 27) + f(C, D, E) + X[idx++] + Y1;
|
||||
C = C << 30 | C >>> 2;
|
||||
}
|
||||
|
||||
//
|
||||
// round 2
|
||||
//
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
// E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y2
|
||||
// B = rotateLeft(B, 30)
|
||||
E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y2;
|
||||
B = B << 30 | B >>> 2;
|
||||
|
||||
D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y2;
|
||||
A = A << 30 | A >>> 2;
|
||||
|
||||
C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y2;
|
||||
E = E << 30 | E >>> 2;
|
||||
|
||||
B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y2;
|
||||
D = D << 30 | D >>> 2;
|
||||
|
||||
A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y2;
|
||||
C = C << 30 | C >>> 2;
|
||||
}
|
||||
|
||||
//
|
||||
// round 3
|
||||
//
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
// E = rotateLeft(A, 5) + g(B, C, D) + E + X[idx++] + Y3
|
||||
// B = rotateLeft(B, 30)
|
||||
E += (A << 5 | A >>> 27) + g(B, C, D) + X[idx++] + Y3;
|
||||
B = B << 30 | B >>> 2;
|
||||
|
||||
D += (E << 5 | E >>> 27) + g(A, B, C) + X[idx++] + Y3;
|
||||
A = A << 30 | A >>> 2;
|
||||
|
||||
C += (D << 5 | D >>> 27) + g(E, A, B) + X[idx++] + Y3;
|
||||
E = E << 30 | E >>> 2;
|
||||
|
||||
B += (C << 5 | C >>> 27) + g(D, E, A) + X[idx++] + Y3;
|
||||
D = D << 30 | D >>> 2;
|
||||
|
||||
A += (B << 5 | B >>> 27) + g(C, D, E) + X[idx++] + Y3;
|
||||
C = C << 30 | C >>> 2;
|
||||
}
|
||||
|
||||
//
|
||||
// round 4
|
||||
//
|
||||
for (int j = 0; j <= 3; j++)
|
||||
{
|
||||
// E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y4
|
||||
// B = rotateLeft(B, 30)
|
||||
E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y4;
|
||||
B = B << 30 | B >>> 2;
|
||||
|
||||
D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y4;
|
||||
A = A << 30 | A >>> 2;
|
||||
|
||||
C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y4;
|
||||
E = E << 30 | E >>> 2;
|
||||
|
||||
B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y4;
|
||||
D = D << 30 | D >>> 2;
|
||||
|
||||
A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y4;
|
||||
C = C << 30 | C >>> 2;
|
||||
}
|
||||
|
||||
|
||||
H1 += A;
|
||||
H2 += B;
|
||||
H3 += C;
|
||||
H4 += D;
|
||||
H5 += E;
|
||||
|
||||
//
|
||||
// reset start of the buffer.
|
||||
//
|
||||
xOff = 0;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
X[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
291
src/org/bouncycastle1/crypto/digests/SHA256Digest.java
Normal file
291
src/org/bouncycastle1/crypto/digests/SHA256Digest.java
Normal file
|
@ -0,0 +1,291 @@
|
|||
package org.bouncycastle1.crypto.digests;
|
||||
|
||||
|
||||
import org.bouncycastle1.crypto.digests.GeneralDigest;
|
||||
|
||||
|
||||
/**
|
||||
* FIPS 180-2 implementation of SHA-256.
|
||||
*
|
||||
* <pre>
|
||||
* block word digest
|
||||
* SHA-1 512 32 160
|
||||
* SHA-256 512 32 256
|
||||
* SHA-384 1024 64 384
|
||||
* SHA-512 1024 64 512
|
||||
* </pre>
|
||||
*/
|
||||
public class SHA256Digest
|
||||
extends org.bouncycastle1.crypto.digests.GeneralDigest
|
||||
{
|
||||
private static final int DIGEST_LENGTH = 32;
|
||||
|
||||
private int H1, H2, H3, H4, H5, H6, H7, H8;
|
||||
|
||||
private int[] X = new int[64];
|
||||
private int xOff;
|
||||
|
||||
/**
|
||||
* Standard constructor
|
||||
*/
|
||||
public SHA256Digest()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor. This will copy the state of the provided
|
||||
* message digest.
|
||||
*/
|
||||
public SHA256Digest(SHA256Digest t)
|
||||
{
|
||||
super(t);
|
||||
|
||||
H1 = t.H1;
|
||||
H2 = t.H2;
|
||||
H3 = t.H3;
|
||||
H4 = t.H4;
|
||||
H5 = t.H5;
|
||||
H6 = t.H6;
|
||||
H7 = t.H7;
|
||||
H8 = t.H8;
|
||||
|
||||
System.arraycopy(t.X, 0, X, 0, t.X.length);
|
||||
xOff = t.xOff;
|
||||
}
|
||||
|
||||
public String getAlgorithmName()
|
||||
{
|
||||
return "SHA-256";
|
||||
}
|
||||
|
||||
public int getDigestSize()
|
||||
{
|
||||
return DIGEST_LENGTH;
|
||||
}
|
||||
|
||||
protected void processWord(
|
||||
byte[] in,
|
||||
int inOff)
|
||||
{
|
||||
X[xOff++] = ((in[inOff] & 0xff) << 24) | ((in[inOff + 1] & 0xff) << 16)
|
||||
| ((in[inOff + 2] & 0xff) << 8) | ((in[inOff + 3] & 0xff));
|
||||
|
||||
if (xOff == 16)
|
||||
{
|
||||
processBlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void unpackWord(
|
||||
int word,
|
||||
byte[] out,
|
||||
int outOff)
|
||||
{
|
||||
out[outOff] = (byte)(word >>> 24);
|
||||
out[outOff + 1] = (byte)(word >>> 16);
|
||||
out[outOff + 2] = (byte)(word >>> 8);
|
||||
out[outOff + 3] = (byte)word;
|
||||
}
|
||||
|
||||
protected void processLength(
|
||||
long bitLength)
|
||||
{
|
||||
if (xOff > 14)
|
||||
{
|
||||
processBlock();
|
||||
}
|
||||
|
||||
X[14] = (int)(bitLength >>> 32);
|
||||
X[15] = (int)(bitLength & 0xffffffff);
|
||||
}
|
||||
|
||||
public int doFinal(
|
||||
byte[] out,
|
||||
int outOff)
|
||||
{
|
||||
finish();
|
||||
|
||||
unpackWord(H1, out, outOff);
|
||||
unpackWord(H2, out, outOff + 4);
|
||||
unpackWord(H3, out, outOff + 8);
|
||||
unpackWord(H4, out, outOff + 12);
|
||||
unpackWord(H5, out, outOff + 16);
|
||||
unpackWord(H6, out, outOff + 20);
|
||||
unpackWord(H7, out, outOff + 24);
|
||||
unpackWord(H8, out, outOff + 28);
|
||||
|
||||
reset();
|
||||
|
||||
return DIGEST_LENGTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* reset the chaining variables
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
super.reset();
|
||||
|
||||
/* SHA-256 initial hash value
|
||||
* The first 32 bits of the fractional parts of the square roots
|
||||
* of the first eight prime numbers
|
||||
*/
|
||||
|
||||
H1 = 0x6a09e667;
|
||||
H2 = 0xbb67ae85;
|
||||
H3 = 0x3c6ef372;
|
||||
H4 = 0xa54ff53a;
|
||||
H5 = 0x510e527f;
|
||||
H6 = 0x9b05688c;
|
||||
H7 = 0x1f83d9ab;
|
||||
H8 = 0x5be0cd19;
|
||||
|
||||
xOff = 0;
|
||||
for (int i = 0; i != X.length; i++)
|
||||
{
|
||||
X[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected void processBlock()
|
||||
{
|
||||
//
|
||||
// expand 16 word block into 64 word blocks.
|
||||
//
|
||||
for (int t = 16; t <= 63; t++)
|
||||
{
|
||||
X[t] = Theta1(X[t - 2]) + X[t - 7] + Theta0(X[t - 15]) + X[t - 16];
|
||||
}
|
||||
|
||||
//
|
||||
// set up working variables.
|
||||
//
|
||||
int a = H1;
|
||||
int b = H2;
|
||||
int c = H3;
|
||||
int d = H4;
|
||||
int e = H5;
|
||||
int f = H6;
|
||||
int g = H7;
|
||||
int h = H8;
|
||||
|
||||
int t = 0;
|
||||
for(int i = 0; i < 8; i ++)
|
||||
{
|
||||
// t = 8 * i
|
||||
h += Sum1(e) + Ch(e, f, g) + K[t] + X[t++];
|
||||
d += h;
|
||||
h += Sum0(a) + Maj(a, b, c);
|
||||
|
||||
// t = 8 * i + 1
|
||||
g += Sum1(d) + Ch(d, e, f) + K[t] + X[t++];
|
||||
c += g;
|
||||
g += Sum0(h) + Maj(h, a, b);
|
||||
|
||||
// t = 8 * i + 2
|
||||
f += Sum1(c) + Ch(c, d, e) + K[t] + X[t++];
|
||||
b += f;
|
||||
f += Sum0(g) + Maj(g, h, a);
|
||||
|
||||
// t = 8 * i + 3
|
||||
e += Sum1(b) + Ch(b, c, d) + K[t] + X[t++];
|
||||
a += e;
|
||||
e += Sum0(f) + Maj(f, g, h);
|
||||
|
||||
// t = 8 * i + 4
|
||||
d += Sum1(a) + Ch(a, b, c) + K[t] + X[t++];
|
||||
h += d;
|
||||
d += Sum0(e) + Maj(e, f, g);
|
||||
|
||||
// t = 8 * i + 5
|
||||
c += Sum1(h) + Ch(h, a, b) + K[t] + X[t++];
|
||||
g += c;
|
||||
c += Sum0(d) + Maj(d, e, f);
|
||||
|
||||
// t = 8 * i + 6
|
||||
b += Sum1(g) + Ch(g, h, a) + K[t] + X[t++];
|
||||
f += b;
|
||||
b += Sum0(c) + Maj(c, d, e);
|
||||
|
||||
// t = 8 * i + 7
|
||||
a += Sum1(f) + Ch(f, g, h) + K[t] + X[t++];
|
||||
e += a;
|
||||
a += Sum0(b) + Maj(b, c, d);
|
||||
}
|
||||
|
||||
H1 += a;
|
||||
H2 += b;
|
||||
H3 += c;
|
||||
H4 += d;
|
||||
H5 += e;
|
||||
H6 += f;
|
||||
H7 += g;
|
||||
H8 += h;
|
||||
|
||||
//
|
||||
// reset the offset and clean out the word buffer.
|
||||
//
|
||||
xOff = 0;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
X[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* SHA-256 functions */
|
||||
private int Ch(
|
||||
int x,
|
||||
int y,
|
||||
int z)
|
||||
{
|
||||
return (x & y) ^ ((~x) & z);
|
||||
}
|
||||
|
||||
private int Maj(
|
||||
int x,
|
||||
int y,
|
||||
int z)
|
||||
{
|
||||
return (x & y) ^ (x & z) ^ (y & z);
|
||||
}
|
||||
|
||||
private int Sum0(
|
||||
int x)
|
||||
{
|
||||
return ((x >>> 2) | (x << 30)) ^ ((x >>> 13) | (x << 19)) ^ ((x >>> 22) | (x << 10));
|
||||
}
|
||||
|
||||
private int Sum1(
|
||||
int x)
|
||||
{
|
||||
return ((x >>> 6) | (x << 26)) ^ ((x >>> 11) | (x << 21)) ^ ((x >>> 25) | (x << 7));
|
||||
}
|
||||
|
||||
private int Theta0(
|
||||
int x)
|
||||
{
|
||||
return ((x >>> 7) | (x << 25)) ^ ((x >>> 18) | (x << 14)) ^ (x >>> 3);
|
||||
}
|
||||
|
||||
private int Theta1(
|
||||
int x)
|
||||
{
|
||||
return ((x >>> 17) | (x << 15)) ^ ((x >>> 19) | (x << 13)) ^ (x >>> 10);
|
||||
}
|
||||
|
||||
/* SHA-256 Constants
|
||||
* (represent the first 32 bits of the fractional parts of the
|
||||
* cube roots of the first sixty-four prime numbers)
|
||||
*/
|
||||
static final int K[] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
}
|
||||
|
87
src/org/bouncycastle1/crypto/digests/SHA512Digest.java
Normal file
87
src/org/bouncycastle1/crypto/digests/SHA512Digest.java
Normal file
|
@ -0,0 +1,87 @@
|
|||
package org.bouncycastle1.crypto.digests;
|
||||
|
||||
|
||||
/**
|
||||
* FIPS 180-2 implementation of SHA-512.
|
||||
*
|
||||
* <pre>
|
||||
* block word digest
|
||||
* SHA-1 512 32 160
|
||||
* SHA-256 512 32 256
|
||||
* SHA-384 1024 64 384
|
||||
* SHA-512 1024 64 512
|
||||
* </pre>
|
||||
*/
|
||||
public class SHA512Digest
|
||||
extends LongDigest
|
||||
{
|
||||
private static final int DIGEST_LENGTH = 64;
|
||||
|
||||
/**
|
||||
* Standard constructor
|
||||
*/
|
||||
public SHA512Digest()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor. This will copy the state of the provided
|
||||
* message digest.
|
||||
*/
|
||||
public SHA512Digest(SHA512Digest t)
|
||||
{
|
||||
super(t);
|
||||
}
|
||||
|
||||
public String getAlgorithmName()
|
||||
{
|
||||
return "SHA-512";
|
||||
}
|
||||
|
||||
public int getDigestSize()
|
||||
{
|
||||
return DIGEST_LENGTH;
|
||||
}
|
||||
|
||||
public int doFinal(
|
||||
byte[] out,
|
||||
int outOff)
|
||||
{
|
||||
finish();
|
||||
|
||||
unpackWord(H1, out, outOff);
|
||||
unpackWord(H2, out, outOff + 8);
|
||||
unpackWord(H3, out, outOff + 16);
|
||||
unpackWord(H4, out, outOff + 24);
|
||||
unpackWord(H5, out, outOff + 32);
|
||||
unpackWord(H6, out, outOff + 40);
|
||||
unpackWord(H7, out, outOff + 48);
|
||||
unpackWord(H8, out, outOff + 56);
|
||||
|
||||
reset();
|
||||
|
||||
return DIGEST_LENGTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* reset the chaining variables
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
super.reset();
|
||||
|
||||
/* SHA-512 initial hash value
|
||||
* The first 64 bits of the fractional parts of the square roots
|
||||
* of the first eight prime numbers
|
||||
*/
|
||||
H1 = 0x6a09e667f3bcc908L;
|
||||
H2 = 0xbb67ae8584caa73bL;
|
||||
H3 = 0x3c6ef372fe94f82bL;
|
||||
H4 = 0xa54ff53a5f1d36f1L;
|
||||
H5 = 0x510e527fade682d1L;
|
||||
H6 = 0x9b05688c2b3e6c1fL;
|
||||
H7 = 0x1f83d9abfb41bd6bL;
|
||||
H8 = 0x5be0cd19137e2179L;
|
||||
}
|
||||
}
|
||||
|
547
src/org/bouncycastle1/crypto/engines/AESEngine.java
Normal file
547
src/org/bouncycastle1/crypto/engines/AESEngine.java
Normal file
|
@ -0,0 +1,547 @@
|
|||
package org.bouncycastle1.crypto.engines;
|
||||
|
||||
import org.bouncycastle1.crypto.BlockCipher;
|
||||
import org.bouncycastle1.crypto.CipherParameters;
|
||||
import org.bouncycastle1.crypto.DataLengthException;
|
||||
import org.bouncycastle1.crypto.params.KeyParameter;
|
||||
|
||||
/**
|
||||
* an implementation of the AES (Rijndael), from FIPS-197.
|
||||
* <p>
|
||||
* For further details see: <a href="http://csrc.nist.gov/encryption/aes/">http://csrc.nist.gov/encryption/aes/</a>.
|
||||
*
|
||||
* This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
|
||||
* <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/">http://fp.gladman.plus.com/cryptography_technology/rijndael/</a>
|
||||
*
|
||||
* There are three levels of tradeoff of speed vs memory
|
||||
* Because java has no preprocessor, they are written as three separate classes from which to choose
|
||||
*
|
||||
* The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption
|
||||
* and 4 for decryption.
|
||||
*
|
||||
* The middle performance version uses only one 256 word table for each, for a total of 2Kbytes,
|
||||
* adding 12 rotate operations per round to compute the values contained in the other tables from
|
||||
* the contents of the first.
|
||||
*
|
||||
* The slowest version uses no static tables at all and computes the values in each round.
|
||||
* <p>
|
||||
* This file contains the middle performance version with 2Kbytes of static tables for round precomputation.
|
||||
*
|
||||
*/
|
||||
public class AESEngine
|
||||
implements BlockCipher
|
||||
{
|
||||
// The S box
|
||||
private static final byte[] S = {
|
||||
(byte)99, (byte)124, (byte)119, (byte)123, (byte)242, (byte)107, (byte)111, (byte)197,
|
||||
(byte)48, (byte)1, (byte)103, (byte)43, (byte)254, (byte)215, (byte)171, (byte)118,
|
||||
(byte)202, (byte)130, (byte)201, (byte)125, (byte)250, (byte)89, (byte)71, (byte)240,
|
||||
(byte)173, (byte)212, (byte)162, (byte)175, (byte)156, (byte)164, (byte)114, (byte)192,
|
||||
(byte)183, (byte)253, (byte)147, (byte)38, (byte)54, (byte)63, (byte)247, (byte)204,
|
||||
(byte)52, (byte)165, (byte)229, (byte)241, (byte)113, (byte)216, (byte)49, (byte)21,
|
||||
(byte)4, (byte)199, (byte)35, (byte)195, (byte)24, (byte)150, (byte)5, (byte)154,
|
||||
(byte)7, (byte)18, (byte)128, (byte)226, (byte)235, (byte)39, (byte)178, (byte)117,
|
||||
(byte)9, (byte)131, (byte)44, (byte)26, (byte)27, (byte)110, (byte)90, (byte)160,
|
||||
(byte)82, (byte)59, (byte)214, (byte)179, (byte)41, (byte)227, (byte)47, (byte)132,
|
||||
(byte)83, (byte)209, (byte)0, (byte)237, (byte)32, (byte)252, (byte)177, (byte)91,
|
||||
(byte)106, (byte)203, (byte)190, (byte)57, (byte)74, (byte)76, (byte)88, (byte)207,
|
||||
(byte)208, (byte)239, (byte)170, (byte)251, (byte)67, (byte)77, (byte)51, (byte)133,
|
||||
(byte)69, (byte)249, (byte)2, (byte)127, (byte)80, (byte)60, (byte)159, (byte)168,
|
||||
(byte)81, (byte)163, (byte)64, (byte)143, (byte)146, (byte)157, (byte)56, (byte)245,
|
||||
(byte)188, (byte)182, (byte)218, (byte)33, (byte)16, (byte)255, (byte)243, (byte)210,
|
||||
(byte)205, (byte)12, (byte)19, (byte)236, (byte)95, (byte)151, (byte)68, (byte)23,
|
||||
(byte)196, (byte)167, (byte)126, (byte)61, (byte)100, (byte)93, (byte)25, (byte)115,
|
||||
(byte)96, (byte)129, (byte)79, (byte)220, (byte)34, (byte)42, (byte)144, (byte)136,
|
||||
(byte)70, (byte)238, (byte)184, (byte)20, (byte)222, (byte)94, (byte)11, (byte)219,
|
||||
(byte)224, (byte)50, (byte)58, (byte)10, (byte)73, (byte)6, (byte)36, (byte)92,
|
||||
(byte)194, (byte)211, (byte)172, (byte)98, (byte)145, (byte)149, (byte)228, (byte)121,
|
||||
(byte)231, (byte)200, (byte)55, (byte)109, (byte)141, (byte)213, (byte)78, (byte)169,
|
||||
(byte)108, (byte)86, (byte)244, (byte)234, (byte)101, (byte)122, (byte)174, (byte)8,
|
||||
(byte)186, (byte)120, (byte)37, (byte)46, (byte)28, (byte)166, (byte)180, (byte)198,
|
||||
(byte)232, (byte)221, (byte)116, (byte)31, (byte)75, (byte)189, (byte)139, (byte)138,
|
||||
(byte)112, (byte)62, (byte)181, (byte)102, (byte)72, (byte)3, (byte)246, (byte)14,
|
||||
(byte)97, (byte)53, (byte)87, (byte)185, (byte)134, (byte)193, (byte)29, (byte)158,
|
||||
(byte)225, (byte)248, (byte)152, (byte)17, (byte)105, (byte)217, (byte)142, (byte)148,
|
||||
(byte)155, (byte)30, (byte)135, (byte)233, (byte)206, (byte)85, (byte)40, (byte)223,
|
||||
(byte)140, (byte)161, (byte)137, (byte)13, (byte)191, (byte)230, (byte)66, (byte)104,
|
||||
(byte)65, (byte)153, (byte)45, (byte)15, (byte)176, (byte)84, (byte)187, (byte)22,
|
||||
};
|
||||
|
||||
// The inverse S-box
|
||||
private static final byte[] Si = {
|
||||
(byte)82, (byte)9, (byte)106, (byte)213, (byte)48, (byte)54, (byte)165, (byte)56,
|
||||
(byte)191, (byte)64, (byte)163, (byte)158, (byte)129, (byte)243, (byte)215, (byte)251,
|
||||
(byte)124, (byte)227, (byte)57, (byte)130, (byte)155, (byte)47, (byte)255, (byte)135,
|
||||
(byte)52, (byte)142, (byte)67, (byte)68, (byte)196, (byte)222, (byte)233, (byte)203,
|
||||
(byte)84, (byte)123, (byte)148, (byte)50, (byte)166, (byte)194, (byte)35, (byte)61,
|
||||
(byte)238, (byte)76, (byte)149, (byte)11, (byte)66, (byte)250, (byte)195, (byte)78,
|
||||
(byte)8, (byte)46, (byte)161, (byte)102, (byte)40, (byte)217, (byte)36, (byte)178,
|
||||
(byte)118, (byte)91, (byte)162, (byte)73, (byte)109, (byte)139, (byte)209, (byte)37,
|
||||
(byte)114, (byte)248, (byte)246, (byte)100, (byte)134, (byte)104, (byte)152, (byte)22,
|
||||
(byte)212, (byte)164, (byte)92, (byte)204, (byte)93, (byte)101, (byte)182, (byte)146,
|
||||
(byte)108, (byte)112, (byte)72, (byte)80, (byte)253, (byte)237, (byte)185, (byte)218,
|
||||
(byte)94, (byte)21, (byte)70, (byte)87, (byte)167, (byte)141, (byte)157, (byte)132,
|
||||
(byte)144, (byte)216, (byte)171, (byte)0, (byte)140, (byte)188, (byte)211, (byte)10,
|
||||
(byte)247, (byte)228, (byte)88, (byte)5, (byte)184, (byte)179, (byte)69, (byte)6,
|
||||
(byte)208, (byte)44, (byte)30, (byte)143, (byte)202, (byte)63, (byte)15, (byte)2,
|
||||
(byte)193, (byte)175, (byte)189, (byte)3, (byte)1, (byte)19, (byte)138, (byte)107,
|
||||
(byte)58, (byte)145, (byte)17, (byte)65, (byte)79, (byte)103, (byte)220, (byte)234,
|
||||
(byte)151, (byte)242, (byte)207, (byte)206, (byte)240, (byte)180, (byte)230, (byte)115,
|
||||
(byte)150, (byte)172, (byte)116, (byte)34, (byte)231, (byte)173, (byte)53, (byte)133,
|
||||
(byte)226, (byte)249, (byte)55, (byte)232, (byte)28, (byte)117, (byte)223, (byte)110,
|
||||
(byte)71, (byte)241, (byte)26, (byte)113, (byte)29, (byte)41, (byte)197, (byte)137,
|
||||
(byte)111, (byte)183, (byte)98, (byte)14, (byte)170, (byte)24, (byte)190, (byte)27,
|
||||
(byte)252, (byte)86, (byte)62, (byte)75, (byte)198, (byte)210, (byte)121, (byte)32,
|
||||
(byte)154, (byte)219, (byte)192, (byte)254, (byte)120, (byte)205, (byte)90, (byte)244,
|
||||
(byte)31, (byte)221, (byte)168, (byte)51, (byte)136, (byte)7, (byte)199, (byte)49,
|
||||
(byte)177, (byte)18, (byte)16, (byte)89, (byte)39, (byte)128, (byte)236, (byte)95,
|
||||
(byte)96, (byte)81, (byte)127, (byte)169, (byte)25, (byte)181, (byte)74, (byte)13,
|
||||
(byte)45, (byte)229, (byte)122, (byte)159, (byte)147, (byte)201, (byte)156, (byte)239,
|
||||
(byte)160, (byte)224, (byte)59, (byte)77, (byte)174, (byte)42, (byte)245, (byte)176,
|
||||
(byte)200, (byte)235, (byte)187, (byte)60, (byte)131, (byte)83, (byte)153, (byte)97,
|
||||
(byte)23, (byte)43, (byte)4, (byte)126, (byte)186, (byte)119, (byte)214, (byte)38,
|
||||
(byte)225, (byte)105, (byte)20, (byte)99, (byte)85, (byte)33, (byte)12, (byte)125,
|
||||
};
|
||||
|
||||
// vector used in calculating key schedule (powers of x in GF(256))
|
||||
private static final int[] 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 };
|
||||
|
||||
// precomputation tables of calculations for rounds
|
||||
private static final int[] T0 =
|
||||
{
|
||||
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};
|
||||
|
||||
private static final int[] Tinv0 =
|
||||
{
|
||||
0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b,
|
||||
0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad,
|
||||
0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526,
|
||||
0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d,
|
||||
0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 0xe75f8f03,
|
||||
0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458,
|
||||
0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899,
|
||||
0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d,
|
||||
0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1,
|
||||
0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f,
|
||||
0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3,
|
||||
0x2aab5566, 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3,
|
||||
0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a,
|
||||
0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506,
|
||||
0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05,
|
||||
0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd,
|
||||
0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491,
|
||||
0x055dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6,
|
||||
0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7,
|
||||
0xdbeec879, 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000,
|
||||
0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd,
|
||||
0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68,
|
||||
0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0x0fe75793, 0xd296eeb4,
|
||||
0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c,
|
||||
0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0x0b0d090e,
|
||||
0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af,
|
||||
0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644,
|
||||
0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8,
|
||||
0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85,
|
||||
0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc,
|
||||
0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411,
|
||||
0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322,
|
||||
0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6,
|
||||
0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 0xe49d3a2c, 0x0d927850,
|
||||
0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e,
|
||||
0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf,
|
||||
0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x097826cd,
|
||||
0xf418596e, 0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa,
|
||||
0x08cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea,
|
||||
0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235,
|
||||
0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1,
|
||||
0xf7daec41, 0x0e50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43,
|
||||
0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1,
|
||||
0x7f516546, 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb,
|
||||
0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 0x8c61d79a,
|
||||
0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7,
|
||||
0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418,
|
||||
0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478,
|
||||
0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16,
|
||||
0x0c25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08,
|
||||
0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48,
|
||||
0x4257b8d0};
|
||||
|
||||
private int shift(
|
||||
int r,
|
||||
int shift)
|
||||
{
|
||||
return (r >>> shift) | (r << -shift);
|
||||
}
|
||||
|
||||
/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
|
||||
|
||||
private static final int m1 = 0x80808080;
|
||||
private static final int m2 = 0x7f7f7f7f;
|
||||
private static final int m3 = 0x0000001b;
|
||||
|
||||
private int FFmulX(int x)
|
||||
{
|
||||
return (((x & m2) << 1) ^ (((x & m1) >>> 7) * m3));
|
||||
}
|
||||
|
||||
/*
|
||||
The following defines provide alternative definitions of FFmulX that might
|
||||
give improved performance if a fast 32-bit multiply is not available.
|
||||
|
||||
private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); }
|
||||
private static final int m4 = 0x1b1b1b1b;
|
||||
private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); }
|
||||
|
||||
*/
|
||||
|
||||
private int inv_mcol(int x)
|
||||
{
|
||||
int f2 = FFmulX(x);
|
||||
int f4 = FFmulX(f2);
|
||||
int f8 = FFmulX(f4);
|
||||
int f9 = x ^ f8;
|
||||
|
||||
return f2 ^ f4 ^ f8 ^ shift(f2 ^ f9, 8) ^ shift(f4 ^ f9, 16) ^ shift(f9, 24);
|
||||
}
|
||||
|
||||
private int subWord(int x)
|
||||
{
|
||||
return (S[x&255]&255 | ((S[(x>>8)&255]&255)<<8) | ((S[(x>>16)&255]&255)<<16) | S[(x>>24)&255]<<24);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the necessary round keys
|
||||
* The number of calculations depends on key size and block size
|
||||
* AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
|
||||
* This code is written assuming those are the only possible values
|
||||
*/
|
||||
private int[][] generateWorkingKey(
|
||||
byte[] key,
|
||||
boolean forEncryption)
|
||||
{
|
||||
int KC = key.length / 4; // key length in words
|
||||
int t;
|
||||
|
||||
if (((KC != 4) && (KC != 6) && (KC != 8)) || ((KC * 4) != key.length))
|
||||
{
|
||||
throw new IllegalArgumentException("Key length not 128/192/256 bits.");
|
||||
}
|
||||
|
||||
ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes
|
||||
int[][] W = new int[ROUNDS+1][4]; // 4 words in a block
|
||||
|
||||
//
|
||||
// copy the key into the round key array
|
||||
//
|
||||
|
||||
t = 0;
|
||||
int i = 0;
|
||||
while (i < key.length)
|
||||
{
|
||||
W[t >> 2][t & 3] = (key[i]&0xff) | ((key[i+1]&0xff) << 8) | ((key[i+2]&0xff) << 16) | (key[i+3] << 24);
|
||||
i+=4;
|
||||
t++;
|
||||
}
|
||||
|
||||
//
|
||||
// while not enough round key material calculated
|
||||
// calculate new values
|
||||
//
|
||||
int k = (ROUNDS + 1) << 2;
|
||||
for (i = KC; (i < k); i++)
|
||||
{
|
||||
int temp = W[(i-1)>>2][(i-1)&3];
|
||||
if ((i % KC) == 0)
|
||||
{
|
||||
temp = subWord(shift(temp, 8)) ^ rcon[(i / KC)-1];
|
||||
}
|
||||
else if ((KC > 6) && ((i % KC) == 4))
|
||||
{
|
||||
temp = subWord(temp);
|
||||
}
|
||||
|
||||
W[i>>2][i&3] = W[(i - KC)>>2][(i-KC)&3] ^ temp;
|
||||
}
|
||||
|
||||
if (!forEncryption)
|
||||
{
|
||||
for (int j = 1; j < ROUNDS; j++)
|
||||
{
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
W[j][i] = inv_mcol(W[j][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return W;
|
||||
}
|
||||
|
||||
private int ROUNDS;
|
||||
private int[][] WorkingKey = null;
|
||||
private int C0, C1, C2, C3;
|
||||
private boolean forEncryption;
|
||||
|
||||
private static final int BLOCK_SIZE = 16;
|
||||
|
||||
/**
|
||||
* default constructor - 128 bit block size.
|
||||
*/
|
||||
public AESEngine()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* initialise an AES cipher.
|
||||
*
|
||||
* @param forEncryption whether or not we are for encryption.
|
||||
* @param params the parameters required to set up the cipher.
|
||||
* @exception IllegalArgumentException if the params argument is
|
||||
* inappropriate.
|
||||
*/
|
||||
public void init(
|
||||
boolean forEncryption,
|
||||
CipherParameters params)
|
||||
{
|
||||
if (params instanceof KeyParameter)
|
||||
{
|
||||
WorkingKey = generateWorkingKey(((KeyParameter)params).getKey(), forEncryption);
|
||||
this.forEncryption = forEncryption;
|
||||
return;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("invalid parameter passed to AES init - " + params.getClass().getName());
|
||||
}
|
||||
|
||||
public String getAlgorithmName()
|
||||
{
|
||||
return "AES";
|
||||
}
|
||||
|
||||
public int getBlockSize()
|
||||
{
|
||||
return BLOCK_SIZE;
|
||||
}
|
||||
|
||||
public int processBlock(
|
||||
byte[] in,
|
||||
int inOff,
|
||||
byte[] out,
|
||||
int outOff)
|
||||
{
|
||||
if (WorkingKey == null)
|
||||
{
|
||||
throw new IllegalStateException("AES engine not initialised");
|
||||
}
|
||||
|
||||
if ((inOff + (32 / 2)) > in.length)
|
||||
{
|
||||
throw new DataLengthException("input buffer too short");
|
||||
}
|
||||
|
||||
if ((outOff + (32 / 2)) > out.length)
|
||||
{
|
||||
throw new DataLengthException("output buffer too short");
|
||||
}
|
||||
|
||||
if (forEncryption)
|
||||
{
|
||||
unpackBlock(in, inOff);
|
||||
encryptBlock(WorkingKey);
|
||||
packBlock(out, outOff);
|
||||
}
|
||||
else
|
||||
{
|
||||
unpackBlock(in, inOff);
|
||||
decryptBlock(WorkingKey);
|
||||
packBlock(out, outOff);
|
||||
}
|
||||
|
||||
return BLOCK_SIZE;
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
}
|
||||
|
||||
private final void unpackBlock(
|
||||
byte[] bytes,
|
||||
int off)
|
||||
{
|
||||
int index = off;
|
||||
|
||||
C0 = (bytes[index++] & 0xff);
|
||||
C0 |= (bytes[index++] & 0xff) << 8;
|
||||
C0 |= (bytes[index++] & 0xff) << 16;
|
||||
C0 |= bytes[index++] << 24;
|
||||
|
||||
C1 = (bytes[index++] & 0xff);
|
||||
C1 |= (bytes[index++] & 0xff) << 8;
|
||||
C1 |= (bytes[index++] & 0xff) << 16;
|
||||
C1 |= bytes[index++] << 24;
|
||||
|
||||
C2 = (bytes[index++] & 0xff);
|
||||
C2 |= (bytes[index++] & 0xff) << 8;
|
||||
C2 |= (bytes[index++] & 0xff) << 16;
|
||||
C2 |= bytes[index++] << 24;
|
||||
|
||||
C3 = (bytes[index++] & 0xff);
|
||||
C3 |= (bytes[index++] & 0xff) << 8;
|
||||
C3 |= (bytes[index++] & 0xff) << 16;
|
||||
C3 |= bytes[index++] << 24;
|
||||
}
|
||||
|
||||
private final void packBlock(
|
||||
byte[] bytes,
|
||||
int off)
|
||||
{
|
||||
int index = off;
|
||||
|
||||
bytes[index++] = (byte)C0;
|
||||
bytes[index++] = (byte)(C0 >> 8);
|
||||
bytes[index++] = (byte)(C0 >> 16);
|
||||
bytes[index++] = (byte)(C0 >> 24);
|
||||
|
||||
bytes[index++] = (byte)C1;
|
||||
bytes[index++] = (byte)(C1 >> 8);
|
||||
bytes[index++] = (byte)(C1 >> 16);
|
||||
bytes[index++] = (byte)(C1 >> 24);
|
||||
|
||||
bytes[index++] = (byte)C2;
|
||||
bytes[index++] = (byte)(C2 >> 8);
|
||||
bytes[index++] = (byte)(C2 >> 16);
|
||||
bytes[index++] = (byte)(C2 >> 24);
|
||||
|
||||
bytes[index++] = (byte)C3;
|
||||
bytes[index++] = (byte)(C3 >> 8);
|
||||
bytes[index++] = (byte)(C3 >> 16);
|
||||
bytes[index++] = (byte)(C3 >> 24);
|
||||
}
|
||||
|
||||
|
||||
private final void encryptBlock(int[][] KW)
|
||||
{
|
||||
int r, r0, r1, r2, r3;
|
||||
|
||||
C0 ^= KW[0][0];
|
||||
C1 ^= KW[0][1];
|
||||
C2 ^= KW[0][2];
|
||||
C3 ^= KW[0][3];
|
||||
|
||||
r = 1;
|
||||
|
||||
while (r < ROUNDS - 1)
|
||||
{
|
||||
r0 = T0[C0&255] ^ shift(T0[(C1>>8)&255], 24) ^ shift(T0[(C2>>16)&255],16) ^ shift(T0[(C3>>24)&255],8) ^ KW[r][0];
|
||||
r1 = T0[C1&255] ^ shift(T0[(C2>>8)&255], 24) ^ shift(T0[(C3>>16)&255], 16) ^ shift(T0[(C0>>24)&255], 8) ^ KW[r][1];
|
||||
r2 = T0[C2&255] ^ shift(T0[(C3>>8)&255], 24) ^ shift(T0[(C0>>16)&255], 16) ^ shift(T0[(C1>>24)&255], 8) ^ KW[r][2];
|
||||
r3 = T0[C3&255] ^ shift(T0[(C0>>8)&255], 24) ^ shift(T0[(C1>>16)&255], 16) ^ shift(T0[(C2>>24)&255], 8) ^ KW[r++][3];
|
||||
C0 = T0[r0&255] ^ shift(T0[(r1>>8)&255], 24) ^ shift(T0[(r2>>16)&255], 16) ^ shift(T0[(r3>>24)&255], 8) ^ KW[r][0];
|
||||
C1 = T0[r1&255] ^ shift(T0[(r2>>8)&255], 24) ^ shift(T0[(r3>>16)&255], 16) ^ shift(T0[(r0>>24)&255], 8) ^ KW[r][1];
|
||||
C2 = T0[r2&255] ^ shift(T0[(r3>>8)&255], 24) ^ shift(T0[(r0>>16)&255], 16) ^ shift(T0[(r1>>24)&255], 8) ^ KW[r][2];
|
||||
C3 = T0[r3&255] ^ shift(T0[(r0>>8)&255], 24) ^ shift(T0[(r1>>16)&255], 16) ^ shift(T0[(r2>>24)&255], 8) ^ KW[r++][3];
|
||||
}
|
||||
|
||||
r0 = T0[C0&255] ^ shift(T0[(C1>>8)&255], 24) ^ shift(T0[(C2>>16)&255], 16) ^ shift(T0[(C3>>24)&255], 8) ^ KW[r][0];
|
||||
r1 = T0[C1&255] ^ shift(T0[(C2>>8)&255], 24) ^ shift(T0[(C3>>16)&255], 16) ^ shift(T0[(C0>>24)&255], 8) ^ KW[r][1];
|
||||
r2 = T0[C2&255] ^ shift(T0[(C3>>8)&255], 24) ^ shift(T0[(C0>>16)&255], 16) ^ shift(T0[(C1>>24)&255], 8) ^ KW[r][2];
|
||||
r3 = T0[C3&255] ^ shift(T0[(C0>>8)&255], 24) ^ shift(T0[(C1>>16)&255], 16) ^ shift(T0[(C2>>24)&255], 8) ^ KW[r++][3];
|
||||
|
||||
// the final round's table is a simple function of S so we don't use a whole other four tables for it
|
||||
|
||||
C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r][0];
|
||||
C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r][1];
|
||||
C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r][2];
|
||||
C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r][3];
|
||||
|
||||
}
|
||||
|
||||
private final void decryptBlock(int[][] KW)
|
||||
{
|
||||
int r, r0, r1, r2, r3;
|
||||
|
||||
C0 ^= KW[ROUNDS][0];
|
||||
C1 ^= KW[ROUNDS][1];
|
||||
C2 ^= KW[ROUNDS][2];
|
||||
C3 ^= KW[ROUNDS][3];
|
||||
|
||||
r = ROUNDS-1;
|
||||
|
||||
while (r>1)
|
||||
{
|
||||
r0 = Tinv0[C0&255] ^ shift(Tinv0[(C3>>8)&255], 24) ^ shift(Tinv0[(C2>>16)&255], 16) ^ shift(Tinv0[(C1>>24)&255], 8) ^ KW[r][0];
|
||||
r1 = Tinv0[C1&255] ^ shift(Tinv0[(C0>>8)&255], 24) ^ shift(Tinv0[(C3>>16)&255], 16) ^ shift(Tinv0[(C2>>24)&255], 8) ^ KW[r][1];
|
||||
r2 = Tinv0[C2&255] ^ shift(Tinv0[(C1>>8)&255], 24) ^ shift(Tinv0[(C0>>16)&255], 16) ^ shift(Tinv0[(C3>>24)&255], 8) ^ KW[r][2];
|
||||
r3 = Tinv0[C3&255] ^ shift(Tinv0[(C2>>8)&255], 24) ^ shift(Tinv0[(C1>>16)&255], 16) ^ shift(Tinv0[(C0>>24)&255], 8) ^ KW[r--][3];
|
||||
C0 = Tinv0[r0&255] ^ shift(Tinv0[(r3>>8)&255], 24) ^ shift(Tinv0[(r2>>16)&255], 16) ^ shift(Tinv0[(r1>>24)&255], 8) ^ KW[r][0];
|
||||
C1 = Tinv0[r1&255] ^ shift(Tinv0[(r0>>8)&255], 24) ^ shift(Tinv0[(r3>>16)&255], 16) ^ shift(Tinv0[(r2>>24)&255], 8) ^ KW[r][1];
|
||||
C2 = Tinv0[r2&255] ^ shift(Tinv0[(r1>>8)&255], 24) ^ shift(Tinv0[(r0>>16)&255], 16) ^ shift(Tinv0[(r3>>24)&255], 8) ^ KW[r][2];
|
||||
C3 = Tinv0[r3&255] ^ shift(Tinv0[(r2>>8)&255], 24) ^ shift(Tinv0[(r1>>16)&255], 16) ^ shift(Tinv0[(r0>>24)&255], 8) ^ KW[r--][3];
|
||||
}
|
||||
|
||||
r0 = Tinv0[C0&255] ^ shift(Tinv0[(C3>>8)&255], 24) ^ shift(Tinv0[(C2>>16)&255], 16) ^ shift(Tinv0[(C1>>24)&255], 8) ^ KW[r][0];
|
||||
r1 = Tinv0[C1&255] ^ shift(Tinv0[(C0>>8)&255], 24) ^ shift(Tinv0[(C3>>16)&255], 16) ^ shift(Tinv0[(C2>>24)&255], 8) ^ KW[r][1];
|
||||
r2 = Tinv0[C2&255] ^ shift(Tinv0[(C1>>8)&255], 24) ^ shift(Tinv0[(C0>>16)&255], 16) ^ shift(Tinv0[(C3>>24)&255], 8) ^ KW[r][2];
|
||||
r3 = Tinv0[C3&255] ^ shift(Tinv0[(C2>>8)&255], 24) ^ shift(Tinv0[(C1>>16)&255], 16) ^ shift(Tinv0[(C0>>24)&255], 8) ^ KW[r][3];
|
||||
|
||||
// the final round's table is a simple function of Si so we don't use a whole other four tables for it
|
||||
|
||||
C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0][0];
|
||||
C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0][1];
|
||||
C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0][2];
|
||||
C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0][3];
|
||||
}
|
||||
}
|
677
src/org/bouncycastle1/crypto/engines/TwofishEngine.java
Normal file
677
src/org/bouncycastle1/crypto/engines/TwofishEngine.java
Normal file
|
@ -0,0 +1,677 @@
|
|||
package org.bouncycastle1.crypto.engines;
|
||||
|
||||
import org.bouncycastle1.crypto.BlockCipher;
|
||||
import org.bouncycastle1.crypto.CipherParameters;
|
||||
import org.bouncycastle1.crypto.DataLengthException;
|
||||
import org.bouncycastle1.crypto.params.KeyParameter;
|
||||
|
||||
/**
|
||||
* A class that provides Twofish encryption operations.
|
||||
*
|
||||
* This Java implementation is based on the Java reference
|
||||
* implementation provided by Bruce Schneier and developed
|
||||
* by Raif S. Naffah.
|
||||
*/
|
||||
public final class TwofishEngine
|
||||
implements BlockCipher
|
||||
{
|
||||
private static final byte[][] P = {
|
||||
{ // p0
|
||||
(byte) 0xA9, (byte) 0x67, (byte) 0xB3, (byte) 0xE8,
|
||||
(byte) 0x04, (byte) 0xFD, (byte) 0xA3, (byte) 0x76,
|
||||
(byte) 0x9A, (byte) 0x92, (byte) 0x80, (byte) 0x78,
|
||||
(byte) 0xE4, (byte) 0xDD, (byte) 0xD1, (byte) 0x38,
|
||||
(byte) 0x0D, (byte) 0xC6, (byte) 0x35, (byte) 0x98,
|
||||
(byte) 0x18, (byte) 0xF7, (byte) 0xEC, (byte) 0x6C,
|
||||
(byte) 0x43, (byte) 0x75, (byte) 0x37, (byte) 0x26,
|
||||
(byte) 0xFA, (byte) 0x13, (byte) 0x94, (byte) 0x48,
|
||||
(byte) 0xF2, (byte) 0xD0, (byte) 0x8B, (byte) 0x30,
|
||||
(byte) 0x84, (byte) 0x54, (byte) 0xDF, (byte) 0x23,
|
||||
(byte) 0x19, (byte) 0x5B, (byte) 0x3D, (byte) 0x59,
|
||||
(byte) 0xF3, (byte) 0xAE, (byte) 0xA2, (byte) 0x82,
|
||||
(byte) 0x63, (byte) 0x01, (byte) 0x83, (byte) 0x2E,
|
||||
(byte) 0xD9, (byte) 0x51, (byte) 0x9B, (byte) 0x7C,
|
||||
(byte) 0xA6, (byte) 0xEB, (byte) 0xA5, (byte) 0xBE,
|
||||
(byte) 0x16, (byte) 0x0C, (byte) 0xE3, (byte) 0x61,
|
||||
(byte) 0xC0, (byte) 0x8C, (byte) 0x3A, (byte) 0xF5,
|
||||
(byte) 0x73, (byte) 0x2C, (byte) 0x25, (byte) 0x0B,
|
||||
(byte) 0xBB, (byte) 0x4E, (byte) 0x89, (byte) 0x6B,
|
||||
(byte) 0x53, (byte) 0x6A, (byte) 0xB4, (byte) 0xF1,
|
||||
(byte) 0xE1, (byte) 0xE6, (byte) 0xBD, (byte) 0x45,
|
||||
(byte) 0xE2, (byte) 0xF4, (byte) 0xB6, (byte) 0x66,
|
||||
(byte) 0xCC, (byte) 0x95, (byte) 0x03, (byte) 0x56,
|
||||
(byte) 0xD4, (byte) 0x1C, (byte) 0x1E, (byte) 0xD7,
|
||||
(byte) 0xFB, (byte) 0xC3, (byte) 0x8E, (byte) 0xB5,
|
||||
(byte) 0xE9, (byte) 0xCF, (byte) 0xBF, (byte) 0xBA,
|
||||
(byte) 0xEA, (byte) 0x77, (byte) 0x39, (byte) 0xAF,
|
||||
(byte) 0x33, (byte) 0xC9, (byte) 0x62, (byte) 0x71,
|
||||
(byte) 0x81, (byte) 0x79, (byte) 0x09, (byte) 0xAD,
|
||||
(byte) 0x24, (byte) 0xCD, (byte) 0xF9, (byte) 0xD8,
|
||||
(byte) 0xE5, (byte) 0xC5, (byte) 0xB9, (byte) 0x4D,
|
||||
(byte) 0x44, (byte) 0x08, (byte) 0x86, (byte) 0xE7,
|
||||
(byte) 0xA1, (byte) 0x1D, (byte) 0xAA, (byte) 0xED,
|
||||
(byte) 0x06, (byte) 0x70, (byte) 0xB2, (byte) 0xD2,
|
||||
(byte) 0x41, (byte) 0x7B, (byte) 0xA0, (byte) 0x11,
|
||||
(byte) 0x31, (byte) 0xC2, (byte) 0x27, (byte) 0x90,
|
||||
(byte) 0x20, (byte) 0xF6, (byte) 0x60, (byte) 0xFF,
|
||||
(byte) 0x96, (byte) 0x5C, (byte) 0xB1, (byte) 0xAB,
|
||||
(byte) 0x9E, (byte) 0x9C, (byte) 0x52, (byte) 0x1B,
|
||||
(byte) 0x5F, (byte) 0x93, (byte) 0x0A, (byte) 0xEF,
|
||||
(byte) 0x91, (byte) 0x85, (byte) 0x49, (byte) 0xEE,
|
||||
(byte) 0x2D, (byte) 0x4F, (byte) 0x8F, (byte) 0x3B,
|
||||
(byte) 0x47, (byte) 0x87, (byte) 0x6D, (byte) 0x46,
|
||||
(byte) 0xD6, (byte) 0x3E, (byte) 0x69, (byte) 0x64,
|
||||
(byte) 0x2A, (byte) 0xCE, (byte) 0xCB, (byte) 0x2F,
|
||||
(byte) 0xFC, (byte) 0x97, (byte) 0x05, (byte) 0x7A,
|
||||
(byte) 0xAC, (byte) 0x7F, (byte) 0xD5, (byte) 0x1A,
|
||||
(byte) 0x4B, (byte) 0x0E, (byte) 0xA7, (byte) 0x5A,
|
||||
(byte) 0x28, (byte) 0x14, (byte) 0x3F, (byte) 0x29,
|
||||
(byte) 0x88, (byte) 0x3C, (byte) 0x4C, (byte) 0x02,
|
||||
(byte) 0xB8, (byte) 0xDA, (byte) 0xB0, (byte) 0x17,
|
||||
(byte) 0x55, (byte) 0x1F, (byte) 0x8A, (byte) 0x7D,
|
||||
(byte) 0x57, (byte) 0xC7, (byte) 0x8D, (byte) 0x74,
|
||||
(byte) 0xB7, (byte) 0xC4, (byte) 0x9F, (byte) 0x72,
|
||||
(byte) 0x7E, (byte) 0x15, (byte) 0x22, (byte) 0x12,
|
||||
(byte) 0x58, (byte) 0x07, (byte) 0x99, (byte) 0x34,
|
||||
(byte) 0x6E, (byte) 0x50, (byte) 0xDE, (byte) 0x68,
|
||||
(byte) 0x65, (byte) 0xBC, (byte) 0xDB, (byte) 0xF8,
|
||||
(byte) 0xC8, (byte) 0xA8, (byte) 0x2B, (byte) 0x40,
|
||||
(byte) 0xDC, (byte) 0xFE, (byte) 0x32, (byte) 0xA4,
|
||||
(byte) 0xCA, (byte) 0x10, (byte) 0x21, (byte) 0xF0,
|
||||
(byte) 0xD3, (byte) 0x5D, (byte) 0x0F, (byte) 0x00,
|
||||
(byte) 0x6F, (byte) 0x9D, (byte) 0x36, (byte) 0x42,
|
||||
(byte) 0x4A, (byte) 0x5E, (byte) 0xC1, (byte) 0xE0 },
|
||||
{ // p1
|
||||
(byte) 0x75, (byte) 0xF3, (byte) 0xC6, (byte) 0xF4,
|
||||
(byte) 0xDB, (byte) 0x7B, (byte) 0xFB, (byte) 0xC8,
|
||||
(byte) 0x4A, (byte) 0xD3, (byte) 0xE6, (byte) 0x6B,
|
||||
(byte) 0x45, (byte) 0x7D, (byte) 0xE8, (byte) 0x4B,
|
||||
(byte) 0xD6, (byte) 0x32, (byte) 0xD8, (byte) 0xFD,
|
||||
(byte) 0x37, (byte) 0x71, (byte) 0xF1, (byte) 0xE1,
|
||||
(byte) 0x30, (byte) 0x0F, (byte) 0xF8, (byte) 0x1B,
|
||||
(byte) 0x87, (byte) 0xFA, (byte) 0x06, (byte) 0x3F,
|
||||
(byte) 0x5E, (byte) 0xBA, (byte) 0xAE, (byte) 0x5B,
|
||||
(byte) 0x8A, (byte) 0x00, (byte) 0xBC, (byte) 0x9D,
|
||||
(byte) 0x6D, (byte) 0xC1, (byte) 0xB1, (byte) 0x0E,
|
||||
(byte) 0x80, (byte) 0x5D, (byte) 0xD2, (byte) 0xD5,
|
||||
(byte) 0xA0, (byte) 0x84, (byte) 0x07, (byte) 0x14,
|
||||
(byte) 0xB5, (byte) 0x90, (byte) 0x2C, (byte) 0xA3,
|
||||
(byte) 0xB2, (byte) 0x73, (byte) 0x4C, (byte) 0x54,
|
||||
(byte) 0x92, (byte) 0x74, (byte) 0x36, (byte) 0x51,
|
||||
(byte) 0x38, (byte) 0xB0, (byte) 0xBD, (byte) 0x5A,
|
||||
(byte) 0xFC, (byte) 0x60, (byte) 0x62, (byte) 0x96,
|
||||
(byte) 0x6C, (byte) 0x42, (byte) 0xF7, (byte) 0x10,
|
||||
(byte) 0x7C, (byte) 0x28, (byte) 0x27, (byte) 0x8C,
|
||||
(byte) 0x13, (byte) 0x95, (byte) 0x9C, (byte) 0xC7,
|
||||
(byte) 0x24, (byte) 0x46, (byte) 0x3B, (byte) 0x70,
|
||||
(byte) 0xCA, (byte) 0xE3, (byte) 0x85, (byte) 0xCB,
|
||||
(byte) 0x11, (byte) 0xD0, (byte) 0x93, (byte) 0xB8,
|
||||
(byte) 0xA6, (byte) 0x83, (byte) 0x20, (byte) 0xFF,
|
||||
(byte) 0x9F, (byte) 0x77, (byte) 0xC3, (byte) 0xCC,
|
||||
(byte) 0x03, (byte) 0x6F, (byte) 0x08, (byte) 0xBF,
|
||||
(byte) 0x40, (byte) 0xE7, (byte) 0x2B, (byte) 0xE2,
|
||||
(byte) 0x79, (byte) 0x0C, (byte) 0xAA, (byte) 0x82,
|
||||
(byte) 0x41, (byte) 0x3A, (byte) 0xEA, (byte) 0xB9,
|
||||
(byte) 0xE4, (byte) 0x9A, (byte) 0xA4, (byte) 0x97,
|
||||
(byte) 0x7E, (byte) 0xDA, (byte) 0x7A, (byte) 0x17,
|
||||
(byte) 0x66, (byte) 0x94, (byte) 0xA1, (byte) 0x1D,
|
||||
(byte) 0x3D, (byte) 0xF0, (byte) 0xDE, (byte) 0xB3,
|
||||
(byte) 0x0B, (byte) 0x72, (byte) 0xA7, (byte) 0x1C,
|
||||
(byte) 0xEF, (byte) 0xD1, (byte) 0x53, (byte) 0x3E,
|
||||
(byte) 0x8F, (byte) 0x33, (byte) 0x26, (byte) 0x5F,
|
||||
(byte) 0xEC, (byte) 0x76, (byte) 0x2A, (byte) 0x49,
|
||||
(byte) 0x81, (byte) 0x88, (byte) 0xEE, (byte) 0x21,
|
||||
(byte) 0xC4, (byte) 0x1A, (byte) 0xEB, (byte) 0xD9,
|
||||
(byte) 0xC5, (byte) 0x39, (byte) 0x99, (byte) 0xCD,
|
||||
(byte) 0xAD, (byte) 0x31, (byte) 0x8B, (byte) 0x01,
|
||||
(byte) 0x18, (byte) 0x23, (byte) 0xDD, (byte) 0x1F,
|
||||
(byte) 0x4E, (byte) 0x2D, (byte) 0xF9, (byte) 0x48,
|
||||
(byte) 0x4F, (byte) 0xF2, (byte) 0x65, (byte) 0x8E,
|
||||
(byte) 0x78, (byte) 0x5C, (byte) 0x58, (byte) 0x19,
|
||||
(byte) 0x8D, (byte) 0xE5, (byte) 0x98, (byte) 0x57,
|
||||
(byte) 0x67, (byte) 0x7F, (byte) 0x05, (byte) 0x64,
|
||||
(byte) 0xAF, (byte) 0x63, (byte) 0xB6, (byte) 0xFE,
|
||||
(byte) 0xF5, (byte) 0xB7, (byte) 0x3C, (byte) 0xA5,
|
||||
(byte) 0xCE, (byte) 0xE9, (byte) 0x68, (byte) 0x44,
|
||||
(byte) 0xE0, (byte) 0x4D, (byte) 0x43, (byte) 0x69,
|
||||
(byte) 0x29, (byte) 0x2E, (byte) 0xAC, (byte) 0x15,
|
||||
(byte) 0x59, (byte) 0xA8, (byte) 0x0A, (byte) 0x9E,
|
||||
(byte) 0x6E, (byte) 0x47, (byte) 0xDF, (byte) 0x34,
|
||||
(byte) 0x35, (byte) 0x6A, (byte) 0xCF, (byte) 0xDC,
|
||||
(byte) 0x22, (byte) 0xC9, (byte) 0xC0, (byte) 0x9B,
|
||||
(byte) 0x89, (byte) 0xD4, (byte) 0xED, (byte) 0xAB,
|
||||
(byte) 0x12, (byte) 0xA2, (byte) 0x0D, (byte) 0x52,
|
||||
(byte) 0xBB, (byte) 0x02, (byte) 0x2F, (byte) 0xA9,
|
||||
(byte) 0xD7, (byte) 0x61, (byte) 0x1E, (byte) 0xB4,
|
||||
(byte) 0x50, (byte) 0x04, (byte) 0xF6, (byte) 0xC2,
|
||||
(byte) 0x16, (byte) 0x25, (byte) 0x86, (byte) 0x56,
|
||||
(byte) 0x55, (byte) 0x09, (byte) 0xBE, (byte) 0x91 }
|
||||
};
|
||||
|
||||
/**
|
||||
* Define the fixed p0/p1 permutations used in keyed S-box lookup.
|
||||
* By changing the following constant definitions, the S-boxes will
|
||||
* automatically get changed in the Twofish engine.
|
||||
*/
|
||||
private static final int P_00 = 1;
|
||||
private static final int P_01 = 0;
|
||||
private static final int P_02 = 0;
|
||||
private static final int P_03 = P_01 ^ 1;
|
||||
private static final int P_04 = 1;
|
||||
|
||||
private static final int P_10 = 0;
|
||||
private static final int P_11 = 0;
|
||||
private static final int P_12 = 1;
|
||||
private static final int P_13 = P_11 ^ 1;
|
||||
private static final int P_14 = 0;
|
||||
|
||||
private static final int P_20 = 1;
|
||||
private static final int P_21 = 1;
|
||||
private static final int P_22 = 0;
|
||||
private static final int P_23 = P_21 ^ 1;
|
||||
private static final int P_24 = 0;
|
||||
|
||||
private static final int P_30 = 0;
|
||||
private static final int P_31 = 1;
|
||||
private static final int P_32 = 1;
|
||||
private static final int P_33 = P_31 ^ 1;
|
||||
private static final int P_34 = 1;
|
||||
|
||||
/* Primitive polynomial for GF(256) */
|
||||
private static final int GF256_FDBK = 0x169;
|
||||
private static final int GF256_FDBK_2 = GF256_FDBK / 2;
|
||||
private static final int GF256_FDBK_4 = GF256_FDBK / 4;
|
||||
|
||||
private static final int RS_GF_FDBK = 0x14D; // field generator
|
||||
|
||||
//====================================
|
||||
// Useful constants
|
||||
//====================================
|
||||
|
||||
private static final int ROUNDS = 16;
|
||||
private static final int MAX_ROUNDS = 16; // bytes = 128 bits
|
||||
private static final int BLOCK_SIZE = 16; // bytes = 128 bits
|
||||
private static final int MAX_KEY_BITS = 256;
|
||||
|
||||
private static final int INPUT_WHITEN=0;
|
||||
private static final int OUTPUT_WHITEN=INPUT_WHITEN+BLOCK_SIZE/4; // 4
|
||||
private static final int ROUND_SUBKEYS=OUTPUT_WHITEN+BLOCK_SIZE/4;// 8
|
||||
|
||||
private static final int TOTAL_SUBKEYS=ROUND_SUBKEYS+2*MAX_ROUNDS;// 40
|
||||
|
||||
private static final int SK_STEP = 0x02020202;
|
||||
private static final int SK_BUMP = 0x01010101;
|
||||
private static final int SK_ROTL = 9;
|
||||
|
||||
private boolean encrypting = false;
|
||||
|
||||
private int[] gMDS0 = new int[MAX_KEY_BITS];
|
||||
private int[] gMDS1 = new int[MAX_KEY_BITS];
|
||||
private int[] gMDS2 = new int[MAX_KEY_BITS];
|
||||
private int[] gMDS3 = new int[MAX_KEY_BITS];
|
||||
|
||||
/**
|
||||
* gSubKeys[] and gSBox[] are eventually used in the
|
||||
* encryption and decryption methods.
|
||||
*/
|
||||
private int[] gSubKeys;
|
||||
private int[] gSBox;
|
||||
|
||||
private int k64Cnt = 0;
|
||||
|
||||
private byte[] workingKey = null;
|
||||
|
||||
public TwofishEngine()
|
||||
{
|
||||
// calculate the MDS matrix
|
||||
int[] m1 = new int[2];
|
||||
int[] mX = new int[2];
|
||||
int[] mY = new int[2];
|
||||
int j;
|
||||
|
||||
for (int i=0; i< MAX_KEY_BITS ; i++)
|
||||
{
|
||||
j = P[0][i] & 0xff;
|
||||
m1[0] = j;
|
||||
mX[0] = Mx_X(j) & 0xff;
|
||||
mY[0] = Mx_Y(j) & 0xff;
|
||||
|
||||
j = P[1][i] & 0xff;
|
||||
m1[1] = j;
|
||||
mX[1] = Mx_X(j) & 0xff;
|
||||
mY[1] = Mx_Y(j) & 0xff;
|
||||
|
||||
gMDS0[i] = m1[P_00] | mX[P_00] << 8 |
|
||||
mY[P_00] << 16 | mY[P_00] << 24;
|
||||
|
||||
gMDS1[i] = mY[P_10] | mY[P_10] << 8 |
|
||||
mX[P_10] << 16 | m1[P_10] << 24;
|
||||
|
||||
gMDS2[i] = mX[P_20] | mY[P_20] << 8 |
|
||||
m1[P_20] << 16 | mY[P_20] << 24;
|
||||
|
||||
gMDS3[i] = mX[P_30] | m1[P_30] << 8 |
|
||||
mY[P_30] << 16 | mX[P_30] << 24;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* initialise a Twofish cipher.
|
||||
*
|
||||
* @param encrypting whether or not we are for encryption.
|
||||
* @param params the parameters required to set up the cipher.
|
||||
* @exception IllegalArgumentException if the params argument is
|
||||
* inappropriate.
|
||||
*/
|
||||
public void init(
|
||||
boolean encrypting,
|
||||
CipherParameters params)
|
||||
{
|
||||
if (params instanceof KeyParameter)
|
||||
{
|
||||
this.encrypting = encrypting;
|
||||
this.workingKey = ((KeyParameter)params).getKey();
|
||||
this.k64Cnt = (this.workingKey.length / 8); // pre-padded ?
|
||||
setKey(this.workingKey);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("invalid parameter passed to Twofish init - " + params.getClass().getName());
|
||||
}
|
||||
|
||||
public String getAlgorithmName()
|
||||
{
|
||||
return "Twofish";
|
||||
}
|
||||
|
||||
public final int processBlock(
|
||||
byte[] in,
|
||||
int inOff,
|
||||
byte[] out,
|
||||
int outOff)
|
||||
{
|
||||
if (workingKey == null)
|
||||
{
|
||||
throw new IllegalStateException("Twofish not initialised");
|
||||
}
|
||||
|
||||
if ((inOff + BLOCK_SIZE) > in.length)
|
||||
{
|
||||
throw new DataLengthException("input buffer too short");
|
||||
}
|
||||
|
||||
if ((outOff + BLOCK_SIZE) > out.length)
|
||||
{
|
||||
throw new DataLengthException("output buffer too short");
|
||||
}
|
||||
|
||||
if (encrypting)
|
||||
{
|
||||
encryptBlock(in, inOff, out, outOff);
|
||||
}
|
||||
else
|
||||
{
|
||||
decryptBlock(in, inOff, out, outOff);
|
||||
}
|
||||
|
||||
return BLOCK_SIZE;
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
if (this.workingKey != null)
|
||||
{
|
||||
setKey(this.workingKey);
|
||||
}
|
||||
}
|
||||
|
||||
public int getBlockSize()
|
||||
{
|
||||
return BLOCK_SIZE;
|
||||
}
|
||||
|
||||
//==================================
|
||||
// Private Implementation
|
||||
//==================================
|
||||
|
||||
private void setKey(byte[] key)
|
||||
{
|
||||
int[] k32e = new int[MAX_KEY_BITS/64]; // 4
|
||||
int[] k32o = new int[MAX_KEY_BITS/64]; // 4
|
||||
|
||||
int[] sBoxKeys = new int[MAX_KEY_BITS/64]; // 4
|
||||
gSubKeys = new int[TOTAL_SUBKEYS];
|
||||
|
||||
if (k64Cnt < 1)
|
||||
{
|
||||
throw new IllegalArgumentException("Key size less than 64 bits");
|
||||
}
|
||||
|
||||
if (k64Cnt > 4)
|
||||
{
|
||||
throw new IllegalArgumentException("Key size larger than 256 bits");
|
||||
}
|
||||
|
||||
/*
|
||||
* k64Cnt is the number of 8 byte blocks (64 chunks)
|
||||
* that are in the input key. The input key is a
|
||||
* maximum of 32 bytes (256 bits), so the range
|
||||
* for k64Cnt is 1..4
|
||||
*/
|
||||
for (int i=0; i<k64Cnt ; i++)
|
||||
{
|
||||
int p = i* 8;
|
||||
|
||||
k32e[i] = BytesTo32Bits(key, p);
|
||||
k32o[i] = BytesTo32Bits(key, p+4);
|
||||
|
||||
sBoxKeys[k64Cnt-1-i] = RS_MDS_Encode(k32e[i], k32o[i]);
|
||||
}
|
||||
|
||||
int q,A,B;
|
||||
for (int i=0; i < TOTAL_SUBKEYS / 2 ; i++)
|
||||
{
|
||||
q = i*SK_STEP;
|
||||
A = F32(q, k32e);
|
||||
B = F32(q+SK_BUMP, k32o);
|
||||
B = B << 8 | B >>> 24;
|
||||
A += B;
|
||||
gSubKeys[i*2] = A;
|
||||
A += B;
|
||||
gSubKeys[i*2 + 1] = A << SK_ROTL | A >>> (32-SK_ROTL);
|
||||
}
|
||||
|
||||
/*
|
||||
* fully expand the table for speed
|
||||
*/
|
||||
int k0 = sBoxKeys[0];
|
||||
int k1 = sBoxKeys[1];
|
||||
int k2 = sBoxKeys[2];
|
||||
int k3 = sBoxKeys[3];
|
||||
int b0, b1, b2, b3;
|
||||
gSBox = new int[4*MAX_KEY_BITS];
|
||||
for (int i=0; i<MAX_KEY_BITS; i++)
|
||||
{
|
||||
b0 = b1 = b2 = b3 = i;
|
||||
switch (k64Cnt & 3)
|
||||
{
|
||||
case 1:
|
||||
gSBox[i*2] = gMDS0[(P[P_01][b0] & 0xff) ^ b0(k0)];
|
||||
gSBox[i*2+1] = gMDS1[(P[P_11][b1] & 0xff) ^ b1(k0)];
|
||||
gSBox[i*2+0x200] = gMDS2[(P[P_21][b2] & 0xff) ^ b2(k0)];
|
||||
gSBox[i*2+0x201] = gMDS3[(P[P_31][b3] & 0xff) ^ b3(k0)];
|
||||
break;
|
||||
case 0: /* 256 bits of key */
|
||||
b0 = (P[P_04][b0] & 0xff) ^ b0(k3);
|
||||
b1 = (P[P_14][b1] & 0xff) ^ b1(k3);
|
||||
b2 = (P[P_24][b2] & 0xff) ^ b2(k3);
|
||||
b3 = (P[P_34][b3] & 0xff) ^ b3(k3);
|
||||
case 3:
|
||||
b0 = (P[P_03][b0] & 0xff) ^ b0(k2);
|
||||
b1 = (P[P_13][b1] & 0xff) ^ b1(k2);
|
||||
b2 = (P[P_23][b2] & 0xff) ^ b2(k2);
|
||||
b3 = (P[P_33][b3] & 0xff) ^ b3(k2);
|
||||
case 2:
|
||||
gSBox[i*2] = gMDS0[(P[P_01]
|
||||
[(P[P_02][b0] & 0xff) ^ b0(k1)] & 0xff) ^ b0(k0)];
|
||||
gSBox[i*2+1] = gMDS1[(P[P_11]
|
||||
[(P[P_12][b1] & 0xff) ^ b1(k1)] & 0xff) ^ b1(k0)];
|
||||
gSBox[i*2+0x200] = gMDS2[(P[P_21]
|
||||
[(P[P_22][b2] & 0xff) ^ b2(k1)] & 0xff) ^ b2(k0)];
|
||||
gSBox[i*2+0x201] = gMDS3[(P[P_31]
|
||||
[(P[P_32][b3] & 0xff) ^ b3(k1)] & 0xff) ^ b3(k0)];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* the function exits having setup the gSBox with the
|
||||
* input key material.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt the given input starting at the given offset and place
|
||||
* the result in the provided buffer starting at the given offset.
|
||||
* The input will be an exact multiple of our blocksize.
|
||||
*
|
||||
* encryptBlock uses the pre-calculated gSBox[] and subKey[]
|
||||
* arrays.
|
||||
*/
|
||||
private void encryptBlock(
|
||||
byte[] src,
|
||||
int srcIndex,
|
||||
byte[] dst,
|
||||
int dstIndex)
|
||||
{
|
||||
int x0 = BytesTo32Bits(src, srcIndex) ^ gSubKeys[INPUT_WHITEN];
|
||||
int x1 = BytesTo32Bits(src, srcIndex + 4) ^ gSubKeys[INPUT_WHITEN + 1];
|
||||
int x2 = BytesTo32Bits(src, srcIndex + 8) ^ gSubKeys[INPUT_WHITEN + 2];
|
||||
int x3 = BytesTo32Bits(src, srcIndex + 12) ^ gSubKeys[INPUT_WHITEN + 3];
|
||||
|
||||
int k = ROUND_SUBKEYS;
|
||||
int t0, t1;
|
||||
for (int r = 0; r < ROUNDS; r +=2)
|
||||
{
|
||||
t0 = Fe32_0(x0);
|
||||
t1 = Fe32_3(x1);
|
||||
x2 ^= t0 + t1 + gSubKeys[k++];
|
||||
x2 = x2 >>>1 | x2 << 31;
|
||||
x3 = (x3 << 1 | x3 >>> 31) ^ (t0 + 2*t1 + gSubKeys[k++]);
|
||||
|
||||
t0 = Fe32_0(x2);
|
||||
t1 = Fe32_3(x3);
|
||||
x0 ^= t0 + t1 + gSubKeys[k++];
|
||||
x0 = x0 >>>1 | x0 << 31;
|
||||
x1 = (x1 << 1 | x1 >>> 31) ^ (t0 + 2*t1 + gSubKeys[k++]);
|
||||
}
|
||||
|
||||
Bits32ToBytes(x2 ^ gSubKeys[OUTPUT_WHITEN], dst, dstIndex);
|
||||
Bits32ToBytes(x3 ^ gSubKeys[OUTPUT_WHITEN + 1], dst, dstIndex + 4);
|
||||
Bits32ToBytes(x0 ^ gSubKeys[OUTPUT_WHITEN + 2], dst, dstIndex + 8);
|
||||
Bits32ToBytes(x1 ^ gSubKeys[OUTPUT_WHITEN + 3], dst, dstIndex + 12);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt the given input starting at the given offset and place
|
||||
* the result in the provided buffer starting at the given offset.
|
||||
* The input will be an exact multiple of our blocksize.
|
||||
*/
|
||||
private void decryptBlock(
|
||||
byte[] src,
|
||||
int srcIndex,
|
||||
byte[] dst,
|
||||
int dstIndex)
|
||||
{
|
||||
int x2 = BytesTo32Bits(src, srcIndex) ^ gSubKeys[OUTPUT_WHITEN];
|
||||
int x3 = BytesTo32Bits(src, srcIndex+4) ^ gSubKeys[OUTPUT_WHITEN + 1];
|
||||
int x0 = BytesTo32Bits(src, srcIndex+8) ^ gSubKeys[OUTPUT_WHITEN + 2];
|
||||
int x1 = BytesTo32Bits(src, srcIndex+12) ^ gSubKeys[OUTPUT_WHITEN + 3];
|
||||
|
||||
int k = ROUND_SUBKEYS + 2 * ROUNDS -1 ;
|
||||
int t0, t1;
|
||||
for (int r = 0; r< ROUNDS ; r +=2)
|
||||
{
|
||||
t0 = Fe32_0(x2);
|
||||
t1 = Fe32_3(x3);
|
||||
x1 ^= t0 + 2*t1 + gSubKeys[k--];
|
||||
x0 = (x0 << 1 | x0 >>> 31) ^ (t0 + t1 + gSubKeys[k--]);
|
||||
x1 = x1 >>>1 | x1 << 31;
|
||||
|
||||
t0 = Fe32_0(x0);
|
||||
t1 = Fe32_3(x1);
|
||||
x3 ^= t0 + 2*t1 + gSubKeys[k--];
|
||||
x2 = (x2 << 1 | x2 >>> 31) ^ (t0 + t1 + gSubKeys[k--]);
|
||||
x3 = x3 >>>1 | x3 << 31;
|
||||
}
|
||||
|
||||
Bits32ToBytes(x0 ^ gSubKeys[INPUT_WHITEN], dst, dstIndex);
|
||||
Bits32ToBytes(x1 ^ gSubKeys[INPUT_WHITEN + 1], dst, dstIndex + 4);
|
||||
Bits32ToBytes(x2 ^ gSubKeys[INPUT_WHITEN + 2], dst, dstIndex + 8);
|
||||
Bits32ToBytes(x3 ^ gSubKeys[INPUT_WHITEN + 3], dst, dstIndex + 12);
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: This can be optimised and made cleaner by combining
|
||||
* the functionality in this function and applying it appropriately
|
||||
* to the creation of the subkeys during key setup.
|
||||
*/
|
||||
private final int F32(int x, int[] k32)
|
||||
{
|
||||
int b0 = b0(x);
|
||||
int b1 = b1(x);
|
||||
int b2 = b2(x);
|
||||
int b3 = b3(x);
|
||||
int k0 = k32[0];
|
||||
int k1 = k32[1];
|
||||
int k2 = k32[2];
|
||||
int k3 = k32[3];
|
||||
|
||||
int result = 0;
|
||||
switch (k64Cnt & 3)
|
||||
{
|
||||
case 1:
|
||||
result = gMDS0[(P[P_01][b0] & 0xff) ^ b0(k0)] ^
|
||||
gMDS1[(P[P_11][b1] & 0xff) ^ b1(k0)] ^
|
||||
gMDS2[(P[P_21][b2] & 0xff) ^ b2(k0)] ^
|
||||
gMDS3[(P[P_31][b3] & 0xff) ^ b3(k0)];
|
||||
break;
|
||||
case 0: /* 256 bits of key */
|
||||
b0 = (P[P_04][b0] & 0xff) ^ b0(k3);
|
||||
b1 = (P[P_14][b1] & 0xff) ^ b1(k3);
|
||||
b2 = (P[P_24][b2] & 0xff) ^ b2(k3);
|
||||
b3 = (P[P_34][b3] & 0xff) ^ b3(k3);
|
||||
case 3:
|
||||
b0 = (P[P_03][b0] & 0xff) ^ b0(k2);
|
||||
b1 = (P[P_13][b1] & 0xff) ^ b1(k2);
|
||||
b2 = (P[P_23][b2] & 0xff) ^ b2(k2);
|
||||
b3 = (P[P_33][b3] & 0xff) ^ b3(k2);
|
||||
case 2:
|
||||
result =
|
||||
gMDS0[(P[P_01][(P[P_02][b0]&0xff)^b0(k1)]&0xff)^b0(k0)] ^
|
||||
gMDS1[(P[P_11][(P[P_12][b1]&0xff)^b1(k1)]&0xff)^b1(k0)] ^
|
||||
gMDS2[(P[P_21][(P[P_22][b2]&0xff)^b2(k1)]&0xff)^b2(k0)] ^
|
||||
gMDS3[(P[P_31][(P[P_32][b3]&0xff)^b3(k1)]&0xff)^b3(k0)];
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use (12, 8) Reed-Solomon code over GF(256) to produce
|
||||
* a key S-box 32-bit entity from 2 key material 32-bit
|
||||
* entities.
|
||||
*
|
||||
* @param k0 first 32-bit entity
|
||||
* @param k1 second 32-bit entity
|
||||
* @return Remainder polynomial generated using RS code
|
||||
*/
|
||||
private final int RS_MDS_Encode(int k0, int k1)
|
||||
{
|
||||
int r = k1;
|
||||
for (int i = 0 ; i < 4 ; i++) // shift 1 byte at a time
|
||||
{
|
||||
r = RS_rem(r);
|
||||
}
|
||||
r ^= k0;
|
||||
for (int i=0 ; i < 4 ; i++)
|
||||
{
|
||||
r = RS_rem(r);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reed-Solomon code parameters: (12,8) reversible code:<p>
|
||||
* <pre>
|
||||
* g(x) = x^4 + (a+1/a)x^3 + ax^2 + (a+1/a)x + 1
|
||||
* </pre>
|
||||
* where a = primitive root of field generator 0x14D
|
||||
*/
|
||||
private final int RS_rem(int x)
|
||||
{
|
||||
int b = (x >>> 24) & 0xff;
|
||||
int g2 = ((b << 1) ^
|
||||
((b & 0x80) != 0 ? RS_GF_FDBK : 0)) & 0xff;
|
||||
int g3 = ((b >>> 1) ^
|
||||
((b & 0x01) != 0 ? (RS_GF_FDBK >>> 1) : 0)) ^ g2 ;
|
||||
return ((x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b);
|
||||
}
|
||||
|
||||
private final int LFSR1(int x)
|
||||
{
|
||||
return (x >> 1) ^
|
||||
(((x & 0x01) != 0) ? GF256_FDBK_2 : 0);
|
||||
}
|
||||
|
||||
private final int LFSR2(int x)
|
||||
{
|
||||
return (x >> 2) ^
|
||||
(((x & 0x02) != 0) ? GF256_FDBK_2 : 0) ^
|
||||
(((x & 0x01) != 0) ? GF256_FDBK_4 : 0);
|
||||
}
|
||||
|
||||
private final int Mx_X(int x)
|
||||
{
|
||||
return x ^ LFSR2(x);
|
||||
} // 5B
|
||||
|
||||
private final int Mx_Y(int x)
|
||||
{
|
||||
return x ^ LFSR1(x) ^ LFSR2(x);
|
||||
} // EF
|
||||
|
||||
private final int b0(int x)
|
||||
{
|
||||
return x & 0xff;
|
||||
}
|
||||
|
||||
private final int b1(int x)
|
||||
{
|
||||
return (x >>> 8) & 0xff;
|
||||
}
|
||||
|
||||
private final int b2(int x)
|
||||
{
|
||||
return (x >>> 16) & 0xff;
|
||||
}
|
||||
|
||||
private final int b3(int x)
|
||||
{
|
||||
return (x >>> 24) & 0xff;
|
||||
}
|
||||
|
||||
private final int Fe32_0(int x)
|
||||
{
|
||||
return gSBox[ 0x000 + 2*(x & 0xff) ] ^
|
||||
gSBox[ 0x001 + 2*((x >>> 8) & 0xff) ] ^
|
||||
gSBox[ 0x200 + 2*((x >>> 16) & 0xff) ] ^
|
||||
gSBox[ 0x201 + 2*((x >>> 24) & 0xff) ];
|
||||
}
|
||||
|
||||
private final int Fe32_3(int x)
|
||||
{
|
||||
return gSBox[ 0x000 + 2*((x >>> 24) & 0xff) ] ^
|
||||
gSBox[ 0x001 + 2*(x & 0xff) ] ^
|
||||
gSBox[ 0x200 + 2*((x >>> 8) & 0xff) ] ^
|
||||
gSBox[ 0x201 + 2*((x >>> 16) & 0xff) ];
|
||||
}
|
||||
|
||||
private final int BytesTo32Bits(byte[] b, int p)
|
||||
{
|
||||
return ((b[p] & 0xff)) |
|
||||
((b[p+1] & 0xff) << 8) |
|
||||
((b[p+2] & 0xff) << 16) |
|
||||
((b[p+3] & 0xff) << 24);
|
||||
}
|
||||
|
||||
private final void Bits32ToBytes(int in, byte[] b, int offset)
|
||||
{
|
||||
b[offset] = (byte)in;
|
||||
b[offset + 1] = (byte)(in >> 8);
|
||||
b[offset + 2] = (byte)(in >> 16);
|
||||
b[offset + 3] = (byte)(in >> 24);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
package org.bouncycastle1.crypto.generators;
|
||||
|
||||
import org.bouncycastle1.crypto.CipherParameters;
|
||||
import org.bouncycastle1.crypto.Digest;
|
||||
import org.bouncycastle1.crypto.PBEParametersGenerator;
|
||||
import org.bouncycastle1.crypto.params.KeyParameter;
|
||||
import org.bouncycastle1.crypto.params.ParametersWithIV;
|
||||
|
||||
/**
|
||||
* Generator for PBE derived keys and ivs as defined by PKCS 5 V2.0 Scheme 1.
|
||||
* Note this generator is limited to the size of the hash produced by the
|
||||
* digest used to drive it.
|
||||
* <p>
|
||||
* The document this implementation is based on can be found at
|
||||
* <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html>
|
||||
* RSA's PKCS5 Page</a>
|
||||
*/
|
||||
public class PKCS5S1ParametersGenerator
|
||||
extends PBEParametersGenerator
|
||||
{
|
||||
private Digest digest;
|
||||
|
||||
/**
|
||||
* Construct a PKCS 5 Scheme 1 Parameters generator.
|
||||
*
|
||||
* @param digest the digest to be used as the source of derived keys.
|
||||
*/
|
||||
public PKCS5S1ParametersGenerator(
|
||||
Digest digest)
|
||||
{
|
||||
this.digest = digest;
|
||||
}
|
||||
|
||||
/**
|
||||
* the derived key function, the ith hash of the password and the salt.
|
||||
*/
|
||||
private byte[] generateDerivedKey()
|
||||
{
|
||||
byte[] digestBytes = new byte[digest.getDigestSize()];
|
||||
|
||||
digest.update(password, 0, password.length);
|
||||
digest.update(salt, 0, salt.length);
|
||||
|
||||
digest.doFinal(digestBytes, 0);
|
||||
for (int i = 1; i < iterationCount; i++)
|
||||
{
|
||||
digest.update(digestBytes, 0, digestBytes.length);
|
||||
digest.doFinal(digestBytes, 0);
|
||||
}
|
||||
|
||||
return digestBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a key parameter derived from the password, salt, and iteration
|
||||
* count we are currently initialised with.
|
||||
*
|
||||
* @param keySize the size of the key we want (in bits)
|
||||
* @return a KeyParameter object.
|
||||
* @exception IllegalArgumentException if the key length larger than the base hash size.
|
||||
*/
|
||||
public CipherParameters generateDerivedParameters(
|
||||
int keySize)
|
||||
{
|
||||
keySize = keySize / 8;
|
||||
|
||||
if (keySize > digest.getDigestSize())
|
||||
{
|
||||
throw new IllegalArgumentException(
|
||||
"Can't generate a derived key " + keySize + " bytes long.");
|
||||
}
|
||||
|
||||
byte[] dKey = generateDerivedKey();
|
||||
|
||||
return new KeyParameter(dKey, 0, keySize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a key with initialisation vector parameter derived from
|
||||
* the password, salt, and iteration count we are currently initialised
|
||||
* with.
|
||||
*
|
||||
* @param keySize the size of the key we want (in bits)
|
||||
* @param ivSize the size of the iv we want (in bits)
|
||||
* @return a ParametersWithIV object.
|
||||
* @exception IllegalArgumentException if keySize + ivSize is larger than the base hash size.
|
||||
*/
|
||||
public CipherParameters generateDerivedParameters(
|
||||
int keySize,
|
||||
int ivSize)
|
||||
{
|
||||
keySize = keySize / 8;
|
||||
ivSize = ivSize / 8;
|
||||
|
||||
if ((keySize + ivSize) > digest.getDigestSize())
|
||||
{
|
||||
throw new IllegalArgumentException(
|
||||
"Can't generate a derived key " + (keySize + ivSize) + " bytes long.");
|
||||
}
|
||||
|
||||
byte[] dKey = generateDerivedKey();
|
||||
|
||||
return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a key parameter for use with a MAC derived from the password,
|
||||
* salt, and iteration count we are currently initialised with.
|
||||
*
|
||||
* @param keySize the size of the key we want (in bits)
|
||||
* @return a KeyParameter object.
|
||||
* @exception IllegalArgumentException if the key length larger than the base hash size.
|
||||
*/
|
||||
public CipherParameters generateDerivedMacParameters(
|
||||
int keySize)
|
||||
{
|
||||
return generateDerivedParameters(keySize);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
package org.bouncycastle1.crypto.generators;
|
||||
|
||||
import org.bouncycastle1.crypto.CipherParameters;
|
||||
import org.bouncycastle1.crypto.Mac;
|
||||
import org.bouncycastle1.crypto.PBEParametersGenerator;
|
||||
import org.bouncycastle1.crypto.digests.SHA1Digest;
|
||||
import org.bouncycastle1.crypto.macs.HMac;
|
||||
import org.bouncycastle1.crypto.params.KeyParameter;
|
||||
import org.bouncycastle1.crypto.params.ParametersWithIV;
|
||||
|
||||
/**
|
||||
* Generator for PBE derived keys and ivs as defined by PKCS 5 V2.0 Scheme 2.
|
||||
* This generator uses a SHA-1 HMac as the calculation function.
|
||||
* <p>
|
||||
* The document this implementation is based on can be found at
|
||||
* <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html>
|
||||
* RSA's PKCS5 Page</a>
|
||||
*/
|
||||
public class PKCS5S2ParametersGenerator
|
||||
extends PBEParametersGenerator
|
||||
{
|
||||
private Mac hMac = new HMac(new SHA1Digest());
|
||||
|
||||
/**
|
||||
* construct a PKCS5 Scheme 2 Parameters generator.
|
||||
*/
|
||||
public PKCS5S2ParametersGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
private void F(
|
||||
byte[] P,
|
||||
byte[] S,
|
||||
int c,
|
||||
byte[] iBuf,
|
||||
byte[] out,
|
||||
int outOff)
|
||||
{
|
||||
byte[] state = new byte[hMac.getMacSize()];
|
||||
CipherParameters param = new KeyParameter(P);
|
||||
|
||||
hMac.init(param);
|
||||
|
||||
if (S != null)
|
||||
{
|
||||
hMac.update(S, 0, S.length);
|
||||
}
|
||||
|
||||
hMac.update(iBuf, 0, iBuf.length);
|
||||
|
||||
hMac.doFinal(state, 0);
|
||||
|
||||
System.arraycopy(state, 0, out, outOff, state.length);
|
||||
|
||||
if (c == 0)
|
||||
{
|
||||
throw new IllegalArgumentException("iteration count must be at least 1.");
|
||||
}
|
||||
|
||||
for (int count = 1; count < c; count++)
|
||||
{
|
||||
hMac.init(param);
|
||||
hMac.update(state, 0, state.length);
|
||||
hMac.doFinal(state, 0);
|
||||
|
||||
for (int j = 0; j != state.length; j++)
|
||||
{
|
||||
out[outOff + j] ^= state[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void intToOctet(
|
||||
byte[] buf,
|
||||
int i)
|
||||
{
|
||||
buf[0] = (byte)(i >>> 24);
|
||||
buf[1] = (byte)(i >>> 16);
|
||||
buf[2] = (byte)(i >>> 8);
|
||||
buf[3] = (byte)i;
|
||||
}
|
||||
|
||||
private byte[] generateDerivedKey(
|
||||
int dkLen)
|
||||
{
|
||||
int hLen = hMac.getMacSize();
|
||||
int l = (dkLen + hLen - 1) / hLen;
|
||||
byte[] iBuf = new byte[4];
|
||||
byte[] out = new byte[l * hLen];
|
||||
|
||||
for (int i = 1; i <= l; i++)
|
||||
{
|
||||
intToOctet(iBuf, i);
|
||||
|
||||
F(password, salt, iterationCount, iBuf, out, (i - 1) * hLen);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a key parameter derived from the password, salt, and iteration
|
||||
* count we are currently initialised with.
|
||||
*
|
||||
* @param keySize the size of the key we want (in bits)
|
||||
* @return a KeyParameter object.
|
||||
*/
|
||||
public CipherParameters generateDerivedParameters(
|
||||
int keySize)
|
||||
{
|
||||
keySize = keySize / 8;
|
||||
|
||||
byte[] dKey = generateDerivedKey(keySize);
|
||||
|
||||
return new KeyParameter(dKey, 0, keySize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a key with initialisation vector parameter derived from
|
||||
* the password, salt, and iteration count we are currently initialised
|
||||
* with.
|
||||
*
|
||||
* @param keySize the size of the key we want (in bits)
|
||||
* @param ivSize the size of the iv we want (in bits)
|
||||
* @return a ParametersWithIV object.
|
||||
*/
|
||||
public CipherParameters generateDerivedParameters(
|
||||
int keySize,
|
||||
int ivSize)
|
||||
{
|
||||
keySize = keySize / 8;
|
||||
ivSize = ivSize / 8;
|
||||
|
||||
byte[] dKey = generateDerivedKey(keySize + ivSize);
|
||||
|
||||
return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a key parameter for use with a MAC derived from the password,
|
||||
* salt, and iteration count we are currently initialised with.
|
||||
*
|
||||
* @param keySize the size of the key we want (in bits)
|
||||
* @return a KeyParameter object.
|
||||
*/
|
||||
public CipherParameters generateDerivedMacParameters(
|
||||
int keySize)
|
||||
{
|
||||
return generateDerivedParameters(keySize);
|
||||
}
|
||||
}
|
199
src/org/bouncycastle1/crypto/macs/HMac.java
Normal file
199
src/org/bouncycastle1/crypto/macs/HMac.java
Normal file
|
@ -0,0 +1,199 @@
|
|||
package org.bouncycastle1.crypto.macs;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.bouncycastle1.crypto.CipherParameters;
|
||||
import org.bouncycastle1.crypto.Digest;
|
||||
import org.bouncycastle1.crypto.ExtendedDigest;
|
||||
import org.bouncycastle1.crypto.Mac;
|
||||
import org.bouncycastle1.crypto.params.KeyParameter;
|
||||
|
||||
/**
|
||||
* HMAC implementation based on RFC2104
|
||||
*
|
||||
* H(K XOR opad, H(K XOR ipad, text))
|
||||
*/
|
||||
public class HMac
|
||||
implements Mac
|
||||
{
|
||||
private final static byte IPAD = (byte)0x36;
|
||||
private final static byte OPAD = (byte)0x5C;
|
||||
|
||||
private Digest digest;
|
||||
private int digestSize;
|
||||
private int blockLength;
|
||||
|
||||
private byte[] inputPad;
|
||||
private byte[] outputPad;
|
||||
|
||||
private static Hashtable blockLengths;
|
||||
|
||||
static
|
||||
{
|
||||
blockLengths = new Hashtable();
|
||||
|
||||
blockLengths.put("GOST3411", new Integer(32));
|
||||
|
||||
blockLengths.put("MD2", new Integer(16));
|
||||
blockLengths.put("MD4", new Integer(64));
|
||||
blockLengths.put("MD5", new Integer(64));
|
||||
|
||||
blockLengths.put("RIPEMD128", new Integer(64));
|
||||
blockLengths.put("RIPEMD160", new Integer(64));
|
||||
|
||||
blockLengths.put("SHA-1", new Integer(64));
|
||||
blockLengths.put("SHA-224", new Integer(64));
|
||||
blockLengths.put("SHA-256", new Integer(64));
|
||||
blockLengths.put("SHA-384", new Integer(128));
|
||||
blockLengths.put("SHA-512", new Integer(128));
|
||||
|
||||
blockLengths.put("Tiger", new Integer(64));
|
||||
blockLengths.put("Whirlpool", new Integer(64));
|
||||
}
|
||||
|
||||
private static int getByteLength(
|
||||
Digest digest)
|
||||
{
|
||||
if (digest instanceof ExtendedDigest)
|
||||
{
|
||||
return ((ExtendedDigest)digest).getByteLength();
|
||||
}
|
||||
|
||||
Integer b = (Integer)blockLengths.get(digest.getAlgorithmName());
|
||||
|
||||
if (b == null)
|
||||
{
|
||||
throw new IllegalArgumentException("unknown digest passed: " + digest.getAlgorithmName());
|
||||
}
|
||||
|
||||
return b.intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Base constructor for one of the standard digest algorithms that the
|
||||
* byteLength of the algorithm is know for.
|
||||
*
|
||||
* @param digest the digest.
|
||||
*/
|
||||
public HMac(
|
||||
Digest digest)
|
||||
{
|
||||
this(digest, getByteLength(digest));
|
||||
}
|
||||
|
||||
private HMac(
|
||||
Digest digest,
|
||||
int byteLength)
|
||||
{
|
||||
this.digest = digest;
|
||||
digestSize = digest.getDigestSize();
|
||||
|
||||
this.blockLength = byteLength;
|
||||
|
||||
inputPad = new byte[blockLength];
|
||||
outputPad = new byte[blockLength];
|
||||
}
|
||||
|
||||
public String getAlgorithmName()
|
||||
{
|
||||
return digest.getAlgorithmName() + "/HMAC";
|
||||
}
|
||||
|
||||
public Digest getUnderlyingDigest()
|
||||
{
|
||||
return digest;
|
||||
}
|
||||
|
||||
public void init(
|
||||
CipherParameters params)
|
||||
{
|
||||
digest.reset();
|
||||
|
||||
byte[] key = ((KeyParameter)params).getKey();
|
||||
|
||||
if (key.length > blockLength)
|
||||
{
|
||||
digest.update(key, 0, key.length);
|
||||
digest.doFinal(inputPad, 0);
|
||||
for (int i = digestSize; i < inputPad.length; i++)
|
||||
{
|
||||
inputPad[i] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
System.arraycopy(key, 0, inputPad, 0, key.length);
|
||||
for (int i = key.length; i < inputPad.length; i++)
|
||||
{
|
||||
inputPad[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
outputPad = new byte[inputPad.length];
|
||||
System.arraycopy(inputPad, 0, outputPad, 0, inputPad.length);
|
||||
|
||||
for (int i = 0; i < inputPad.length; i++)
|
||||
{
|
||||
inputPad[i] ^= IPAD;
|
||||
}
|
||||
|
||||
for (int i = 0; i < outputPad.length; i++)
|
||||
{
|
||||
outputPad[i] ^= OPAD;
|
||||
}
|
||||
|
||||
digest.update(inputPad, 0, inputPad.length);
|
||||
}
|
||||
|
||||
public int getMacSize()
|
||||
{
|
||||
return digestSize;
|
||||
}
|
||||
|
||||
public void update(
|
||||
byte in)
|
||||
{
|
||||
digest.update(in);
|
||||
}
|
||||
|
||||
public void update(
|
||||
byte[] in,
|
||||
int inOff,
|
||||
int len)
|
||||
{
|
||||
digest.update(in, inOff, len);
|
||||
}
|
||||
|
||||
public int doFinal(
|
||||
byte[] out,
|
||||
int outOff)
|
||||
{
|
||||
byte[] tmp = new byte[digestSize];
|
||||
digest.doFinal(tmp, 0);
|
||||
|
||||
digest.update(outputPad, 0, outputPad.length);
|
||||
digest.update(tmp, 0, tmp.length);
|
||||
|
||||
int len = digest.doFinal(out, outOff);
|
||||
|
||||
reset();
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the mac generator.
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
/*
|
||||
* reset the underlying digest.
|
||||
*/
|
||||
digest.reset();
|
||||
|
||||
/*
|
||||
* reinitialize the digest.
|
||||
*/
|
||||
digest.update(inputPad, 0, inputPad.length);
|
||||
}
|
||||
}
|
233
src/org/bouncycastle1/crypto/modes/CBCBlockCipher.java
Normal file
233
src/org/bouncycastle1/crypto/modes/CBCBlockCipher.java
Normal file
|
@ -0,0 +1,233 @@
|
|||
package org.bouncycastle1.crypto.modes;
|
||||
|
||||
import org.bouncycastle1.crypto.BlockCipher;
|
||||
import org.bouncycastle1.crypto.CipherParameters;
|
||||
import org.bouncycastle1.crypto.DataLengthException;
|
||||
import org.bouncycastle1.crypto.params.ParametersWithIV;
|
||||
|
||||
/**
|
||||
* implements Cipher-Block-Chaining (CBC) mode on top of a simple cipher.
|
||||
*/
|
||||
public class CBCBlockCipher
|
||||
implements BlockCipher
|
||||
{
|
||||
private byte[] IV;
|
||||
private byte[] cbcV;
|
||||
private byte[] cbcNextV;
|
||||
|
||||
private int blockSize;
|
||||
private BlockCipher cipher = null;
|
||||
private boolean encrypting;
|
||||
|
||||
/**
|
||||
* Basic constructor.
|
||||
*
|
||||
* @param cipher the block cipher to be used as the basis of chaining.
|
||||
*/
|
||||
public CBCBlockCipher(
|
||||
BlockCipher cipher)
|
||||
{
|
||||
this.cipher = cipher;
|
||||
this.blockSize = cipher.getBlockSize();
|
||||
|
||||
this.IV = new byte[blockSize];
|
||||
this.cbcV = new byte[blockSize];
|
||||
this.cbcNextV = new byte[blockSize];
|
||||
}
|
||||
|
||||
/**
|
||||
* return the underlying block cipher that we are wrapping.
|
||||
*
|
||||
* @return the underlying block cipher that we are wrapping.
|
||||
*/
|
||||
public BlockCipher getUnderlyingCipher()
|
||||
{
|
||||
return cipher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the cipher and, possibly, the initialisation vector (IV).
|
||||
* If an IV isn't passed as part of the parameter, the IV will be all zeros.
|
||||
*
|
||||
* @param encrypting if true the cipher is initialised for
|
||||
* encryption, if false for decryption.
|
||||
* @param params the key and other data required by the cipher.
|
||||
* @exception IllegalArgumentException if the params argument is
|
||||
* inappropriate.
|
||||
*/
|
||||
public void init(
|
||||
boolean encrypting,
|
||||
CipherParameters params)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
this.encrypting = encrypting;
|
||||
|
||||
if (params instanceof ParametersWithIV)
|
||||
{
|
||||
ParametersWithIV ivParam = (ParametersWithIV)params;
|
||||
byte[] iv = ivParam.getIV();
|
||||
|
||||
if (iv.length != blockSize)
|
||||
{
|
||||
throw new IllegalArgumentException("initialisation vector must be the same length as block size");
|
||||
}
|
||||
|
||||
System.arraycopy(iv, 0, IV, 0, iv.length);
|
||||
|
||||
reset();
|
||||
|
||||
cipher.init(encrypting, ivParam.getParameters());
|
||||
}
|
||||
else
|
||||
{
|
||||
reset();
|
||||
|
||||
cipher.init(encrypting, params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return the algorithm name and mode.
|
||||
*
|
||||
* @return the name of the underlying algorithm followed by "/CBC".
|
||||
*/
|
||||
public String getAlgorithmName()
|
||||
{
|
||||
return cipher.getAlgorithmName() + "/CBC";
|
||||
}
|
||||
|
||||
/**
|
||||
* return the block size of the underlying cipher.
|
||||
*
|
||||
* @return the block size of the underlying cipher.
|
||||
*/
|
||||
public int getBlockSize()
|
||||
{
|
||||
return cipher.getBlockSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process one block of input from the array in and write it to
|
||||
* the out array.
|
||||
*
|
||||
* @param in the array containing the input data.
|
||||
* @param inOff offset into the in array the data starts at.
|
||||
* @param out the array the output data will be copied into.
|
||||
* @param outOff the offset into the out array the output will start at.
|
||||
* @exception DataLengthException if there isn't enough data in in, or
|
||||
* space in out.
|
||||
* @exception IllegalStateException if the cipher isn't initialised.
|
||||
* @return the number of bytes processed and produced.
|
||||
*/
|
||||
public int processBlock(
|
||||
byte[] in,
|
||||
int inOff,
|
||||
byte[] out,
|
||||
int outOff)
|
||||
throws DataLengthException, IllegalStateException
|
||||
{
|
||||
return (encrypting) ? encryptBlock(in, inOff, out, outOff) : decryptBlock(in, inOff, out, outOff);
|
||||
}
|
||||
|
||||
/**
|
||||
* reset the chaining vector back to the IV and reset the underlying
|
||||
* cipher.
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
System.arraycopy(IV, 0, cbcV, 0, IV.length);
|
||||
|
||||
cipher.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the appropriate chaining step for CBC mode encryption.
|
||||
*
|
||||
* @param in the array containing the data to be encrypted.
|
||||
* @param inOff offset into the in array the data starts at.
|
||||
* @param out the array the encrypted data will be copied into.
|
||||
* @param outOff the offset into the out array the output will start at.
|
||||
* @exception DataLengthException if there isn't enough data in in, or
|
||||
* space in out.
|
||||
* @exception IllegalStateException if the cipher isn't initialised.
|
||||
* @return the number of bytes processed and produced.
|
||||
*/
|
||||
private int encryptBlock(
|
||||
byte[] in,
|
||||
int inOff,
|
||||
byte[] out,
|
||||
int outOff)
|
||||
throws DataLengthException, IllegalStateException
|
||||
{
|
||||
if ((inOff + blockSize) > in.length)
|
||||
{
|
||||
throw new DataLengthException("input buffer too short");
|
||||
}
|
||||
|
||||
/*
|
||||
* XOR the cbcV and the input,
|
||||
* then encrypt the cbcV
|
||||
*/
|
||||
for (int i = 0; i < blockSize; i++)
|
||||
{
|
||||
cbcV[i] ^= in[inOff + i];
|
||||
}
|
||||
|
||||
int length = cipher.processBlock(cbcV, 0, out, outOff);
|
||||
|
||||
/*
|
||||
* copy ciphertext to cbcV
|
||||
*/
|
||||
System.arraycopy(out, outOff, cbcV, 0, cbcV.length);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the appropriate chaining step for CBC mode decryption.
|
||||
*
|
||||
* @param in the array containing the data to be decrypted.
|
||||
* @param inOff offset into the in array the data starts at.
|
||||
* @param out the array the decrypted data will be copied into.
|
||||
* @param outOff the offset into the out array the output will start at.
|
||||
* @exception DataLengthException if there isn't enough data in in, or
|
||||
* space in out.
|
||||
* @exception IllegalStateException if the cipher isn't initialised.
|
||||
* @return the number of bytes processed and produced.
|
||||
*/
|
||||
private int decryptBlock(
|
||||
byte[] in,
|
||||
int inOff,
|
||||
byte[] out,
|
||||
int outOff)
|
||||
throws DataLengthException, IllegalStateException
|
||||
{
|
||||
if ((inOff + blockSize) > in.length)
|
||||
{
|
||||
throw new DataLengthException("input buffer too short");
|
||||
}
|
||||
|
||||
System.arraycopy(in, inOff, cbcNextV, 0, blockSize);
|
||||
|
||||
int length = cipher.processBlock(in, inOff, out, outOff);
|
||||
|
||||
/*
|
||||
* XOR the cbcV and the output
|
||||
*/
|
||||
for (int i = 0; i < blockSize; i++)
|
||||
{
|
||||
out[outOff + i] ^= cbcV[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* swap the back up buffer into next position
|
||||
*/
|
||||
byte[] tmp;
|
||||
|
||||
tmp = cbcV;
|
||||
cbcV = cbcNextV;
|
||||
cbcNextV = tmp;
|
||||
|
||||
return length;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package org.bouncycastle1.crypto.paddings;
|
||||
|
||||
import org.bouncycastle1.crypto.SecureRandom;
|
||||
|
||||
import org.bouncycastle1.crypto.InvalidCipherTextException;
|
||||
|
||||
/**
|
||||
* Block cipher padders are expected to conform to this interface
|
||||
*/
|
||||
public interface BlockCipherPadding
|
||||
{
|
||||
/**
|
||||
* Initialise the padder.
|
||||
*
|
||||
* @param random the source of randomness for the padding, if required.
|
||||
*/
|
||||
public void init(SecureRandom random)
|
||||
throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Return the name of the algorithm the cipher implements.
|
||||
*
|
||||
* @return the name of the algorithm the cipher implements.
|
||||
*/
|
||||
public String getPaddingName();
|
||||
|
||||
/**
|
||||
* add the pad bytes to the passed in block, returning the
|
||||
* number of bytes added.
|
||||
* <p>
|
||||
* Note: this assumes that the last block of plain text is always
|
||||
* passed to it inside in. i.e. if inOff is zero, indicating the
|
||||
* entire block is to be overwritten with padding the value of in
|
||||
* should be the same as the last block of plain text. The reason
|
||||
* for this is that some modes such as "trailing bit compliment"
|
||||
* base the padding on the last byte of plain text.
|
||||
* </p>
|
||||
*/
|
||||
public int addPadding(byte[] in, int inOff);
|
||||
|
||||
/**
|
||||
* return the number of pad bytes present in the block.
|
||||
* @exception InvalidCipherTextException if the padding is badly formed
|
||||
* or invalid.
|
||||
*/
|
||||
public int padCount(byte[] in)
|
||||
throws InvalidCipherTextException;
|
||||
}
|
74
src/org/bouncycastle1/crypto/paddings/PKCS7Padding.java
Normal file
74
src/org/bouncycastle1/crypto/paddings/PKCS7Padding.java
Normal file
|
@ -0,0 +1,74 @@
|
|||
package org.bouncycastle1.crypto.paddings;
|
||||
|
||||
import org.bouncycastle1.crypto.InvalidCipherTextException;
|
||||
|
||||
/**
|
||||
* A padder that adds PKCS7/PKCS5 padding to a block.
|
||||
*/
|
||||
public class PKCS7Padding
|
||||
implements BlockCipherPadding
|
||||
{
|
||||
/**
|
||||
* Initialise the padder.
|
||||
*
|
||||
* @param random - a SecureRandom if available.
|
||||
*/
|
||||
public void init(org.bouncycastle1.crypto.SecureRandom random)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
// nothing to do.
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the algorithm the padder implements.
|
||||
*
|
||||
* @return the name of the algorithm the padder implements.
|
||||
*/
|
||||
public String getPaddingName()
|
||||
{
|
||||
return "PKCS7";
|
||||
}
|
||||
|
||||
/**
|
||||
* add the pad bytes to the passed in block, returning the
|
||||
* number of bytes added.
|
||||
*/
|
||||
public int addPadding(
|
||||
byte[] in,
|
||||
int inOff)
|
||||
{
|
||||
byte code = (byte)(in.length - inOff);
|
||||
|
||||
while (inOff < in.length)
|
||||
{
|
||||
in[inOff] = code;
|
||||
inOff++;
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the number of pad bytes present in the block.
|
||||
*/
|
||||
public int padCount(byte[] in)
|
||||
throws InvalidCipherTextException
|
||||
{
|
||||
int count = in[in.length - 1] & 0xff;
|
||||
|
||||
if (count > in.length)
|
||||
{
|
||||
throw new InvalidCipherTextException("pad block corrupted");
|
||||
}
|
||||
|
||||
for (int i = 1; i <= count; i++)
|
||||
{
|
||||
if (in[in.length - i] != count)
|
||||
{
|
||||
throw new InvalidCipherTextException("pad block corrupted");
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,299 @@
|
|||
package org.bouncycastle1.crypto.paddings;
|
||||
|
||||
import org.bouncycastle1.crypto.BlockCipher;
|
||||
import org.bouncycastle1.crypto.BufferedBlockCipher;
|
||||
import org.bouncycastle1.crypto.CipherParameters;
|
||||
import org.bouncycastle1.crypto.DataLengthException;
|
||||
import org.bouncycastle1.crypto.InvalidCipherTextException;
|
||||
import org.bouncycastle1.crypto.params.ParametersWithRandom;
|
||||
|
||||
/**
|
||||
* A wrapper class that allows block ciphers to be used to process data in
|
||||
* a piecemeal fashion with padding. The PaddedBufferedBlockCipher
|
||||
* outputs a block only when the buffer is full and more data is being added,
|
||||
* or on a doFinal (unless the current block in the buffer is a pad block).
|
||||
* The default padding mechanism used is the one outlined in PKCS5/PKCS7.
|
||||
*/
|
||||
public class PaddedBufferedBlockCipher
|
||||
extends BufferedBlockCipher
|
||||
{
|
||||
BlockCipherPadding padding;
|
||||
|
||||
/**
|
||||
* Create a buffered block cipher with the desired padding.
|
||||
*
|
||||
* @param cipher the underlying block cipher this buffering object wraps.
|
||||
* @param padding the padding type.
|
||||
*/
|
||||
public PaddedBufferedBlockCipher(
|
||||
BlockCipher cipher,
|
||||
BlockCipherPadding padding)
|
||||
{
|
||||
this.cipher = cipher;
|
||||
this.padding = padding;
|
||||
|
||||
buf = new byte[cipher.getBlockSize()];
|
||||
bufOff = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a buffered block cipher PKCS7 padding
|
||||
*
|
||||
* @param cipher the underlying block cipher this buffering object wraps.
|
||||
*/
|
||||
public PaddedBufferedBlockCipher(
|
||||
BlockCipher cipher)
|
||||
{
|
||||
this(cipher, new PKCS7Padding());
|
||||
}
|
||||
|
||||
/**
|
||||
* initialise the cipher.
|
||||
*
|
||||
* @param forEncryption if true the cipher is initialised for
|
||||
* encryption, if false for decryption.
|
||||
* @param params the key and other data required by the cipher.
|
||||
* @exception IllegalArgumentException if the params argument is
|
||||
* inappropriate.
|
||||
*/
|
||||
public void init(
|
||||
boolean forEncryption,
|
||||
CipherParameters params)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
this.forEncryption = forEncryption;
|
||||
|
||||
reset();
|
||||
|
||||
if (params instanceof ParametersWithRandom)
|
||||
{
|
||||
ParametersWithRandom p = (ParametersWithRandom)params;
|
||||
|
||||
padding.init(p.getRandom());
|
||||
|
||||
cipher.init(forEncryption, p.getParameters());
|
||||
}
|
||||
else
|
||||
{
|
||||
padding.init(null);
|
||||
|
||||
cipher.init(forEncryption, params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return the minimum size of the output buffer required for an update
|
||||
* plus a doFinal with an input of len bytes.
|
||||
*
|
||||
* @param len the length of the input.
|
||||
* @return the space required to accommodate a call to update and doFinal
|
||||
* with len bytes of input.
|
||||
*/
|
||||
public int getOutputSize(
|
||||
int len)
|
||||
{
|
||||
int total = len + bufOff;
|
||||
int leftOver = total % buf.length;
|
||||
|
||||
if (leftOver == 0)
|
||||
{
|
||||
if (forEncryption)
|
||||
{
|
||||
return total + buf.length;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
return total - leftOver + buf.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the size of the output buffer required for an update
|
||||
* an input of len bytes.
|
||||
*
|
||||
* @param len the length of the input.
|
||||
* @return the space required to accommodate a call to update
|
||||
* with len bytes of input.
|
||||
*/
|
||||
public int getUpdateOutputSize(
|
||||
int len)
|
||||
{
|
||||
int total = len + bufOff;
|
||||
int leftOver = total % buf.length;
|
||||
|
||||
if (leftOver == 0)
|
||||
{
|
||||
return total - buf.length;
|
||||
}
|
||||
|
||||
return total - leftOver;
|
||||
}
|
||||
|
||||
/**
|
||||
* process a single byte, producing an output block if neccessary.
|
||||
*
|
||||
* @param in the input byte.
|
||||
* @param out the space for any output that might be produced.
|
||||
* @param outOff the offset from which the output will be copied.
|
||||
* @return the number of output bytes copied to out.
|
||||
* @exception DataLengthException if there isn't enough space in out.
|
||||
* @exception IllegalStateException if the cipher isn't initialised.
|
||||
*/
|
||||
public int processByte(
|
||||
byte in,
|
||||
byte[] out,
|
||||
int outOff)
|
||||
throws DataLengthException, IllegalStateException
|
||||
{
|
||||
int resultLen = 0;
|
||||
|
||||
if (bufOff == buf.length)
|
||||
{
|
||||
resultLen = cipher.processBlock(buf, 0, out, outOff);
|
||||
bufOff = 0;
|
||||
}
|
||||
|
||||
buf[bufOff++] = in;
|
||||
|
||||
return resultLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* process an array of bytes, producing output if necessary.
|
||||
*
|
||||
* @param in the input byte array.
|
||||
* @param inOff the offset at which the input data starts.
|
||||
* @param len the number of bytes to be copied out of the input array.
|
||||
* @param out the space for any output that might be produced.
|
||||
* @param outOff the offset from which the output will be copied.
|
||||
* @return the number of output bytes copied to out.
|
||||
* @exception DataLengthException if there isn't enough space in out.
|
||||
* @exception IllegalStateException if the cipher isn't initialised.
|
||||
*/
|
||||
public int processBytes(
|
||||
byte[] in,
|
||||
int inOff,
|
||||
int len,
|
||||
byte[] out,
|
||||
int outOff)
|
||||
throws DataLengthException, IllegalStateException
|
||||
{
|
||||
if (len < 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Can't have a negative input length!");
|
||||
}
|
||||
|
||||
int blockSize = getBlockSize();
|
||||
int length = getUpdateOutputSize(len);
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
if ((outOff + length) > out.length)
|
||||
{
|
||||
throw new DataLengthException("output buffer too short");
|
||||
}
|
||||
}
|
||||
|
||||
int resultLen = 0;
|
||||
int gapLen = buf.length - bufOff;
|
||||
|
||||
if (len > gapLen)
|
||||
{
|
||||
System.arraycopy(in, inOff, buf, bufOff, gapLen);
|
||||
|
||||
resultLen += cipher.processBlock(buf, 0, out, outOff);
|
||||
|
||||
bufOff = 0;
|
||||
len -= gapLen;
|
||||
inOff += gapLen;
|
||||
|
||||
while (len > buf.length)
|
||||
{
|
||||
resultLen += cipher.processBlock(in, inOff, out, outOff + resultLen);
|
||||
|
||||
len -= blockSize;
|
||||
inOff += blockSize;
|
||||
}
|
||||
}
|
||||
|
||||
System.arraycopy(in, inOff, buf, bufOff, len);
|
||||
|
||||
bufOff += len;
|
||||
|
||||
return resultLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the last block in the buffer. If the buffer is currently
|
||||
* full and padding needs to be added a call to doFinal will produce
|
||||
* 2 * getBlockSize() bytes.
|
||||
*
|
||||
* @param out the array the block currently being held is copied into.
|
||||
* @param outOff the offset at which the copying starts.
|
||||
* @return the number of output bytes copied to out.
|
||||
* @exception DataLengthException if there is insufficient space in out for
|
||||
* the output or we are decrypting and the input is not block size aligned.
|
||||
* @exception IllegalStateException if the underlying cipher is not
|
||||
* initialised.
|
||||
* @exception InvalidCipherTextException if padding is expected and not found.
|
||||
*/
|
||||
public int doFinal(
|
||||
byte[] out,
|
||||
int outOff)
|
||||
throws DataLengthException, IllegalStateException, InvalidCipherTextException
|
||||
{
|
||||
int blockSize = cipher.getBlockSize();
|
||||
int resultLen = 0;
|
||||
|
||||
if (forEncryption)
|
||||
{
|
||||
if (bufOff == blockSize)
|
||||
{
|
||||
if ((outOff + 2 * blockSize) > out.length)
|
||||
{
|
||||
reset();
|
||||
|
||||
throw new DataLengthException("output buffer too short");
|
||||
}
|
||||
|
||||
resultLen = cipher.processBlock(buf, 0, out, outOff);
|
||||
bufOff = 0;
|
||||
}
|
||||
|
||||
padding.addPadding(buf, bufOff);
|
||||
|
||||
resultLen += cipher.processBlock(buf, 0, out, outOff + resultLen);
|
||||
|
||||
reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.println ("Decrypt");
|
||||
if (bufOff == blockSize)
|
||||
{
|
||||
resultLen = cipher.processBlock(buf, 0, buf, 0);
|
||||
bufOff = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
reset();
|
||||
|
||||
throw new DataLengthException("last block incomplete in decryption");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
resultLen -= padding.padCount(buf);
|
||||
|
||||
System.arraycopy(buf, 0, out, outOff, resultLen);
|
||||
}
|
||||
finally
|
||||
{
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
return resultLen;
|
||||
}
|
||||
}
|
30
src/org/bouncycastle1/crypto/params/KeyParameter.java
Normal file
30
src/org/bouncycastle1/crypto/params/KeyParameter.java
Normal file
|
@ -0,0 +1,30 @@
|
|||
package org.bouncycastle1.crypto.params;
|
||||
|
||||
import org.bouncycastle1.crypto.CipherParameters;
|
||||
|
||||
public class KeyParameter
|
||||
implements CipherParameters
|
||||
{
|
||||
private byte[] key;
|
||||
|
||||
public KeyParameter(
|
||||
byte[] key)
|
||||
{
|
||||
this(key, 0, key.length);
|
||||
}
|
||||
|
||||
public KeyParameter(
|
||||
byte[] key,
|
||||
int keyOff,
|
||||
int keyLen)
|
||||
{
|
||||
this.key = new byte[keyLen];
|
||||
|
||||
System.arraycopy(key, keyOff, this.key, 0, keyLen);
|
||||
}
|
||||
|
||||
public byte[] getKey()
|
||||
{
|
||||
return key;
|
||||
}
|
||||
}
|
39
src/org/bouncycastle1/crypto/params/ParametersWithIV.java
Normal file
39
src/org/bouncycastle1/crypto/params/ParametersWithIV.java
Normal file
|
@ -0,0 +1,39 @@
|
|||
package org.bouncycastle1.crypto.params;
|
||||
|
||||
import org.bouncycastle1.crypto.CipherParameters;
|
||||
|
||||
public class ParametersWithIV
|
||||
implements CipherParameters
|
||||
{
|
||||
private byte[] iv;
|
||||
private CipherParameters parameters;
|
||||
|
||||
public ParametersWithIV(
|
||||
CipherParameters parameters,
|
||||
byte[] iv)
|
||||
{
|
||||
this(parameters, iv, 0, iv.length);
|
||||
}
|
||||
|
||||
public ParametersWithIV(
|
||||
CipherParameters parameters,
|
||||
byte[] iv,
|
||||
int ivOff,
|
||||
int ivLen)
|
||||
{
|
||||
this.iv = new byte[ivLen];
|
||||
this.parameters = parameters;
|
||||
|
||||
System.arraycopy(iv, ivOff, this.iv, 0, ivLen);
|
||||
}
|
||||
|
||||
public byte[] getIV()
|
||||
{
|
||||
return iv;
|
||||
}
|
||||
|
||||
public CipherParameters getParameters()
|
||||
{
|
||||
return parameters;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package org.bouncycastle1.crypto.params;
|
||||
|
||||
import org.bouncycastle1.crypto.CipherParameters;
|
||||
|
||||
import org.bouncycastle1.crypto.SecureRandom;
|
||||
|
||||
public class ParametersWithRandom
|
||||
implements CipherParameters
|
||||
{
|
||||
private SecureRandom random;
|
||||
private CipherParameters parameters;
|
||||
|
||||
public ParametersWithRandom(
|
||||
CipherParameters parameters,
|
||||
SecureRandom random)
|
||||
{
|
||||
this.random = random;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
public ParametersWithRandom(
|
||||
CipherParameters parameters)
|
||||
{
|
||||
this(parameters, new SecureRandom());
|
||||
}
|
||||
|
||||
public SecureRandom getRandom()
|
||||
{
|
||||
return random;
|
||||
}
|
||||
|
||||
public CipherParameters getParameters()
|
||||
{
|
||||
return parameters;
|
||||
}
|
||||
}
|
97
src/org/bouncycastle1/crypto/prng/DigestRandomGenerator.java
Normal file
97
src/org/bouncycastle1/crypto/prng/DigestRandomGenerator.java
Normal file
|
@ -0,0 +1,97 @@
|
|||
package org.bouncycastle1.crypto.prng;
|
||||
|
||||
import org.bouncycastle1.crypto.Digest;
|
||||
|
||||
/**
|
||||
* Random generation based on the digest with counter. Calling addSeedMaterial will
|
||||
* always increase the entropy of the hash.
|
||||
* <p>
|
||||
* Internal access to the digest is synchronized so a single one of these can be shared.
|
||||
* </p>
|
||||
*/
|
||||
public class DigestRandomGenerator
|
||||
implements RandomGenerator
|
||||
{
|
||||
private long counter;
|
||||
private Digest digest;
|
||||
private byte[] state;
|
||||
|
||||
// public constructors
|
||||
public DigestRandomGenerator(
|
||||
Digest digest)
|
||||
{
|
||||
this.digest = digest;
|
||||
this.state = new byte[digest.getDigestSize()];
|
||||
this.counter = 1;
|
||||
}
|
||||
|
||||
public void addSeedMaterial(byte[] inSeed)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
digestUpdate(inSeed);
|
||||
}
|
||||
}
|
||||
|
||||
public void addSeedMaterial(long rSeed)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
for (int i = 0; i != 8; i++)
|
||||
{
|
||||
digestUpdate((byte)rSeed);
|
||||
rSeed >>>= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void nextBytes(byte[] bytes)
|
||||
{
|
||||
nextBytes(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
public void nextBytes(byte[] bytes, int start, int len)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
int stateOff = 0;
|
||||
|
||||
digestDoFinal(state);
|
||||
|
||||
int end = start + len;
|
||||
for (int i = start; i != end; i++)
|
||||
{
|
||||
if (stateOff == state.length)
|
||||
{
|
||||
digestUpdate(counter++);
|
||||
digestUpdate(state);
|
||||
digestDoFinal(state);
|
||||
stateOff = 0;
|
||||
}
|
||||
bytes[i] = state[stateOff++];
|
||||
}
|
||||
|
||||
digestUpdate(counter++);
|
||||
digestUpdate(state);
|
||||
}
|
||||
}
|
||||
|
||||
private void digestUpdate(long seed)
|
||||
{
|
||||
for (int i = 0; i != 8; i++)
|
||||
{
|
||||
digest.update((byte)seed);
|
||||
seed >>>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
private void digestUpdate(byte[] inSeed)
|
||||
{
|
||||
digest.update(inSeed, 0, inSeed.length);
|
||||
}
|
||||
|
||||
private void digestDoFinal(byte[] result)
|
||||
{
|
||||
digest.doFinal(result, 0);
|
||||
}
|
||||
}
|
38
src/org/bouncycastle1/crypto/prng/RandomGenerator.java
Normal file
38
src/org/bouncycastle1/crypto/prng/RandomGenerator.java
Normal file
|
@ -0,0 +1,38 @@
|
|||
package org.bouncycastle1.crypto.prng;
|
||||
|
||||
/**
|
||||
* Generic interface for objects generating random bytes.
|
||||
*/
|
||||
public interface RandomGenerator
|
||||
{
|
||||
/**
|
||||
* Add more seed material to the generator.
|
||||
*
|
||||
* @param seed a byte array to be mixed into the generator's state.
|
||||
*/
|
||||
void addSeedMaterial(byte[] seed);
|
||||
|
||||
/**
|
||||
* Add more seed material to the generator.
|
||||
*
|
||||
* @param seed a long value to be mixed into the generator's state.
|
||||
*/
|
||||
void addSeedMaterial(long seed);
|
||||
|
||||
/**
|
||||
* Fill bytes with random values.
|
||||
*
|
||||
* @param bytes byte array to be filled.
|
||||
*/
|
||||
void nextBytes(byte[] bytes);
|
||||
|
||||
/**
|
||||
* Fill part of bytes with random values.
|
||||
*
|
||||
* @param bytes byte array to be filled.
|
||||
* @param start index to start filling at.
|
||||
* @param len length of segment to fill.
|
||||
*/
|
||||
void nextBytes(byte[] bytes, int start, int len);
|
||||
|
||||
}
|
88
src/org/bouncycastle1/util/Arrays.java
Normal file
88
src/org/bouncycastle1/util/Arrays.java
Normal file
|
@ -0,0 +1,88 @@
|
|||
package org.bouncycastle1.util;
|
||||
|
||||
/**
|
||||
* General array utilities.
|
||||
*/
|
||||
public final class Arrays
|
||||
{
|
||||
private Arrays()
|
||||
{
|
||||
// static class, hide constructor
|
||||
}
|
||||
|
||||
public static boolean areEqual(
|
||||
byte[] a,
|
||||
byte[] b)
|
||||
{
|
||||
if (a == b)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a.length != b.length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i != a.length; i++)
|
||||
{
|
||||
if (a[i] != b[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void fill(
|
||||
byte[] array,
|
||||
byte value)
|
||||
{
|
||||
for (int i = 0; i < array.length; i++)
|
||||
{
|
||||
array[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static void fill(
|
||||
long[] array,
|
||||
long value)
|
||||
{
|
||||
for (int i = 0; i < array.length; i++)
|
||||
{
|
||||
array[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static void fill(
|
||||
short[] array,
|
||||
short value)
|
||||
{
|
||||
for (int i = 0; i < array.length; i++)
|
||||
{
|
||||
array[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static int hashCode(byte[] data)
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
for (int i = 0; i != data.length; i++)
|
||||
{
|
||||
value ^= (data[i] & 0xff) << (i % 4);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static byte[] clone(byte[] data)
|
||||
{
|
||||
byte[] copy = new byte[data.length];
|
||||
|
||||
System.arraycopy(data, 0, copy, 0, data.length);
|
||||
|
||||
return copy;
|
||||
}
|
||||
}
|
17
src/org/bouncycastle1/util/encoders/Encoder.java
Normal file
17
src/org/bouncycastle1/util/encoders/Encoder.java
Normal file
|
@ -0,0 +1,17 @@
|
|||
package org.bouncycastle1.util.encoders;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Encode and decode byte arrays (typically from binary to 7-bit ASCII
|
||||
* encodings).
|
||||
*/
|
||||
public interface Encoder
|
||||
{
|
||||
int encode(byte[] data, int off, int length, OutputStream out) throws IOException;
|
||||
|
||||
int decode(byte[] data, int off, int length, OutputStream out) throws IOException;
|
||||
|
||||
int decode(String data, OutputStream out) throws IOException;
|
||||
}
|
131
src/org/bouncycastle1/util/encoders/Hex.java
Normal file
131
src/org/bouncycastle1/util/encoders/Hex.java
Normal file
|
@ -0,0 +1,131 @@
|
|||
package org.bouncycastle1.util.encoders;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class Hex
|
||||
{
|
||||
private static final Encoder encoder = new HexEncoder();
|
||||
|
||||
/**
|
||||
* encode the input data producing a Hex encoded byte array.
|
||||
*
|
||||
* @return a byte array containing the Hex encoded data.
|
||||
*/
|
||||
public static byte[] encode(
|
||||
byte[] data)
|
||||
{
|
||||
return encode(data, 0, data.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* encode the input data producing a Hex encoded byte array.
|
||||
*
|
||||
* @return a byte array containing the Hex encoded data.
|
||||
*/
|
||||
public static byte[] encode(
|
||||
byte[] data,
|
||||
int off,
|
||||
int length)
|
||||
{
|
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
||||
|
||||
try
|
||||
{
|
||||
encoder.encode(data, off, length, bOut);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException("exception encoding Hex string: " + e);
|
||||
}
|
||||
|
||||
return bOut.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hex encode the byte data writing it to the given output stream.
|
||||
*
|
||||
* @return the number of bytes produced.
|
||||
*/
|
||||
public static int encode(
|
||||
byte[] data,
|
||||
OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
return encoder.encode(data, 0, data.length, out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hex encode the byte data writing it to the given output stream.
|
||||
*
|
||||
* @return the number of bytes produced.
|
||||
*/
|
||||
public static int encode(
|
||||
byte[] data,
|
||||
int off,
|
||||
int length,
|
||||
OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
return encoder.encode(data, off, length, out);
|
||||
}
|
||||
|
||||
/**
|
||||
* decode the Hex encoded input data. It is assumed the input data is valid.
|
||||
*
|
||||
* @return a byte array representing the decoded data.
|
||||
*/
|
||||
public static byte[] decode(
|
||||
byte[] data)
|
||||
{
|
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
||||
|
||||
try
|
||||
{
|
||||
encoder.decode(data, 0, data.length, bOut);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException("exception decoding Hex string: " + e);
|
||||
}
|
||||
|
||||
return bOut.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* decode the Hex encoded String data - whitespace will be ignored.
|
||||
*
|
||||
* @return a byte array representing the decoded data.
|
||||
*/
|
||||
public static byte[] decode(
|
||||
String data)
|
||||
{
|
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
||||
|
||||
try
|
||||
{
|
||||
encoder.decode(data, bOut);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException("exception decoding Hex string: " + e);
|
||||
}
|
||||
|
||||
return bOut.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* decode the Hex encoded String data writing it to the given output stream,
|
||||
* whitespace characters will be ignored.
|
||||
*
|
||||
* @return the number of bytes produced.
|
||||
*/
|
||||
public static int decode(
|
||||
String data,
|
||||
OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
return encoder.decode(data, out);
|
||||
}
|
||||
}
|
172
src/org/bouncycastle1/util/encoders/HexEncoder.java
Normal file
172
src/org/bouncycastle1/util/encoders/HexEncoder.java
Normal file
|
@ -0,0 +1,172 @@
|
|||
package org.bouncycastle1.util.encoders;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class HexEncoder
|
||||
implements Encoder
|
||||
{
|
||||
protected final byte[] encodingTable =
|
||||
{
|
||||
(byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7',
|
||||
(byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f'
|
||||
};
|
||||
|
||||
/*
|
||||
* set up the decoding table.
|
||||
*/
|
||||
protected final byte[] decodingTable = new byte[128];
|
||||
|
||||
protected void initialiseDecodingTable()
|
||||
{
|
||||
for (int i = 0; i < encodingTable.length; i++)
|
||||
{
|
||||
decodingTable[encodingTable[i]] = (byte)i;
|
||||
}
|
||||
|
||||
decodingTable['A'] = decodingTable['a'];
|
||||
decodingTable['B'] = decodingTable['b'];
|
||||
decodingTable['C'] = decodingTable['c'];
|
||||
decodingTable['D'] = decodingTable['d'];
|
||||
decodingTable['E'] = decodingTable['e'];
|
||||
decodingTable['F'] = decodingTable['f'];
|
||||
}
|
||||
|
||||
public HexEncoder()
|
||||
{
|
||||
initialiseDecodingTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* encode the input data producing a Hex output stream.
|
||||
*
|
||||
* @return the number of bytes produced.
|
||||
*/
|
||||
public int encode(
|
||||
byte[] data,
|
||||
int off,
|
||||
int length,
|
||||
OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
for (int i = off; i < (off + length); i++)
|
||||
{
|
||||
int v = data[i] & 0xff;
|
||||
|
||||
out.write(encodingTable[(v >>> 4)]);
|
||||
out.write(encodingTable[v & 0xf]);
|
||||
}
|
||||
|
||||
return length * 2;
|
||||
}
|
||||
|
||||
private boolean ignore(
|
||||
char c)
|
||||
{
|
||||
return (c == '\n' || c =='\r' || c == '\t' || c == ' ');
|
||||
}
|
||||
|
||||
/**
|
||||
* decode the Hex encoded byte data writing it to the given output stream,
|
||||
* whitespace characters will be ignored.
|
||||
*
|
||||
* @return the number of bytes produced.
|
||||
*/
|
||||
public int decode(
|
||||
byte[] data,
|
||||
int off,
|
||||
int length,
|
||||
OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
byte b1, b2;
|
||||
int outLen = 0;
|
||||
|
||||
int end = off + length;
|
||||
|
||||
while (end > off)
|
||||
{
|
||||
if (!ignore((char)data[end - 1]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
end--;
|
||||
}
|
||||
|
||||
int i = off;
|
||||
while (i < end)
|
||||
{
|
||||
while (i < end && ignore((char)data[i]))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
||||
b1 = decodingTable[data[i++]];
|
||||
|
||||
while (i < end && ignore((char)data[i]))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
||||
b2 = decodingTable[data[i++]];
|
||||
|
||||
out.write((b1 << 4) | b2);
|
||||
|
||||
outLen++;
|
||||
}
|
||||
|
||||
return outLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* decode the Hex encoded String data writing it to the given output stream,
|
||||
* whitespace characters will be ignored.
|
||||
*
|
||||
* @return the number of bytes produced.
|
||||
*/
|
||||
public int decode(
|
||||
String data,
|
||||
OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
byte b1, b2;
|
||||
int length = 0;
|
||||
|
||||
int end = data.length();
|
||||
|
||||
while (end > 0)
|
||||
{
|
||||
if (!ignore(data.charAt(end - 1)))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
end--;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
while (i < end)
|
||||
{
|
||||
while (i < end && ignore(data.charAt(i)))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
||||
b1 = decodingTable[data.charAt(i++)];
|
||||
|
||||
while (i < end && ignore(data.charAt(i)))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
||||
b2 = decodingTable[data.charAt(i++)];
|
||||
|
||||
out.write((b1 << 4) | b2);
|
||||
|
||||
length++;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
}
|
21
src/org/phoneid/Definition.java
Normal file
21
src/org/phoneid/Definition.java
Normal file
|
@ -0,0 +1,21 @@
|
|||
package org.phoneid;
|
||||
|
||||
// import org.bouncycastle1.util.encoders.Hex;
|
||||
|
||||
public class Definition {
|
||||
public static final String KDBRecordStoreName = "KeePassKDB";
|
||||
public static final int NUM_ICONS = 65;
|
||||
public static final String TITLE = new String ("KeePass for J2ME");
|
||||
public static final int USER_CODE_LEN = 4;
|
||||
public static final int PASS_CODE_LEN = 4;
|
||||
public static final int ENC_CODE_LEN = 16;
|
||||
public static final String DEFAULT_KDB_URL = "http://keepassserver.info/download.php";
|
||||
public static final int MAX_TEXT_LEN = 128;
|
||||
public static final int PASSWORD_KEY_SHA_ROUNDS = 6000;
|
||||
public static final int KDB_HEADER_LEN = 124;
|
||||
public static final boolean CONFIG_NO_WEB = false; // disable web sync feature
|
||||
public static final boolean DEBUG = false;
|
||||
|
||||
public static final byte[] ZeroIV = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
}
|
||||
|
9
src/org/phoneid/PhoneIDException.java
Normal file
9
src/org/phoneid/PhoneIDException.java
Normal file
|
@ -0,0 +1,9 @@
|
|||
package org.phoneid;
|
||||
|
||||
import java.lang.Exception;
|
||||
|
||||
public class PhoneIDException extends Exception {
|
||||
public PhoneIDException(String str) {
|
||||
super(str);
|
||||
}
|
||||
}
|
30
src/org/phoneid/PhoneIDUtil.java
Normal file
30
src/org/phoneid/PhoneIDUtil.java
Normal file
|
@ -0,0 +1,30 @@
|
|||
package org.phoneid;
|
||||
|
||||
public class PhoneIDUtil {
|
||||
|
||||
/**
|
||||
* Compare byte arrays
|
||||
*/
|
||||
public static boolean compare(byte[] array1, byte[] array2)
|
||||
{
|
||||
if (array1.length != array2.length)
|
||||
return false;
|
||||
|
||||
for (int i=0; i<array1.length; i++)
|
||||
if (array1[i] != array2[i])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* fill byte array
|
||||
*/
|
||||
public static void fill(byte[] array, byte value)
|
||||
{
|
||||
for (int i=0; i<array.length; i++)
|
||||
array[i] = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
554
src/org/phoneid/keepassj2me/ImporterV3.java
Normal file
554
src/org/phoneid/keepassj2me/ImporterV3.java
Normal file
|
@ -0,0 +1,554 @@
|
|||
/*
|
||||
KeePass for J2ME
|
||||
|
||||
Copyright 2007 Naomaru Itoi <nao@phoneid.org>
|
||||
|
||||
This file was derived from
|
||||
|
||||
Java clone of KeePass - A KeePass file viewer for Java
|
||||
Copyright 2006 Bill Zwicky <billzwicky@users.sourceforge.net>
|
||||
|
||||
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; version 2
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package org.phoneid.keepassj2me;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.bouncycastle1.crypto.*;
|
||||
import org.bouncycastle1.crypto.digests.SHA256Digest;
|
||||
import org.bouncycastle1.crypto.engines.AESEngine;
|
||||
import org.bouncycastle1.crypto.modes.CBCBlockCipher;
|
||||
import org.bouncycastle1.crypto.paddings.PKCS7Padding;
|
||||
import org.bouncycastle1.crypto.params.KeyParameter;
|
||||
import org.bouncycastle1.crypto.params.ParametersWithIV;
|
||||
import org.phoneid.PhoneIDException;
|
||||
import org.phoneid.PhoneIDUtil;
|
||||
|
||||
/**
|
||||
* Load a v3 database file.
|
||||
*
|
||||
* @author Naomaru Itoi <nao@phoneid.org>
|
||||
* @author Bill Zwicky <wrzwicky@pobox.com>
|
||||
*/
|
||||
public class ImporterV3 {
|
||||
|
||||
public ImporterV3() {
|
||||
//super();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load a v3 database file, return contents in a new PwManager.
|
||||
*
|
||||
* @param infile Existing file to load.
|
||||
* @param password Pass phrase for infile.
|
||||
* @param pRepair (unused)
|
||||
* @return new PwManager container.
|
||||
*
|
||||
* @throws IOException on any file error.
|
||||
* @throws InvalidKeyException on a decryption error, or possible internal bug.
|
||||
* @throws IllegalBlockSizeException on a decryption error, or possible internal bug.
|
||||
* @throws BadPaddingException on a decryption error, or possible internal bug.
|
||||
* @throws NoSuchAlgorithmException on a decryption error, or possible internal bug.
|
||||
* @throws NoSuchPaddingException on a decryption error, or possible internal bug.
|
||||
* @throws InvalidAlgorithmParameterException if error decrypting main file body.
|
||||
* @throws ShortBufferException if error decrypting main file body.
|
||||
*/
|
||||
public PwManager openDatabase( InputStream inStream, String password )
|
||||
throws IOException, InvalidCipherTextException
|
||||
{
|
||||
PwManager newManager;
|
||||
SHA256Digest md;
|
||||
/** Master key encrypted several times */
|
||||
byte[] transformedMasterKey;
|
||||
byte[] finalKey;
|
||||
|
||||
|
||||
// Load entire file, most of it's encrypted.
|
||||
// InputStream in = new FileInputStream( infile );
|
||||
byte[] filebuf = new byte[(int)inStream.available()];
|
||||
inStream.read( filebuf, 0, (int)inStream.available());
|
||||
inStream.close();
|
||||
|
||||
// Parse header (unencrypted)
|
||||
if( filebuf.length < PwDbHeader.BUF_SIZE )
|
||||
throw new IOException( "File too short for header" );
|
||||
PwDbHeader hdr = new PwDbHeader( filebuf, 0 );
|
||||
|
||||
if( (hdr.signature1 != PwManager.PWM_DBSIG_1) || (hdr.signature2 != PwManager.PWM_DBSIG_2) ) {
|
||||
//KeePassMIDlet.logS ( "Bad database file signature" );
|
||||
throw new IOException( "Bad database file signature" );
|
||||
}
|
||||
|
||||
if( hdr.version != PwManager.PWM_DBVER_DW ) {
|
||||
//KeePassMIDlet.logS ( "Bad database file version");
|
||||
//throw new IOException( "Bad database file version" );
|
||||
}
|
||||
|
||||
newManager = new PwManager();
|
||||
newManager.setMasterKey( password );
|
||||
|
||||
// Select algorithm
|
||||
if( (hdr.flags & PwManager.PWM_FLAG_RIJNDAEL) != 0 ) {
|
||||
//KeePassMIDlet.logS ( "Algorithm AES");
|
||||
newManager.algorithm = PwManager.ALGO_AES;
|
||||
} else if( (hdr.flags & PwManager.PWM_FLAG_TWOFISH) != 0 ) {
|
||||
//KeePassMIDlet.logS ( "Algorithm TWOFISH");
|
||||
newManager.algorithm = PwManager.ALGO_TWOFISH;
|
||||
} else {
|
||||
throw new IOException( "Unknown algorithm." );
|
||||
}
|
||||
|
||||
if( newManager.algorithm == PwManager.ALGO_TWOFISH )
|
||||
throw new IOException( "TwoFish algorithm is not supported" );
|
||||
|
||||
|
||||
newManager.numKeyEncRounds = hdr.numKeyEncRounds;
|
||||
|
||||
// testRijndael_JCE();
|
||||
|
||||
newManager.name = "KeePass Password Manager";
|
||||
|
||||
// Generate transformedMasterKey from masterKey
|
||||
//KeePassMIDlet.logS ("masterSeed2: " + new String(Hex.encode(hdr.masterSeed2)));
|
||||
|
||||
transformedMasterKey = transformMasterKey( hdr.masterSeed2,
|
||||
newManager.masterKey,
|
||||
newManager.numKeyEncRounds );
|
||||
// Hash the master password with the salt in the file
|
||||
md = new SHA256Digest();
|
||||
md.update( hdr.masterSeed, 0, hdr.masterSeed.length );
|
||||
md.update( transformedMasterKey, 0, transformedMasterKey.length );
|
||||
finalKey = new byte[md.getDigestSize()];
|
||||
md.doFinal ( finalKey, 0);
|
||||
|
||||
// NI
|
||||
//KeePassMIDlet.logS ("finalKey: " + new String(Hex.encode(finalKey)));
|
||||
|
||||
// Initialize Rijndael algorithm
|
||||
|
||||
// Cipher cipher = Cipher.getInstance( "AES/CBC/PKCS5Padding" );
|
||||
//PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine()));
|
||||
BufferedBlockCipher cipher = new BufferedBlockCipher(new CBCBlockCipher(new AESEngine()));
|
||||
|
||||
//cipher.init( Cipher.DECRYPT_MODE, new SecretKeySpec( finalKey, "AES" ), new IvParameterSpec( hdr.encryptionIV ) );
|
||||
|
||||
cipher.init(false, new ParametersWithIV(new KeyParameter(finalKey), hdr.encryptionIV));
|
||||
// Decrypt! The first bytes aren't encrypted (that's the header)
|
||||
//int encryptedPartSize = cipher.doFinal( filebuf, PwDbHeader.BUF_SIZE, filebuf.length - PwDbHeader.BUF_SIZE, filebuf, PwDbHeader.BUF_SIZE );
|
||||
//int encryptedPartSize
|
||||
int paddedEncryptedPartSize = cipher.processBytes(filebuf, PwDbHeader.BUF_SIZE, filebuf.length - PwDbHeader.BUF_SIZE, filebuf, PwDbHeader.BUF_SIZE );
|
||||
|
||||
int encryptedPartSize = 0;
|
||||
//try {
|
||||
PKCS7Padding padding = new PKCS7Padding();
|
||||
encryptedPartSize = paddedEncryptedPartSize - padding.padCount(filebuf);
|
||||
//} catch (Exception e) {
|
||||
//}
|
||||
// NI
|
||||
byte[] plainContent = new byte[encryptedPartSize];
|
||||
System.arraycopy(filebuf, PwDbHeader.BUF_SIZE, plainContent, 0, encryptedPartSize);
|
||||
|
||||
//if( pRepair == null ) {
|
||||
md = new SHA256Digest();
|
||||
md.update( filebuf, PwDbHeader.BUF_SIZE, encryptedPartSize );
|
||||
md.doFinal (finalKey, 0);
|
||||
|
||||
if( PhoneIDUtil.compare( finalKey, hdr.contentsHash ) == false) {
|
||||
//KeePassMIDlet.logS ( "Database file did not decrypt correctly. (checksum code is broken)" );
|
||||
System.out.println ("Database file did not decrypt correctly. (checksum code is broken)");
|
||||
// }
|
||||
}
|
||||
|
||||
// Import all groups
|
||||
|
||||
int pos = PwDbHeader.BUF_SIZE;
|
||||
PwGroup newGrp = new PwGroup();
|
||||
for( int i = 0; i < hdr.numGroups; ) {
|
||||
int fieldType = Types.readShort( filebuf, pos );
|
||||
pos += 2;
|
||||
int fieldSize = Types.readInt( filebuf, pos );
|
||||
pos += 4;
|
||||
|
||||
if( fieldType == 0xFFFF ) {
|
||||
//KeePassMIDlet.logS ( newGrp.level + " " + newGrp.name );
|
||||
|
||||
// End-Group record. Save group and count it.
|
||||
//newManager.groups.add( newGrp );
|
||||
newManager.addGroup( newGrp );
|
||||
newGrp = new PwGroup();
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
readGroupField( newGrp, fieldType, filebuf, pos );
|
||||
}
|
||||
pos += fieldSize;
|
||||
}
|
||||
// fixGroups( groups );
|
||||
|
||||
// Import all entries
|
||||
PwEntry newEnt = new PwEntry();
|
||||
for( int i = 0; i < hdr.numEntries; ) {
|
||||
int fieldType = Types.readShort( filebuf, pos );
|
||||
int fieldSize = Types.readInt( filebuf, pos + 2 );
|
||||
|
||||
if( fieldType == 0xFFFF ) {
|
||||
// End-Group record. Save group and count it.
|
||||
newManager.addEntry( newEnt );
|
||||
//KeePassMIDlet.logS( newEnt.title );
|
||||
newEnt = new PwEntry();
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
readEntryField( newEnt, filebuf, pos );
|
||||
}
|
||||
pos += 2 + 4 + fieldSize;
|
||||
}
|
||||
|
||||
// Keep the Meta-Info entry separate
|
||||
for( int i=0; i<newManager.entries.size(); i++) {
|
||||
PwEntry ent = (PwEntry)newManager.entries.elementAt(i);
|
||||
if( ent.title.equals( "Meta-Info" )
|
||||
&& ent.url.equals( "$" )
|
||||
&& ent.username.equals( "SYSTEM" ) ) {
|
||||
newManager.metaInfo = ent;
|
||||
newManager.entries.removeElementAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
return newManager;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* KeePass's custom pad style.
|
||||
*
|
||||
* @param data buffer to pad.
|
||||
* @return addtional bytes to append to data[] to make
|
||||
* a properly padded array.
|
||||
*/
|
||||
public static byte[] makePad( byte[] data ) {
|
||||
//custom pad method
|
||||
//TODO //WRZ doesn't work (yet)
|
||||
|
||||
// append 0x80 plus zeros to a multiple of 4 bytes
|
||||
int thisblk = 32 - data.length % 32; // bytes needed to finish blk
|
||||
int nextblk = 0; // 32 if we need another block
|
||||
// need 9 bytes; add new block if no room
|
||||
if( thisblk < 9 ) {
|
||||
nextblk = 32;
|
||||
}
|
||||
|
||||
// all bytes are zeroed for free
|
||||
byte[] pad = new byte[ thisblk + nextblk ];
|
||||
pad[0] = (byte)0x80;
|
||||
|
||||
// write length*8 to end of final block
|
||||
int ix = thisblk + nextblk - 8;
|
||||
Types.writeInt( data.length>>29, pad, ix );
|
||||
bsw32( pad, ix );
|
||||
ix += 4;
|
||||
Types.writeInt( data.length<<3, pad, ix );
|
||||
bsw32( pad, ix );
|
||||
|
||||
return pad;
|
||||
}
|
||||
|
||||
public static void bsw32( byte[] ary, int offset ) {
|
||||
byte t = ary[offset];
|
||||
ary[offset] = ary[offset+3];
|
||||
ary[offset+3] = t;
|
||||
t = ary[offset+1];
|
||||
ary[offset+1] = ary[offset+2];
|
||||
ary[offset+2] = t;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encrypt the master key a few times to make brute-force key-search harder
|
||||
* @throws NoSuchPaddingException
|
||||
* @throws NoSuchAlgorithmException
|
||||
* @throws ShortBufferException
|
||||
*/
|
||||
|
||||
static byte[] transformMasterKey( byte[] pKeySeed, byte[] pKey, int rounds )
|
||||
/*throws InvalidKeyException,
|
||||
IllegalBlockSizeException,
|
||||
BadPaddingException,
|
||||
NoSuchAlgorithmException,
|
||||
NoSuchPaddingException, ShortBufferException*/ {
|
||||
//KeePassMIDlet.logS("transformMasterKey, rounds=" + rounds);
|
||||
//KeePassMIDlet.logS("transformMasterKey, pkey=" + new String(Hex.encode(pKey)));
|
||||
|
||||
byte[] newKey = new byte[pKey.length];
|
||||
int i;
|
||||
|
||||
|
||||
BufferedBlockCipher cipher = new BufferedBlockCipher(new AESEngine());
|
||||
cipher.init(true, new KeyParameter(pKeySeed));
|
||||
|
||||
newKey = pKey;
|
||||
for( i = 0; i < rounds; i++ )
|
||||
cipher.processBytes (newKey, 0, newKey.length, newKey, 0);
|
||||
|
||||
// Hash once with SHA-256
|
||||
SHA256Digest md = new SHA256Digest();
|
||||
md.update(newKey, 0, newKey.length );
|
||||
//newKey = md.digest( newKey );
|
||||
md.doFinal(newKey, 0);
|
||||
|
||||
return newKey;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Parse and save one record from binary file.
|
||||
* @param buf
|
||||
* @param offset
|
||||
* @return If >0,
|
||||
*/
|
||||
void readGroupField( PwGroup grp, int fieldType, byte[] buf, int offset ) {
|
||||
switch( fieldType ) {
|
||||
case 0x0000 :
|
||||
// Ignore field
|
||||
break;
|
||||
case 0x0001 :
|
||||
grp.groupId = Types.readInt( buf, offset );
|
||||
break;
|
||||
case 0x0002 :
|
||||
grp.name = new String( buf, offset, Types.strlen( buf, offset ) );
|
||||
break;
|
||||
case 0x0003 :
|
||||
grp.tCreation = Types.readTime( buf, offset );
|
||||
break;
|
||||
case 0x0004 :
|
||||
grp.tLastMod = Types.readTime( buf, offset );
|
||||
break;
|
||||
case 0x0005 :
|
||||
grp.tLastAccess = Types.readTime( buf, offset );
|
||||
break;
|
||||
case 0x0006 :
|
||||
grp.tExpire = Types.readTime( buf, offset );
|
||||
break;
|
||||
case 0x0007 :
|
||||
grp.imageId = Types.readInt( buf, offset );
|
||||
break;
|
||||
case 0x0008 :
|
||||
grp.level = Types.readShort( buf, offset );
|
||||
break;
|
||||
case 0x0009 :
|
||||
grp.flags = Types.readInt( buf, offset );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void readEntryField( PwEntry ent, byte[] buf, int offset )
|
||||
throws UnsupportedEncodingException
|
||||
{
|
||||
int fieldType = Types.readShort( buf, offset );
|
||||
offset += 2;
|
||||
int fieldSize = Types.readInt( buf, offset );
|
||||
offset += 4;
|
||||
|
||||
switch( fieldType ) {
|
||||
case 0x0000 :
|
||||
// Ignore field
|
||||
break;
|
||||
case 0x0001 :
|
||||
System.arraycopy( buf, offset, ent.uuid, 0, 16 );
|
||||
break;
|
||||
case 0x0002 :
|
||||
ent.groupId = Types.readInt( buf, offset );
|
||||
break;
|
||||
case 0x0003 :
|
||||
ent.imageId = Types.readInt( buf, offset );
|
||||
break;
|
||||
case 0x0004 :
|
||||
ent.title = new String( buf, offset, Types.strlen( buf, offset ), "UTF-8" );
|
||||
break;
|
||||
case 0x0005 :
|
||||
ent.url = new String( buf, offset, Types.strlen( buf, offset ), "UTF-8" );
|
||||
break;
|
||||
case 0x0006 :
|
||||
ent.username = new String( buf, offset, Types.strlen( buf, offset ), "UTF-8" );
|
||||
break;
|
||||
case 0x0007 :
|
||||
ent.setPassword( buf, offset, Types.strlen( buf, offset ) );
|
||||
break;
|
||||
case 0x0008 :
|
||||
ent.additional = new String( buf, offset, Types.strlen( buf, offset ), "UTF-8" );
|
||||
break;
|
||||
case 0x0009 :
|
||||
ent.tCreation = Types.readTime( buf, offset );
|
||||
break;
|
||||
case 0x000A :
|
||||
ent.tLastMod = Types.readTime( buf, offset );
|
||||
break;
|
||||
case 0x000B :
|
||||
ent.tLastAccess = Types.readTime( buf, offset );
|
||||
break;
|
||||
case 0x000C :
|
||||
ent.tExpire = Types.readTime( buf, offset );
|
||||
break;
|
||||
case 0x000D :
|
||||
ent.binaryDesc = new String( buf, offset, Types.strlen( buf, offset ), "UTF-8" );
|
||||
break;
|
||||
case 0x000E :
|
||||
ent.setBinaryData( buf, offset, fieldSize );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Attach groups to parent groups.
|
||||
*
|
||||
* @param groups
|
||||
* @return root group.
|
||||
*//*
|
||||
private PwGroup fixGroups( List groups ) {
|
||||
int curLevel = -1;
|
||||
Stack parents = new Stack();
|
||||
PwGroup root;
|
||||
|
||||
root = new PwGroup();
|
||||
root.level = curLevel;
|
||||
parents.push( root );
|
||||
|
||||
for( Iterator iter = groups.iterator(); iter.hasNext(); ) {
|
||||
PwGroup group = (PwGroup)iter.next();
|
||||
|
||||
while( group.level <= curLevel ){
|
||||
parents.pop();
|
||||
curLevel = ((PwGroup)parents.peek()).level;
|
||||
}
|
||||
|
||||
if( group.level >= curLevel ) {
|
||||
if( !parents.isEmpty() )
|
||||
((PwGroup)parents.peek()).children.add( group );
|
||||
parents.push( group );
|
||||
curLevel = group.level;
|
||||
}
|
||||
}
|
||||
|
||||
return root;
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test the BouncyCastle lib.
|
||||
*/
|
||||
/* -- we're not using BouncyCastle
|
||||
static void testRijndael_Bouncy() {
|
||||
byte[] aKey = new byte[32];
|
||||
byte[] aTest = new byte[16];
|
||||
byte[] aRef = new byte[16];
|
||||
// The Rijndael class will be tested, that's the expected ciphertext
|
||||
int[] aRef_int = {
|
||||
0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89
|
||||
};
|
||||
int i;
|
||||
|
||||
// Do a quick test if the Rijndael class worked correctly
|
||||
for( i = 0; i < 32; i++ ) {
|
||||
aKey[i] = (byte)i;
|
||||
}
|
||||
for( i = 0; i < 16; i++ ) {
|
||||
aTest[i] = (byte)((i << 4) | i);
|
||||
aRef[i] = (byte)aRef_int[i];
|
||||
}
|
||||
|
||||
RijndaelEngine rijndael = new RijndaelEngine( 128 );
|
||||
rijndael.init( true, new KeyParameter( aKey ) );
|
||||
rijndael.processBlock( aTest, 0, aTest, 0 );
|
||||
|
||||
if( !Arrays.equals( aTest, aRef ) )
|
||||
throw new RuntimeException( "RijndaelEngine failed test" );
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Test Sun's JCE.
|
||||
* Note you need the "unlimited security" policy files from Sun.
|
||||
* They're where you download the JDK, i.e.
|
||||
* <a href="http://java.sun.com/j2se/1.5.0/download.jsp"
|
||||
* >http://java.sun.com/j2se/1.5.0/download.jsp</a>
|
||||
* @throws NoSuchPaddingException
|
||||
* @throws NoSuchAlgorithmException
|
||||
*/
|
||||
static void testRijndael_JCE() {
|
||||
byte[] aKey = new byte[32];
|
||||
byte[] aTest = new byte[16];
|
||||
byte[] aRef = new byte[16];
|
||||
// The Rijndael class will be tested, that's the expected ciphertext
|
||||
int[] aRef_int = {
|
||||
0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89
|
||||
};
|
||||
int i;
|
||||
|
||||
// Do a quick test if the Rijndael class worked correctly
|
||||
for( i = 0; i < 32; i++ ) {
|
||||
aKey[i] = (byte)i;
|
||||
}
|
||||
for( i = 0; i < 16; i++ ) {
|
||||
aTest[i] = (byte)((i << 4) | i);
|
||||
aRef[i] = (byte)aRef_int[i];
|
||||
}
|
||||
|
||||
try {
|
||||
// Cipher cipher = Cipher.getInstance( "AES/ECB/NoPadding" );
|
||||
BufferedBlockCipher cipher = new BufferedBlockCipher(new AESEngine());
|
||||
//cipher.init( Cipher.ENCRYPT_MODE, new SecretKeySpec( aKey, "AES" ) );
|
||||
cipher.init(true, new KeyParameter(aKey));
|
||||
//aTest = cipher.doFinal( aTest );
|
||||
cipher.processBytes(aTest, 0, aTest.length, aTest, 0);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
throw new RuntimeException( "JCE failed test" );
|
||||
}
|
||||
|
||||
if( PhoneIDUtil.compare (aTest, aRef) == false)
|
||||
throw new RuntimeException( "JCE failed test" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
NIST.gov states the following:
|
||||
|
||||
Suppose that the length of the message, M, is l bits. Append the bit 1 to the end of the
|
||||
message, followed by k zero bits, where k is the smallest, non-negative solution to the equation
|
||||
l +1+ k º 448mod 512 . Then append the 64-bit block that is equal to the number l expressed
|
||||
using a binary representation. For example, the (8-bit ASCII) message abc has length
|
||||
8´3 = 24, so the message is padded with a one bit, then 448 - (24 +1) = 423 zero bits, and then
|
||||
the message length, to become the 512-bit padded message
|
||||
|
||||
423 64
|
||||
01100001 01100010 01100011 1 00
00 00
011000
|
||||
a b c l = 24
|
||||
|
||||
The length of the padded message should now be a multiple of 512 bits.
|
||||
*/
|
84
src/org/phoneid/keepassj2me/PwDbHeader.java
Normal file
84
src/org/phoneid/keepassj2me/PwDbHeader.java
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
KeePass for J2ME
|
||||
|
||||
Copyright 2007 Naomaru Itoi <nao@phoneid.org>
|
||||
|
||||
This file was derived from
|
||||
|
||||
Java clone of KeePass - A KeePass file viewer for Java
|
||||
Copyright 2006 Bill Zwicky <billzwicky@users.sourceforge.net>
|
||||
|
||||
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; version 2
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package org.phoneid.keepassj2me;
|
||||
|
||||
public class PwDbHeader {
|
||||
/**
|
||||
* Parse given buf, as read from file.
|
||||
* @param buf
|
||||
*/
|
||||
public PwDbHeader( byte buf[], int offset ) {
|
||||
signature1 = Types.readInt( buf, offset + 0 );
|
||||
signature2 = Types.readInt( buf, offset + 4 );
|
||||
flags = Types.readInt( buf, offset + 8 );
|
||||
version = Types.readInt( buf, offset + 12 );
|
||||
|
||||
System.arraycopy( buf, offset + 16, masterSeed, 0, 16 );
|
||||
System.arraycopy( buf, offset + 32, encryptionIV, 0, 16 );
|
||||
|
||||
numGroups = Types.readInt( buf, offset + 48 );
|
||||
numEntries = Types.readInt( buf, offset + 52 );
|
||||
|
||||
System.arraycopy( buf, offset + 56, contentsHash, 0, 32 );
|
||||
|
||||
System.arraycopy( buf, offset + 88, masterSeed2, 0, 32 );
|
||||
numKeyEncRounds = Types.readInt( buf, offset + 120 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void toBuf( byte[] buf, int offset ) {
|
||||
throw new RuntimeException("Method 'toBuf' not implemented yet");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Size of byte buffer needed to hold this struct. */
|
||||
public static final int BUF_SIZE = 124;
|
||||
|
||||
|
||||
|
||||
public int signature1; // = PWM_DBSIG_1
|
||||
public int signature2; // = PWM_DBSIG_2
|
||||
public int flags;
|
||||
public int version;
|
||||
|
||||
/** Seed that gets hashed with the userkey to form the final key */
|
||||
public byte masterSeed[] = new byte[16];
|
||||
/** IV used for content encryption */
|
||||
public byte encryptionIV[] = new byte[16];
|
||||
|
||||
/** Number of groups in the database */
|
||||
public int numGroups;
|
||||
/** Number of entries in the database */
|
||||
public int numEntries;
|
||||
|
||||
/** SHA-256 hash of the database, used for integrity check */
|
||||
public byte contentsHash[] = new byte[32];
|
||||
|
||||
/** Used for the dwKeyEncRounds AES transformations */
|
||||
public byte masterSeed2[] = new byte[32];
|
||||
public int numKeyEncRounds;
|
||||
}
|
129
src/org/phoneid/keepassj2me/PwEntry.java
Normal file
129
src/org/phoneid/keepassj2me/PwEntry.java
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
KeePass for J2ME
|
||||
|
||||
Copyright 2007 Naomaru Itoi <nao@phoneid.org>
|
||||
|
||||
This file was derived from
|
||||
|
||||
Java clone of KeePass - A KeePass file viewer for Java
|
||||
Copyright 2006 Bill Zwicky <billzwicky@users.sourceforge.net>
|
||||
|
||||
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; version 2
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package org.phoneid.keepassj2me;
|
||||
|
||||
// PhoneID
|
||||
import org.phoneid.*;
|
||||
|
||||
// Java
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
* Structure containing information about one entry.
|
||||
*
|
||||
* <PRE>
|
||||
* One entry: [FIELDTYPE(FT)][FIELDSIZE(FS)][FIELDDATA(FD)]
|
||||
* [FT+FS+(FD)][FT+FS+(FD)][FT+FS+(FD)][FT+FS+(FD)][FT+FS+(FD)]...
|
||||
*
|
||||
* [ 2 bytes] FIELDTYPE
|
||||
* [ 4 bytes] FIELDSIZE, size of FIELDDATA in bytes
|
||||
* [ n bytes] FIELDDATA, n = FIELDSIZE
|
||||
*
|
||||
* Notes:
|
||||
* - Strings are stored in UTF-8 encoded form and are null-terminated.
|
||||
* - FIELDTYPE can be one of the FT_ constants.
|
||||
* </PRE>
|
||||
*
|
||||
* @author Naomaru Itoi <nao@phoneid.org>
|
||||
* @author Bill Zwicky <wrzwicky@pobox.com>
|
||||
* @author Dominik Reichl <dominik.reichl@t-online.de>
|
||||
*/
|
||||
public class PwEntry {
|
||||
|
||||
// for tree traversing
|
||||
public PwGroup parent = null;
|
||||
|
||||
public PwEntry() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return the actual password byte array.
|
||||
*/
|
||||
public byte[] getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Securely erase old password before copying new. */
|
||||
public void setPassword( byte[] buf, int offset, int len ) {
|
||||
if( password != null ) {
|
||||
PhoneIDUtil.fill( password, (byte)0 );
|
||||
password = null;
|
||||
}
|
||||
password = new byte[len];
|
||||
System.arraycopy( buf, offset, password, 0, len );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return the actual binaryData byte array.
|
||||
*/
|
||||
public byte[] getBinaryData() {
|
||||
return binaryData;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Securely erase old data before copying new. */
|
||||
public void setBinaryData( byte[] buf, int offset, int len ) {
|
||||
if( binaryData != null ) {
|
||||
PhoneIDUtil.fill( binaryData, (byte)0 );
|
||||
binaryData = null;
|
||||
}
|
||||
binaryData = new byte[len];
|
||||
System.arraycopy( buf, offset, binaryData, 0, len );
|
||||
}
|
||||
|
||||
|
||||
/** Size of byte buffer needed to hold this struct. */
|
||||
public static final int BUF_SIZE = 124;
|
||||
|
||||
|
||||
public byte uuid[] = new byte[16];
|
||||
public int groupId;
|
||||
public int imageId;
|
||||
|
||||
public String title;
|
||||
public String url;
|
||||
public String username;
|
||||
|
||||
private byte[] password;
|
||||
|
||||
public String additional;
|
||||
|
||||
public Date tCreation;
|
||||
public Date tLastMod;
|
||||
public Date tLastAccess;
|
||||
public Date tExpire;
|
||||
|
||||
/** A string describing what is in pBinaryData */
|
||||
public String binaryDesc;
|
||||
private byte[] binaryData;
|
||||
}
|
64
src/org/phoneid/keepassj2me/PwGroup.java
Normal file
64
src/org/phoneid/keepassj2me/PwGroup.java
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
KeePass for J2ME
|
||||
|
||||
Copyright 2007 Naomaru Itoi <nao@phoneid.org>
|
||||
|
||||
This file was derived from
|
||||
|
||||
Java clone of KeePass - A KeePass file viewer for Java
|
||||
Copyright 2006 Bill Zwicky <billzwicky@users.sourceforge.net>
|
||||
|
||||
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; version 2
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package org.phoneid.keepassj2me;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Naomaru Itoi <nao@phoneid.org>
|
||||
* @author Bill Zwicky <wrzwicky@pobox.com>
|
||||
* @author Dominik Reichl <dominik.reichl@t-online.de>
|
||||
*/
|
||||
public class PwGroup {
|
||||
public PwGroup() {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/** Size of byte buffer needed to hold this struct. */
|
||||
public static final int BUF_SIZE = 124;
|
||||
|
||||
// for tree traversing
|
||||
public Vector childGroups = null;
|
||||
public Vector childEntries = null;
|
||||
public PwGroup parent = null;
|
||||
|
||||
public int groupId;
|
||||
public int imageId;
|
||||
public String name;
|
||||
|
||||
public Date tCreation;
|
||||
public Date tLastMod;
|
||||
public Date tLastAccess;
|
||||
public Date tExpire;
|
||||
|
||||
public int level; //short
|
||||
|
||||
/** Used by KeePass internally, don't use */
|
||||
public int flags;
|
||||
}
|
192
src/org/phoneid/keepassj2me/PwManager.java
Normal file
192
src/org/phoneid/keepassj2me/PwManager.java
Normal file
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
|
||||
KeePass for J2ME
|
||||
|
||||
Copyright 2007 Naomaru Itoi <nao@phoneid.org>
|
||||
|
||||
This file was derived from
|
||||
|
||||
Java clone of KeePass - A KeePass file viewer for Java
|
||||
Copyright 2006 Bill Zwicky <billzwicky@users.sourceforge.net>
|
||||
|
||||
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
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package org.phoneid.keepassj2me;
|
||||
|
||||
// Java
|
||||
import java.util.Vector;
|
||||
|
||||
// Bouncy Castle
|
||||
import org.bouncycastle1.crypto.digests.*;
|
||||
|
||||
/**
|
||||
* @author Naomaru Itoi <nao@phoneid.org>
|
||||
* @author Bill Zwicky <wrzwicky@pobox.com>
|
||||
* @author Dominik Reichl <dominik.reichl@t-online.de>
|
||||
*/
|
||||
public class PwManager {
|
||||
|
||||
// Constants
|
||||
// private static final int PWM_SESSION_KEY_SIZE = 12;
|
||||
// DB sig from KeePass 1.03
|
||||
static final int PWM_DBSIG_1 = 0x9AA2D903;
|
||||
// DB sig from KeePass 1.03
|
||||
static final int PWM_DBSIG_2 = 0xB54BFB65;
|
||||
// DB sig from KeePass 1.03
|
||||
static final int PWM_DBVER_DW = 0x00030002;
|
||||
|
||||
static final int PWM_FLAG_SHA2 = 1;
|
||||
static final int PWM_FLAG_RIJNDAEL = 2;
|
||||
static final int PWM_FLAG_ARCFOUR = 4;
|
||||
static final int PWM_FLAG_TWOFISH = 8;
|
||||
|
||||
static final int ALGO_AES = 0;
|
||||
static final int ALGO_TWOFISH = 1;
|
||||
|
||||
// Descriptive name for database, used in GUI.
|
||||
public String name = "KeePass database";
|
||||
|
||||
// Special entry for settings
|
||||
public PwEntry metaInfo;
|
||||
|
||||
// all entries
|
||||
public Vector entries = new Vector();
|
||||
// all groups
|
||||
public Vector groups = new Vector();
|
||||
// Last modified entry, use GetLastEditedEntry() to get it
|
||||
// PwEntry lastEditedEntry = null;
|
||||
// Pseudo-random number generator
|
||||
//CNewRandom m_random;
|
||||
// Used for in-memory encryption of passwords
|
||||
// private byte sessionKey[] = new byte[PWM_SESSION_KEY_SIZE];
|
||||
// Master key used to encrypt the whole database
|
||||
byte masterKey[] = new byte[32];
|
||||
// Algorithm used to encrypt the database
|
||||
int algorithm;
|
||||
int numKeyEncRounds;
|
||||
|
||||
// root group
|
||||
PwGroup rootGroup;
|
||||
|
||||
public void setMasterKey( String key ) {
|
||||
if( key == null || key.length() == 0 )
|
||||
throw new IllegalArgumentException( "Key cannot be empty." );
|
||||
|
||||
SHA256Digest md = new SHA256Digest();
|
||||
md.update( key.getBytes(), 0, key.getBytes().length );
|
||||
masterKey = new byte[md.getDigestSize()];
|
||||
md.doFinal(masterKey, 0);
|
||||
}
|
||||
/*
|
||||
//
|
||||
// Erase all members and buffers, then null pointers.
|
||||
// Ensures no memory (that we control) contains leftover keys.
|
||||
//
|
||||
void secureErase() {
|
||||
// TODO finish this!
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
public Vector getGrpRoots() {
|
||||
int target = 0;
|
||||
Vector kids = new Vector();
|
||||
for( int i=0; i < groups.size(); i++ ) {
|
||||
PwGroup grp = (PwGroup)groups.elementAt( i );
|
||||
if( grp.level == target )
|
||||
kids.addElement( grp );
|
||||
}
|
||||
return kids;
|
||||
}
|
||||
|
||||
public Vector getGrpChildren( PwGroup parent ) {
|
||||
int idx = groups.indexOf( parent );
|
||||
int target = parent.level + 1;
|
||||
Vector kids = new Vector();
|
||||
while( ++idx < groups.size() ) {
|
||||
PwGroup grp = (PwGroup)groups.elementAt( idx );
|
||||
if( grp.level < target )
|
||||
break;
|
||||
else
|
||||
if( grp.level == target )
|
||||
kids.addElement( grp );
|
||||
}
|
||||
return kids;
|
||||
}
|
||||
|
||||
public Vector getEntries( PwGroup parent ) {
|
||||
Vector kids = new Vector();
|
||||
/*for( Iterator i = entries.iterator(); i.hasNext(); ) {
|
||||
PwEntry ent = (PwEntry)i.next();
|
||||
if( ent.groupId == parent.groupId )
|
||||
kids.add( ent );
|
||||
}*/
|
||||
for (int i=0; i<entries.size(); i++) {
|
||||
PwEntry ent = (PwEntry)entries.elementAt(i);
|
||||
if( ent.groupId == parent.groupId )
|
||||
kids.addElement( ent );
|
||||
}
|
||||
return kids;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void addGroup(Object group)
|
||||
{
|
||||
groups.addElement(group);
|
||||
}
|
||||
|
||||
public void addEntry(Object entry)
|
||||
{
|
||||
entries.addElement(entry);
|
||||
}
|
||||
|
||||
public void constructTree(PwGroup currentGroup)
|
||||
{
|
||||
// I'm in root
|
||||
if (currentGroup == null) {
|
||||
rootGroup = new PwGroup();
|
||||
|
||||
Vector rootChildGroups = getGrpRoots();
|
||||
rootGroup.childGroups = rootChildGroups;
|
||||
rootGroup.childEntries = new Vector();
|
||||
for (int i=0; i<rootChildGroups.size(); i++) {
|
||||
((PwGroup)rootChildGroups.elementAt(i)).parent = rootGroup;
|
||||
constructTree((PwGroup)rootChildGroups.elementAt(i));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// I'm in non-root
|
||||
// get child groups
|
||||
currentGroup.childGroups = getGrpChildren(currentGroup);
|
||||
currentGroup.childEntries = getEntries(currentGroup);
|
||||
|
||||
// set parent in child entries
|
||||
for (int i=0; i<currentGroup.childEntries.size(); i++) {
|
||||
((PwEntry)currentGroup.childEntries.elementAt(i)).parent = currentGroup;
|
||||
}
|
||||
// recursively construct child groups
|
||||
for (int i=0; i<currentGroup.childGroups.size(); i++) {
|
||||
((PwGroup)currentGroup.childGroups.elementAt(i)).parent = currentGroup;
|
||||
constructTree((PwGroup)currentGroup.childGroups.elementAt(i));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
144
src/org/phoneid/keepassj2me/Types.java
Normal file
144
src/org/phoneid/keepassj2me/Types.java
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
KeePass for J2ME
|
||||
|
||||
Copyright 2007 Naomaru Itoi <nao@phoneid.org>
|
||||
|
||||
This file was derived from
|
||||
|
||||
Java clone of KeePass - A KeePass file viewer for Java
|
||||
Copyright 2006 Bill Zwicky <billzwicky@users.sourceforge.net>
|
||||
|
||||
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; version 2
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package org.phoneid.keepassj2me;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Tools for slicing and dicing Java and KeePass data types.
|
||||
*
|
||||
* @author Bill Zwicky <wrzwicky@pobox.com>
|
||||
*/
|
||||
public class Types {
|
||||
/**
|
||||
* Read a 32-bit value.
|
||||
*
|
||||
* @param buf
|
||||
* @param offset
|
||||
* @return
|
||||
*/
|
||||
public static int readInt( byte buf[], int offset ) {
|
||||
return (buf[offset + 0] & 0xFF) + ((buf[offset + 1] & 0xFF) << 8) + ((buf[offset + 2] & 0xFF) << 16)
|
||||
+ ((buf[offset + 3] & 0xFF) << 24);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Write a 32-bit value.
|
||||
*
|
||||
* @param val
|
||||
* @param buf
|
||||
* @param offset
|
||||
*/
|
||||
public static void writeInt( int val, byte[] buf, int offset ) {
|
||||
buf[offset + 0] = (byte)(val & 0xFF);
|
||||
buf[offset + 1] = (byte)((val >>> 8) & 0xFF);
|
||||
buf[offset + 2] = (byte)((val >>> 16) & 0xFF);
|
||||
buf[offset + 3] = (byte)((val >>> 24) & 0xFF);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Read an unsigned 16-bit value.
|
||||
*
|
||||
* @param buf
|
||||
* @param offset
|
||||
* @return
|
||||
*/
|
||||
public static int readShort( byte[] buf, int offset ) {
|
||||
return (buf[offset + 0] & 0xFF) + ((buf[offset + 1] & 0xFF) << 8);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Read an unsigned byte */
|
||||
public static int readUByte( byte[] buf, int offset ) {
|
||||
return ((int)buf[offset] & 0xFF);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return len of null-terminated string (i.e. distance to null)
|
||||
* within a byte buffer.
|
||||
*
|
||||
* @param buf
|
||||
* @param offset
|
||||
* @return
|
||||
*/
|
||||
public static int strlen( byte[] buf, int offset ) {
|
||||
int len = 0;
|
||||
while( buf[offset + len] != 0 )
|
||||
len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Copy a sequence of bytes into a new array.
|
||||
*
|
||||
* @param b - source array
|
||||
* @param offset - first byte
|
||||
* @param len - number of bytes
|
||||
* @return new byte[len]
|
||||
*/
|
||||
public static byte[] extract( byte[] b, int offset, int len ) {
|
||||
byte[] b2 = new byte[len];
|
||||
System.arraycopy( b, offset, b2, 0, len );
|
||||
return b2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Unpack date from 5 byte format.
|
||||
* The five bytes at 'offset' are unpacked to a java.util.Date instance.
|
||||
*/
|
||||
public static Date readTime( byte[] buf, int offset ) {
|
||||
int dw1 = readUByte( buf, offset );
|
||||
int dw2 = readUByte( buf, offset + 1 );
|
||||
int dw3 = readUByte( buf, offset + 2 );
|
||||
int dw4 = readUByte( buf, offset + 3 );
|
||||
int dw5 = readUByte( buf, offset + 4 );
|
||||
|
||||
// Unpack 5 byte structure to date and time
|
||||
int year = (dw1 << 6) | (dw2 >> 2);
|
||||
int month = ((dw2 & 0x00000003) << 2) | (dw3 >> 6);
|
||||
int day = (dw3 >> 1) & 0x0000001F;
|
||||
int hour = ((dw3 & 0x00000001) << 4) | (dw4 >> 4);
|
||||
int minute = ((dw4 & 0x0000000F) << 2) | (dw5 >> 6);
|
||||
int second = dw5 & 0x0000003F;
|
||||
|
||||
//Calendar time = Calendar.getInstance();
|
||||
//time.set( year, month, day, hour, minute, second );
|
||||
|
||||
//return time.getTime();
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue